From 75e480e425dff4318a3e432e63c3af5755b09e90 Mon Sep 17 00:00:00 2001 From: Poornima Nagarajan Date: Wed, 2 Oct 2024 17:11:19 -0700 Subject: [PATCH 1/5] use 6.9 native sdk and add push support --- plugin.xml | 2 +- src/android/ApptentiveBridge.kt | 21 ++ www/Apptentive.js | 344 ++++++++++++++++++++++---------- 3 files changed, 263 insertions(+), 104 deletions(-) diff --git a/plugin.xml b/plugin.xml index 40cb6cc..e346b71 100644 --- a/plugin.xml +++ b/plugin.xml @@ -54,7 +54,7 @@ - + diff --git a/src/android/ApptentiveBridge.kt b/src/android/ApptentiveBridge.kt index cc42d1d..c1f703c 100644 --- a/src/android/ApptentiveBridge.kt +++ b/src/android/ApptentiveBridge.kt @@ -242,6 +242,16 @@ class ApptentiveBridge : CordovaPlugin(), ApptentiveActivityInfo { } return true } + ACTION_SET_PUSH_NOTIFICATION_INTEGRATION -> { + if (isApptentiveRegistered) { + val provider = parsePushProvider("apptentive") + android.util.Log.d("Apptentive", "[CORDOVA] Provider is set to $provider") + val token = args.getString(0) + Apptentive.setPushNotificationIntegration(currentActivity.application, provider, token) + } else + android.util.Log.d("Apptentive", "[CORDOVA] Apptentive is not registered, push notification is not integerated") + return true + } else -> { android.util.Log.e("Apptentive", "[CORDOVA] Unhandled action in ApptentiveBridge: $action") callbackContext.error("Unhandled action in ApptentiveBridge: $action") @@ -328,6 +338,16 @@ class ApptentiveBridge : CordovaPlugin(), ApptentiveActivityInfo { } } + private fun parsePushProvider(pushProvider: String): Int { + when { + pushProvider.contains("apptentive") -> { return Apptentive.PUSH_PROVIDER_APPTENTIVE } + pushProvider.contains("amazon") -> { return Apptentive.PUSH_PROVIDER_AMAZON_AWS_SNS } + pushProvider.contains("parse") -> { return Apptentive.PUSH_PROVIDER_PARSE } + pushProvider.contains("urban_airship") -> { return Apptentive.PUSH_PROVIDER_URBAN_AIRSHIP } + else -> throw IllegalArgumentException("Unknown push provider: $pushProvider") + } + } + private companion object { val CORDOVA_TAG = LogTag("CORDOVA") @@ -360,6 +380,7 @@ class ApptentiveBridge : CordovaPlugin(), ApptentiveActivityInfo { const val ACTION_SHOW_MESSAGE_CENTER = "showMessageCenter" const val ACTION_CAN_SHOW_MESSAGE_CENTER = "canShowMessageCenter" const val ACTION_CAN_SHOW_INTERACTION = "canShowInteraction" + const val ACTION_SET_PUSH_NOTIFICATION_INTEGRATION = "setPushNotificationIntegration" } override fun getApptentiveActivityInfo(): Activity? { diff --git a/www/Apptentive.js b/www/Apptentive.js index 1b1a129..2d38e4b 100644 --- a/www/Apptentive.js +++ b/www/Apptentive.js @@ -1,107 +1,245 @@ var Apptentive = { - distributionVersion: "6.8.0", - - addCustomDeviceData: function (successCallback, errorCallback, key, value) { - cordova.exec(successCallback, errorCallback, "ApptentiveBridge", "addCustomDeviceData", [key, value]); - }, - - addCustomPersonData: function (successCallback, errorCallback, key, value) { - cordova.exec(successCallback, errorCallback, "ApptentiveBridge", "addCustomPersonData", [key, value]); - }, - - deviceReady: function (successCallback, errorCallback) { - console.log("Apptentive.deviceReady()"); - this.registerWithLogs(successCallback, errorCallback, "Info"); - }, - - registerWithLogs: function (successCallback, errorCallback, loglevel) { - console.log("Apptentive.registerWithLogs()"); - cordova.exec(successCallback, errorCallback, "ApptentiveBridge", "deviceReady", [this.distributionVersion, loglevel]); - }, - - engage: function (successCallback, errorCallback, eventName, customData) { - if (customData && typeof customData === 'object') { - cordova.exec(successCallback, errorCallback, "ApptentiveBridge", "engage", [eventName, customData]); - } else { - cordova.exec(successCallback, errorCallback, "ApptentiveBridge", "engage", [eventName]); - } - }, - - getUnreadMessageCount: function (successCallback, errorCallback) { - cordova.exec(successCallback, errorCallback, "ApptentiveBridge", "getUnreadMessageCount", []); - }, - - putRatingProviderArg: function (successCallback, errorCallback, key, value) { - cordova.exec(successCallback, errorCallback, "ApptentiveBridge", "putRatingProviderArg", [key, value]); - }, - - removeCustomDeviceData: function (successCallback, errorCallback, key) { - cordova.exec(successCallback, errorCallback, "ApptentiveBridge", "removeCustomDeviceData", [key]); - }, - - removeCustomPersonData: function (successCallback, errorCallback, key) { - cordova.exec(successCallback, errorCallback, "ApptentiveBridge", "removeCustomPersonData", [key]); - }, - - getPersonEmail: function (successCallback, errorCallback) { - cordova.exec(successCallback, errorCallback, "ApptentiveBridge", "getPersonEmail", []); - }, - - setPersonEmail: function (successCallback, errorCallback, email) { - cordova.exec(successCallback, errorCallback, "ApptentiveBridge", "setPersonEmail", [email]); - }, - - getPersonName: function (successCallback, errorCallback) { - cordova.exec(successCallback, errorCallback, "ApptentiveBridge", "getPersonName", []); - }, - - setPersonName: function (successCallback, errorCallback, name) { - cordova.exec(successCallback, errorCallback, "ApptentiveBridge", "setPersonName", [name]); - }, - - setRatingProvider: function (successCallback, errorCallback, ratingProviderName) { - successCallback(); // Deprecated. Use the ANDROID_CUSTOM_APP_STORE_URL variable instead. - }, - - addUnreadMessagesListener: function (unreadMessagesCallback, errorCallback) { - cordova.exec(unreadMessagesCallback, errorCallback, "ApptentiveBridge", "addUnreadMessagesListener", []); - }, - - addSurveyFinishedListener: function (surveyFinishedCallback, errorCallback) { - cordova.exec(surveyFinishedCallback, errorCallback, "ApptentiveBridge", "setOnSurveyFinishedListener", []); - }, - - showMessageCenter: function (successCallback, errorCallback, customData) { - if (customData) { - cordova.exec(successCallback, errorCallback, "ApptentiveBridge", "showMessageCenter", [customData]); - } else { - cordova.exec(successCallback, errorCallback, "ApptentiveBridge", "showMessageCenter", []); - } - }, - - canShowMessageCenter: function (successCallback, errorCallback) { - cordova.exec(successCallback, errorCallback, "ApptentiveBridge", "canShowMessageCenter", []); - }, - - canShowInteraction: function (successCallback, errorCallback, eventName) { - cordova.exec(successCallback, errorCallback, "ApptentiveBridge", "canShowInteraction", [eventName]); - }, - - setProperty: function (successCallback, errorCallback, key, value) { - successCallback(); // Does nothing on Android - }, - - login: function (successCallback, errorCallback, token) { - successCallback(); // Does nothing on Android. We are working on re-implementing this feature. - }, - - logout: function (successCallback, errorCallback) { - successCallback(); // Does nothing on Android. We are working on re-implementing this feature. - }, - - sendAttachmentText: function (successCallback, errorCallback, text) { - cordova.exec(successCallback, errorCallback, "ApptentiveBridge", "sendAttachmentText", [text]); - }, + distributionVersion: "6.8.0", + + addCustomDeviceData: function (successCallback, errorCallback, key, value) { + cordova.exec( + successCallback, + errorCallback, + "ApptentiveBridge", + "addCustomDeviceData", + [key, value] + ); + }, + + addCustomPersonData: function (successCallback, errorCallback, key, value) { + cordova.exec( + successCallback, + errorCallback, + "ApptentiveBridge", + "addCustomPersonData", + [key, value] + ); + }, + + deviceReady: function (successCallback, errorCallback) { + console.log("Apptentive.deviceReady()"); + this.registerWithLogs(successCallback, errorCallback, "Info"); + }, + + registerWithLogs: function (successCallback, errorCallback, loglevel) { + console.log("Apptentive.registerWithLogs()"); + cordova.exec( + successCallback, + errorCallback, + "ApptentiveBridge", + "deviceReady", + [this.distributionVersion, loglevel] + ); + }, + + engage: function (successCallback, errorCallback, eventName, customData) { + if (customData && typeof customData === "object") { + cordova.exec( + successCallback, + errorCallback, + "ApptentiveBridge", + "engage", + [eventName, customData] + ); + } else { + cordova.exec( + successCallback, + errorCallback, + "ApptentiveBridge", + "engage", + [eventName] + ); + } + }, + + getUnreadMessageCount: function (successCallback, errorCallback) { + cordova.exec( + successCallback, + errorCallback, + "ApptentiveBridge", + "getUnreadMessageCount", + [] + ); + }, + + putRatingProviderArg: function (successCallback, errorCallback, key, value) { + cordova.exec( + successCallback, + errorCallback, + "ApptentiveBridge", + "putRatingProviderArg", + [key, value] + ); + }, + + removeCustomDeviceData: function (successCallback, errorCallback, key) { + cordova.exec( + successCallback, + errorCallback, + "ApptentiveBridge", + "removeCustomDeviceData", + [key] + ); + }, + + removeCustomPersonData: function (successCallback, errorCallback, key) { + cordova.exec( + successCallback, + errorCallback, + "ApptentiveBridge", + "removeCustomPersonData", + [key] + ); + }, + + getPersonEmail: function (successCallback, errorCallback) { + cordova.exec( + successCallback, + errorCallback, + "ApptentiveBridge", + "getPersonEmail", + [] + ); + }, + + setPersonEmail: function (successCallback, errorCallback, email) { + cordova.exec( + successCallback, + errorCallback, + "ApptentiveBridge", + "setPersonEmail", + [email] + ); + }, + + getPersonName: function (successCallback, errorCallback) { + cordova.exec( + successCallback, + errorCallback, + "ApptentiveBridge", + "getPersonName", + [] + ); + }, + + setPersonName: function (successCallback, errorCallback, name) { + cordova.exec( + successCallback, + errorCallback, + "ApptentiveBridge", + "setPersonName", + [name] + ); + }, + + setRatingProvider: function ( + successCallback, + errorCallback, + ratingProviderName + ) { + successCallback(); // Deprecated. Use the ANDROID_CUSTOM_APP_STORE_URL variable instead. + }, + + addUnreadMessagesListener: function (unreadMessagesCallback, errorCallback) { + cordova.exec( + unreadMessagesCallback, + errorCallback, + "ApptentiveBridge", + "addUnreadMessagesListener", + [] + ); + }, + + addSurveyFinishedListener: function (surveyFinishedCallback, errorCallback) { + cordova.exec( + surveyFinishedCallback, + errorCallback, + "ApptentiveBridge", + "setOnSurveyFinishedListener", + [] + ); + }, + + showMessageCenter: function (successCallback, errorCallback, customData) { + if (customData) { + cordova.exec( + successCallback, + errorCallback, + "ApptentiveBridge", + "showMessageCenter", + [customData] + ); + } else { + cordova.exec( + successCallback, + errorCallback, + "ApptentiveBridge", + "showMessageCenter", + [] + ); + } + }, + + canShowMessageCenter: function (successCallback, errorCallback) { + cordova.exec( + successCallback, + errorCallback, + "ApptentiveBridge", + "canShowMessageCenter", + [] + ); + }, + + canShowInteraction: function (successCallback, errorCallback, eventName) { + cordova.exec( + successCallback, + errorCallback, + "ApptentiveBridge", + "canShowInteraction", + [eventName] + ); + }, + + setProperty: function (successCallback, errorCallback, key, value) { + successCallback(); // Does nothing on Android + }, + + login: function (successCallback, errorCallback, token) { + successCallback(); // Does nothing on Android. We are working on re-implementing this feature. + }, + + logout: function (successCallback, errorCallback) { + successCallback(); // Does nothing on Android. We are working on re-implementing this feature. + }, + + sendAttachmentText: function (successCallback, errorCallback, text) { + cordova.exec( + successCallback, + errorCallback, + "ApptentiveBridge", + "sendAttachmentText", + [text] + ); + }, + + setPushNotificationIntegration: function ( + successCallback, + errorCallback, + token + ) { + cordova.exec( + successCallback, + errorCallback, + "ApptentiveBridge", + "setPushNotificationIntegration", + [token] + ); + }, }; module.exports = Apptentive; From 66df3e504ff028043d9d9f54b2a447912337ef69 Mon Sep 17 00:00:00 2001 From: Frank Schmitt Date: Thu, 3 Oct 2024 14:26:59 -0700 Subject: [PATCH 2/5] Add setPushNotificationIntegration command --- src/ios/ApptentiveBridge.swift | 46 ++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/ios/ApptentiveBridge.swift b/src/ios/ApptentiveBridge.swift index b80841c..1a97383 100644 --- a/src/ios/ApptentiveBridge.swift +++ b/src/ios/ApptentiveBridge.swift @@ -231,6 +231,20 @@ class ApptentiveBridge: CDVPlugin { } } + @objc func setPushNotificationIntegration(_ command: CDVInvokedUrlCommand) { + do { + let _ = try Self.checkArgumentCount(command, 1...1) + let tokenString = try Self.string(from: command) + guard let tokenData = Data(hexString: tokenString) else { + throw PluginError.invalidJSONData + } + Apptentive.shared.setRemoteNotificationDeviceToken(tokenData) + self.commandDelegate.send(.init(status: CDVCommandStatus_OK), callbackId: command.callbackId) + } catch let error { + self.commandDelegate.send(.init(status: CDVCommandStatus_ERROR, messageAs: error.localizedDescription), callbackId: command.callbackId) + } + } + // MARK: - Helper functions func sendUnimplementedError(_ command: CDVInvokedUrlCommand) { @@ -376,6 +390,7 @@ class ApptentiveBridge: CDVPlugin { case invalidArgumentType(atIndex: Int, expecting: String) case unimplementedCommand(String) case invalidJSONData + case invalidTokenString(String) case unrecognizedLogLevel(String) var errorDescription: String? { @@ -416,9 +431,40 @@ class ApptentiveBridge: CDVPlugin { case .invalidJSONData: return "The string passed for the custom data argument is not valid JSON." + case .invalidTokenString(let string): + return "The device token (\(string)) was not recognized as valid hex-encoded data." + case .unrecognizedLogLevel(let logLevel): return "The log level (\"\(logLevel)\") is not a valid log level (valid values are \"verbose\", \"debug\", \"info\", \"warn\", \"error\", and \"critical\")." } } } } + +extension Data { + /// Creates a new Data object by converting hexadecimal characters in the input string. + /// + /// Returns nil if the string contains non-hexadecimal characters or has an odd number of characters. + /// - Parameter hexString: A string of hexadecimal characters. + init?(hexString: String) { + // TODO: Use `Scanner` when we drop iOS <13 support. + var result = Data() + var index = hexString.startIndex + + while index < hexString.endIndex { + guard let endIndex = hexString.index(index, offsetBy: 2, limitedBy: hexString.endIndex) else { + return nil + } + + guard let byte = UInt8(String(hexString[index.. Date: Thu, 3 Oct 2024 15:07:59 -0700 Subject: [PATCH 3/5] Throw correct error --- src/ios/ApptentiveBridge.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ios/ApptentiveBridge.swift b/src/ios/ApptentiveBridge.swift index 1a97383..512b511 100644 --- a/src/ios/ApptentiveBridge.swift +++ b/src/ios/ApptentiveBridge.swift @@ -236,7 +236,7 @@ class ApptentiveBridge: CDVPlugin { let _ = try Self.checkArgumentCount(command, 1...1) let tokenString = try Self.string(from: command) guard let tokenData = Data(hexString: tokenString) else { - throw PluginError.invalidJSONData + throw PluginError.invalidTokenString(tokenString) } Apptentive.shared.setRemoteNotificationDeviceToken(tokenData) self.commandDelegate.send(.init(status: CDVCommandStatus_OK), callbackId: command.callbackId) From ebe7062c8324591aa1fe6961fbb98961c1b3db51 Mon Sep 17 00:00:00 2001 From: Frank Schmitt Date: Thu, 3 Oct 2024 15:09:38 -0700 Subject: [PATCH 4/5] Remove invalid TODO --- src/ios/ApptentiveBridge.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ios/ApptentiveBridge.swift b/src/ios/ApptentiveBridge.swift index 512b511..4d7abf9 100644 --- a/src/ios/ApptentiveBridge.swift +++ b/src/ios/ApptentiveBridge.swift @@ -447,7 +447,6 @@ extension Data { /// Returns nil if the string contains non-hexadecimal characters or has an odd number of characters. /// - Parameter hexString: A string of hexadecimal characters. init?(hexString: String) { - // TODO: Use `Scanner` when we drop iOS <13 support. var result = Data() var index = hexString.startIndex From f900b3a141b046ae2aa8591b9084143d8a4da920 Mon Sep 17 00:00:00 2001 From: frankus Date: Thu, 3 Oct 2024 23:43:11 +0000 Subject: [PATCH 5/5] Update for 6.9.0 --- .scripts/changes.md | 4 ++-- CHANGELOG.md | 5 +++++ package.json | 2 +- plugin.xml | 4 ++-- www/Apptentive.js | 2 +- 5 files changed, 11 insertions(+), 6 deletions(-) diff --git a/.scripts/changes.md b/.scripts/changes.md index f617539..c086074 100644 --- a/.scripts/changes.md +++ b/.scripts/changes.md @@ -1,2 +1,2 @@ -- Apptentive Android SDK: 6.8.0 -- Apptentive iOS SDK: 6.8.1 +- Apptentive Android SDK: 6.9.0 +- Apptentive iOS SDK: 6.9.0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 488dc77..a9d68e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ This document lets you know what has changed in the Cordova plugin. For changes - [Android Changelog](https://github.com/apptentive/apptentive-kit-android/blob/master/CHANGELOG.md) - [iOS Changelog](https://github.com/apptentive/apptentive-kit-ios/blob/master/CHANGELOG.md) +# 2024-10-03 - v6.9.0 + +- Apptentive Android SDK: 6.9.0 +- Apptentive iOS SDK: 6.9.0 + # 2024-06-26 - v6.8.0 - Apptentive Android SDK: 6.8.0 diff --git a/package.json b/package.json index fd9ddc4..1d9fe80 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "apptentive-cordova", - "version": "6.8.0", + "version": "6.9.0", "description": "Apptentive Plugin For Cordova", "cordova": { "id": "apptentive-cordova", diff --git a/plugin.xml b/plugin.xml index e346b71..3ef8061 100644 --- a/plugin.xml +++ b/plugin.xml @@ -1,5 +1,5 @@ - + Apptentive Apptentive Plugin For Cordova @@ -112,7 +112,7 @@ - + diff --git a/www/Apptentive.js b/www/Apptentive.js index 2d38e4b..4767dd2 100644 --- a/www/Apptentive.js +++ b/www/Apptentive.js @@ -1,5 +1,5 @@ var Apptentive = { - distributionVersion: "6.8.0", + distributionVersion: "6.9.0", addCustomDeviceData: function (successCallback, errorCallback, key, value) { cordova.exec(