From 3ac8570f4a0a98ae80e8f04c812c2d752b2b7486 Mon Sep 17 00:00:00 2001 From: nymea Date: Wed, 19 Sep 2018 15:21:12 +0200 Subject: [PATCH] mplement platform helper on ios --- libnymea-app-core/connection/awsclient.cpp | 19 +++--- libnymea-app-core/connection/awsclient.h | 10 +-- nymea-app/main.cpp | 4 ++ nymea-app/nymea-app.pro | 9 ++- .../ios/platformhelperios.cpp | 41 ++++++++++++ .../ios/platformhelperios.h | 27 ++++++++ packaging/ios/platformhelperios.mm | 67 +++++++++++++++++++ 7 files changed, 162 insertions(+), 15 deletions(-) create mode 100644 nymea-app/platformintegration/ios/platformhelperios.cpp create mode 100644 nymea-app/platformintegration/ios/platformhelperios.h create mode 100644 packaging/ios/platformhelperios.mm diff --git a/libnymea-app-core/connection/awsclient.cpp b/libnymea-app-core/connection/awsclient.cpp index babf3e19..18f443cb 100644 --- a/libnymea-app-core/connection/awsclient.cpp +++ b/libnymea-app-core/connection/awsclient.cpp @@ -614,7 +614,7 @@ void AWSClient::registerPushNotificationEndpoint(const QString ®istrationId, if (tokensExpired()) { qDebug() << "Cannot register push endpoint. Need to refresh our tokens"; refreshAccessToken(); - m_callQueue.append(QueuedCall("registerPushNotificationEndpoint", registrationId)); + m_callQueue.append(QueuedCall("registerPushNotificationEndpoint", registrationId, deviceDisplayName, mobileDeviceId)); return; } @@ -623,11 +623,6 @@ void AWSClient::registerPushNotificationEndpoint(const QString ®istrationId, request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); request.setRawHeader("x-api-idToken", m_idToken); -// qDebug() << "POST" << url.toString(); -// qDebug() << "HEADERS:"; -// foreach (const QByteArray &hdr, request.rawHeaderList()) { -// qDebug() << hdr << ":" << request.rawHeader(hdr); -// } QVariantMap payload; payload.insert("registrationId", registrationId); @@ -640,7 +635,13 @@ void AWSClient::registerPushNotificationEndpoint(const QString ®istrationId, payload.insert("mobileDeviceUuid", mobileDeviceId); QJsonDocument jsonDoc = QJsonDocument::fromVariant(payload); - qDebug() << "Registering push notification endpoint:" << payload.value("channel").toString(); + qDebug() << "Registering push notification endpoint:"; + qDebug() << "POST" << url.toString(); + qDebug() << "HEADERS:"; + foreach (const QByteArray &hdr, request.rawHeaderList()) { + qDebug() << hdr << ":" << request.rawHeader(hdr); + } + qDebug() << "Payload:" << qUtf8Printable(jsonDoc.toJson(QJsonDocument::Compact)); QNetworkReply *reply = m_nam->post(request, jsonDoc.toJson(QJsonDocument::Compact)); connect(reply, &QNetworkReply::finished, this, [reply]() { @@ -784,9 +785,11 @@ void AWSClient::getCredentialsForIdentity(const QString &identityId) if (qc.method == "fetchDevices") { fetchDevices(); } else if (qc.method == "postToMQTT") { - postToMQTT(qc.boxId, qc.timestamp, qc.callback); + postToMQTT(qc.arg1, qc.arg2, qc.callback); } else if (qc.method == "deleteAccount") { deleteAccount(); + } else if (qc.method == "registerPushNotificationEndpoint") { + registerPushNotificationEndpoint(qc.arg1, qc.arg2, qc.arg3); } } }); diff --git a/libnymea-app-core/connection/awsclient.h b/libnymea-app-core/connection/awsclient.h index 7b790b8a..86554664 100644 --- a/libnymea-app-core/connection/awsclient.h +++ b/libnymea-app-core/connection/awsclient.h @@ -175,11 +175,13 @@ private: class QueuedCall { public: QueuedCall(const QString &method): method(method) { } - QueuedCall(const QString &method, const QString &boxId): method(method), boxId(boxId) { } - QueuedCall(const QString &method, const QString &boxId, const QString ×tamp, std::function callback): method(method), boxId(boxId), timestamp(timestamp), callback(callback) {} + QueuedCall(const QString &method, const QString &arg1): method(method), arg1(arg1) { } + QueuedCall(const QString &method, const QString &arg1, const QString &arg2, const QString &arg3): method(method), arg1(arg1), arg2(arg2), arg3(arg3) { } + QueuedCall(const QString &method, const QString &arg1, const QString &arg2, std::function callback): method(method), arg1(arg1), arg2(arg2), callback(callback) {} QString method; - QString boxId; - QString timestamp; + QString arg1; + QString arg2; + QString arg3; std::function callback; }; diff --git a/nymea-app/main.cpp b/nymea-app/main.cpp index 0d4ca445..a088f3f0 100644 --- a/nymea-app/main.cpp +++ b/nymea-app/main.cpp @@ -28,6 +28,8 @@ #ifdef Q_OS_ANDROID #include #include "platformintegration/android/platformhelperandroid.h" +#elif defined(Q_OS_IOS) +#include "platformintegration/ios/platformhelperios.h" #else #include "platformintegration/generic/platformhelpergeneric.h" #endif @@ -44,6 +46,8 @@ QObject *platformHelperProvider(QQmlEngine *engine, QJSEngine *scriptEngine) Q_UNUSED(scriptEngine) #ifdef Q_OS_ANDROID return new PlatformHelperAndroid(); +#elif defined(Q_OS_IOS) + return new PlatformHelperIOS(); #else return new PlatformHelperGeneric(); #endif diff --git a/nymea-app/nymea-app.pro b/nymea-app/nymea-app.pro index ee0dca7f..cb65d8f7 100644 --- a/nymea-app/nymea-app.pro +++ b/nymea-app/nymea-app.pro @@ -20,13 +20,15 @@ HEADERS += \ stylecontroller.h \ pushnotifications.h \ platformhelper.h \ - platformintegration/generic/platformhelpergeneric.h + platformintegration/generic/platformhelpergeneric.h \ + platformintegration/ios/platformhelperios.h SOURCES += main.cpp \ stylecontroller.cpp \ pushnotifications.cpp \ platformhelper.cpp \ - platformintegration/generic/platformhelpergeneric.cpp + platformintegration/generic/platformhelpergeneric.cpp \ + platformintegration/ios/platformhelperios.cpp OTHER_FILES += $$files(*.qml, true) @@ -102,7 +104,8 @@ ios: { IOS_ENTITLEMENTS.value = $$files($$PWD/../packaging/ios/pushnotifications.entitlements) QMAKE_MAC_XCODE_SETTINGS += IOS_ENTITLEMENTS - OBJECTIVE_SOURCES += $$PWD/../packaging/ios/pushnotifications.mm + OBJECTIVE_SOURCES += $$PWD/../packaging/ios/pushnotifications.mm \ + $$PWD/../packaging/ios/platformhelperios.mm } BR=$$BRANDING diff --git a/nymea-app/platformintegration/ios/platformhelperios.cpp b/nymea-app/platformintegration/ios/platformhelperios.cpp new file mode 100644 index 00000000..ab1d5948 --- /dev/null +++ b/nymea-app/platformintegration/ios/platformhelperios.cpp @@ -0,0 +1,41 @@ +#include "platformhelperios.h" +#include +#include + +PlatformHelperIOS::PlatformHelperIOS(QObject *parent) : PlatformHelper(parent) +{ + +} + +void PlatformHelperIOS::requestPermissions() +{ + emit permissionsRequestFinished(); +} + +bool PlatformHelperIOS::hasPermissions() const +{ + return true; +} + +QString PlatformHelperIOS::deviceSerial() const +{ + QString deviceId = const_cast(this)->readKeyChainEntry("io.guh.nymea-app", "deviceId"); + qDebug() << "read keychain value:" << deviceId; + if (deviceId.isEmpty()) { + deviceId = QUuid::createUuid().toString(); + const_cast(this)->writeKeyChainEntry("io.guh.nymea-app", "deviceId", deviceId); + } + qDebug() << "Returning device ID" << deviceId; + return deviceId; +} + +QString PlatformHelperIOS::deviceModel() const +{ + qDebug() << "SYSINFO:" << QSysInfo::productType() << QSysInfo::prettyProductName() << QSysInfo::productVersion(); + return QSysInfo::prettyProductName(); +} + +QString PlatformHelperIOS::deviceManufacturer() const +{ + return QString("iPhone"); +} diff --git a/nymea-app/platformintegration/ios/platformhelperios.h b/nymea-app/platformintegration/ios/platformhelperios.h new file mode 100644 index 00000000..f80cca4f --- /dev/null +++ b/nymea-app/platformintegration/ios/platformhelperios.h @@ -0,0 +1,27 @@ +#ifndef PLATFORMHELPERIOS_H +#define PLATFORMHELPERIOS_H + +#include + +#include "platformhelper.h" + +class PlatformHelperIOS : public PlatformHelper +{ + Q_OBJECT +public: + explicit PlatformHelperIOS(QObject *parent = nullptr); + + Q_INVOKABLE virtual void requestPermissions() override; + + virtual bool hasPermissions() const override; + virtual QString deviceSerial() const override; + virtual QString deviceModel() const override; + virtual QString deviceManufacturer() const override; + +private: + // defined in platformhelperios.mm + QString readKeyChainEntry(const QString &service, const QString &key); + void writeKeyChainEntry(const QString &service, const QString &key, const QString &value); +}; + +#endif // PLATFORMHELPERIOS_H diff --git a/packaging/ios/platformhelperios.mm b/packaging/ios/platformhelperios.mm new file mode 100644 index 00000000..d7d58519 --- /dev/null +++ b/packaging/ios/platformhelperios.mm @@ -0,0 +1,67 @@ + +#import +#import + +#include +#include "platformintegration/ios/platformhelperios.h" + +QString PlatformHelperIOS::readKeyChainEntry(const QString &service, const QString &key) +{ + NSDictionary *const query = @{ + (__bridge id) kSecClass: (__bridge id) kSecClassGenericPassword, + (__bridge id) kSecAttrService: (__bridge NSString *) service.toCFString(), + (__bridge id) kSecAttrAccount: (__bridge NSString *) key.toCFString(), + (__bridge id) kSecReturnData: @YES, + }; + + CFTypeRef dataRef = nil; + const OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query, &dataRef); + + QByteArray data; + if (status == errSecSuccess) { + if (dataRef) + data = QByteArray::fromCFData((CFDataRef) dataRef); + + } else { + qWarning() << "Error accessing keychain value" << status; + } + + if (dataRef) + [dataRef release]; + + return data; +} + +void PlatformHelperIOS::writeKeyChainEntry(const QString &service, const QString &key, const QString &value) +{ + NSDictionary *const query = @{ + (__bridge id) kSecClass: (__bridge id) kSecClassGenericPassword, + (__bridge id) kSecAttrService: (__bridge NSString *) service.toCFString(), + (__bridge id) kSecAttrAccount: (__bridge NSString *) key.toCFString(), + }; + + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef) query, nil); + + if (status == errSecSuccess) { + NSDictionary *const update = @{ + (__bridge id) kSecValueData: (__bridge NSData *) value.toUtf8().toCFData(), + }; + + status = SecItemUpdate((__bridge CFDictionaryRef) query, (__bridge CFDictionaryRef) update); + } else { + NSDictionary *const insert = @{ + (__bridge id) kSecClass: (__bridge id) kSecClassGenericPassword, + (__bridge id) kSecAttrService: (__bridge NSString *) service.toCFString(), + (__bridge id) kSecAttrAccount: (__bridge NSString *) key.toCFString(), + (__bridge id) kSecValueData: (__bridge NSData *) value.toUtf8().toCFData(), + }; + + status = SecItemAdd((__bridge CFDictionaryRef) insert, nil); + } + + if (status == errSecSuccess) { + qDebug() << "Successfully stored value in keychain"; + } else { + qWarning() << "Error storing value in keycahin" << status; + } +}