From 65601c0d9a9053bdd19425d3e9fb6baced1e9e49 Mon Sep 17 00:00:00 2001 From: Jeriel Ng Date: Mon, 26 Aug 2024 09:09:38 -0400 Subject: [PATCH] Release Cordova SDK version 10.0.0 --- CHANGELOG.md | 22 +++++ README.md | 9 +- package.json | 2 +- plugin.xml | 8 +- sample-project/config.xml | 8 +- sample-project/package.json | 2 +- sample-project/www/index.html | 5 + sample-project/www/js/index.js | 29 ++++++ src/android/BrazePlugin.kt | 83 +++++++++++++++- src/android/build-extras.gradle | 2 +- src/ios/BrazePlugin.h | 3 + src/ios/BrazePlugin.m | 161 ++++++++++++++++++++++++++++---- www/BrazePlugin.js | 126 ++++++++++++++++++++----- 13 files changed, 405 insertions(+), 55 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c471bca..b59faa0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,27 @@ ⚠️ In version 2.33.0, we changed the iOS bridge from AppboyKit, which is written in Objective-C, to the new [Swift SDK](https://github.com/braze-inc/braze-swift-sdk). If you are upgrading from a version below 2.33.0 to a version above 2.33.0, please read [the instructions](https://github.com/braze-inc/braze-cordova-sdk/blob/master/CHANGELOG.md#2330) to ensure a smooth transition and backward compatibility. +## 10.0.0 + +##### Breaking +- ⚠️ This version now requires Cordova Android 13.0.0. ⚠️ + - Refer to the [Cordova release announcement](https://cordova.apache.org/announcements/2024/05/23/cordova-android-13.0.0.html) for a full list of project dependency requirements. +- Updated the native Android bridge [from Braze Android SDK 30.3.0 to 32.1.0](https://github.com/braze-inc/braze-android-sdk/compare/v30.3.0...v32.1.0#diff-06572a96a58dc510037d5efa622f9bec8519bc1beab13c9f251e97e657a9d4ed). +- Updated the native iOS bridge [from Braze Swift SDK 9.2.0 to 10.1.0](https://github.com/braze-inc/braze-swift-sdk/compare/9.2.0...10.1.0#diff-06572a96a58dc510037d5efa622f9bec8519bc1beab13c9f251e97e657a9d4ed). + +##### Fixed +- Fixed the native-to-JavaScript translation of in-app message strings, where nested escape characters were previously being removed. +- Fixed the `subscribeToInAppMessage` method on iOS to respect the `useBrazeUI` setting. + - Updated the Android implementation to match iOS by using the `DISCARD` option instead of `DISPLAY_LATER` if the default Braze UI is not used. +- Fixed the `getContentCardsFromServer` method to trigger an error callback on iOS when cards have failed to refresh. + +##### Added +- Added the `getUserId()` method to get the ID of the current user. This method will return `null` if the current user is anonymous. +- Added support for new Feature Flag property types and APIs for accessing them: + - `getFeatureFlagTimestampProperty(id, key)` for accessing Int Unix UTC millisecond timestamps as `number`s. + - `getFeatureFlagImageProperty(id, key)` for accessing image URLs as `string`s. + - `getFeatureFlagJSONProperty(id, key)` for accessing JSON objects as `object` types. +- Added `setLocationCustomAttribute(key, latitude, longitude)` to set a location custom attribute. + ## 9.2.0 ##### Added diff --git a/README.md b/README.md index 9bb1b7f..1d97322 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,14 @@ Effective marketing automation is an essential part of successfully scaling and See our [Technical Documentation for Android](https://www.braze.com/docs/developer_guide/platform_integration_guides/cordova/initial_sdk_setup/android/) and [Technical Documentation for iOS](https://www.braze.com/docs/developer_guide/platform_integration_guides/cordova/initial_sdk_setup/ios/) for instructions on integrating Braze into your Cordova app. -# Running the sample application +## Minimum version requirements + +| Braze Plugin | Cordova Android | Cordova iOS | +| ------------ | --------------- | ----------- | +| 10.0.0+ | >= 13.0.0 | >= 5.0.0 | +| 2.31.0+ | >= 12.0.0 | >= 5.0.0 | + +## Running the sample application ``` cordova plugin remove cordova-plugin-braze diff --git a/package.json b/package.json index f79d09a..91f12ff 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { "name": "braze-cordova-sdk", - "version": "9.2.0", + "version": "10.0.0", "main": "www/BrazePlugin.js" } \ No newline at end of file diff --git a/plugin.xml b/plugin.xml index e6f8ed7..be5ef8b 100644 --- a/plugin.xml +++ b/plugin.xml @@ -1,6 +1,6 @@ + id="cordova-plugin-braze" version="10.0.0"> Braze Braze Cordova SDK MIT @@ -54,9 +54,9 @@ - - - + + + diff --git a/sample-project/config.xml b/sample-project/config.xml index 98550e9..44ea3a9 100755 --- a/sample-project/config.xml +++ b/sample-project/config.xml @@ -25,10 +25,10 @@ - - - - + + + + diff --git a/sample-project/package.json b/sample-project/package.json index b7aad68..28155a6 100644 --- a/sample-project/package.json +++ b/sample-project/package.json @@ -23,7 +23,7 @@ }, "devDependencies": { "braze-cordova-sdk": "file:../local", - "cordova-android": "^11.0.0", + "cordova-android": "^13.0.0", "cordova-ios": "^6.2.0" } } \ No newline at end of file diff --git a/sample-project/www/index.html b/sample-project/www/index.html index 609b681..d4ff01d 100755 --- a/sample-project/www/index.html +++ b/sample-project/www/index.html @@ -48,6 +48,7 @@

Apache Cordova

+
@@ -97,6 +98,7 @@

Apache Cordova

+ @@ -116,6 +118,9 @@

Apache Cordova

+ + + diff --git a/sample-project/www/js/index.js b/sample-project/www/js/index.js index 7691f60..7563d51 100755 --- a/sample-project/www/js/index.js +++ b/sample-project/www/js/index.js @@ -41,6 +41,7 @@ var app = { document.getElementById("getFeatureFlagPropertyBtn").addEventListener("click", getFeatureFlagProperty); document.getElementById("logFeatureFlagImpressionBtn").addEventListener("click", logFeatureFlagImpression); document.getElementById("changeUserBtn").addEventListener("click", changeUser); + document.getElementById("getUserIdBtn").addEventListener("click", getUserId); document.getElementById("setSdkAuthBtn").addEventListener("click", setSdkAuthenticationSignature); document.getElementById("logCustomEventBtn").addEventListener("click", logCustomEvent); document.getElementById("logPurchaseBtn").addEventListener("click", logPurchase); @@ -70,6 +71,7 @@ var app = { document.getElementById("requestFlushBtn").addEventListener("click", requestDataFlush); document.getElementById("setLanguageBtn").addEventListener("click", setLanguage); document.getElementById("setLastKnownLocationBtn").addEventListener("click", setLastKnownLocation); + document.getElementById("setLocationCustomAttributeBtn").addEventListener("click", setLocationCustomAttribute); document.getElementById("getDeviceId").addEventListener("click", getDeviceId); document.getElementById("requestPushPermission").addEventListener("click", requestPushPermission); document.getElementById("updateTrackingPropertiesBtn").addEventListener("click", updateTrackingProperties); @@ -118,6 +120,16 @@ function changeUser() { showTextBubble(`User changed to ${userId} with auth signature ${sdkAuthSignature}`); } +async function getUserId() { + BrazePlugin.getUserId(customPluginSuccessCallback("User ID: "), customPluginErrorCallback); + const userId = await BrazePlugin.getUserId(); + if (!userId) { + showTextBubble("User ID not found."); + } else { + showTextBubble(`User ID: ${userId}`); + } +} + function setSdkAuthenticationSignature() { const sdkAuthSignature = document.getElementById("sdkAuthSignature").value; if (!sdkAuthSignature) { @@ -187,6 +199,18 @@ async function getFeatureFlagProperty() { const stringProperty = await BrazePlugin.getFeatureFlagStringProperty(featureFlagId, propertyKey); showTextBubble(`Got string property: ${stringProperty}`); break; + case 'timestamp': + const timestampProperty = await BrazePlugin.getFeatureFlagTimestampProperty(featureFlagId, propertyKey); + showTextBubble(`Got timestamp property: ${timestampProperty}`); + break; + case 'jsonobject': + const jsonProperty = await BrazePlugin.getFeatureFlagJSONProperty(featureFlagId, propertyKey); + showTextBubble(`Got JSON property: ${JSON.stringify(jsonProperty)}`); + break; + case 'image': + const imageProperty = await BrazePlugin.getFeatureFlagImageProperty(featureFlagId, propertyKey); + showTextBubble(`Got image property: ${imageProperty}`); + break; default: showTextBubble("No property type selected."); } @@ -465,6 +489,11 @@ function setLastKnownLocation() { } } +function setLocationCustomAttribute() { + BrazePlugin.setLocationCustomAttribute("work", 40.7128, 74.006); + showTextBubble("Location custom attribute set."); +} + function getDeviceId() { BrazePlugin.getDeviceId(customPluginSuccessCallback("Device ID: "), customPluginErrorCallback); } diff --git a/src/android/BrazePlugin.kt b/src/android/BrazePlugin.kt index 4e72677..7682900 100644 --- a/src/android/BrazePlugin.kt +++ b/src/android/BrazePlugin.kt @@ -95,6 +95,16 @@ open class BrazePlugin : CordovaPlugin() { runOnBraze { it.changeUser(userId, sdkAuthToken) } return true } + "getUserId" -> { + runOnUser { + if (it.userId.isNullOrBlank()) { + callbackContext.sendCordovaSuccessPluginResultAsNull() + } else { + callbackContext.success(it.userId) + } + } + return true + } "logCustomEvent" -> { var properties: BrazeProperties? = null if (args[1] !== JSONObject.NULL) { @@ -293,6 +303,22 @@ open class BrazePlugin : CordovaPlugin() { } return true } + "setLocationCustomAttribute" -> { + runOnUser { + val newArgs = parseJSONArraytoDoubleArray(args) + val key = args.getString(0) + val latitude = newArgs[1] + val longitude = newArgs[2] + + if (latitude == null || longitude == null) { + brazelog (I) { "Invalid location information with the latitude: $latitude, longitude: $longitude" } + } else { + it.setLocationCustomAttribute(key, latitude, longitude) + brazelog (I) { "Location custom attribute set with key: $key, latitude: $latitude, longitude: $longitude"} + } + } + return true + } "setPushNotificationSubscriptionType" -> { runOnUser { currentUser -> NotificationSubscriptionType.fromValue(args.getString(0))?.let { @@ -337,7 +363,7 @@ open class BrazePlugin : CordovaPlugin() { inAppMessageDisplayOperation = if (useBrazeUI) { InAppMessageOperation.DISPLAY_NOW } else { - InAppMessageOperation.DISPLAY_LATER + InAppMessageOperation.DISCARD } setDefaultInAppMessageListener() } @@ -507,6 +533,45 @@ open class BrazePlugin : CordovaPlugin() { } return true } + "getFeatureFlagTimestampProperty" -> { + runOnBraze { + val flagId = args.getString(0) + val propKey = args.getString(1) + val result = it.getFeatureFlag(flagId)?.getTimestampProperty(propKey) + if (result == null) { + callbackContext.sendCordovaSuccessPluginResultAsNull() + } else { + callbackContext.sendPluginResult(PluginResult(PluginResult.Status.OK, result.toFloat())) + } + } + return true + } + "getFeatureFlagJSONProperty" -> { + runOnBraze { + val flagId = args.getString(0) + val propKey = args.getString(1) + val result = it.getFeatureFlag(flagId)?.getJSONProperty(propKey) + if (result == null) { + callbackContext.sendCordovaSuccessPluginResultAsNull() + } else { + callbackContext.sendPluginResult(PluginResult(PluginResult.Status.OK, result)) + } + } + return true + } + "getFeatureFlagImageProperty" -> { + runOnBraze { + val flagId = args.getString(0) + val propKey = args.getString(1) + val result = it.getFeatureFlag(flagId)?.getImageProperty(propKey) + if (result == null) { + callbackContext.sendCordovaSuccessPluginResultAsNull() + } else { + callbackContext.sendPluginResult(PluginResult(PluginResult.Status.OK, result)) + } + } + return true + } "logFeatureFlagImpression" -> { runOnBraze { Braze.getInstance(applicationContext).logFeatureFlagImpression(args.getString(0)) @@ -942,7 +1007,7 @@ open class BrazePlugin : CordovaPlugin() { super.beforeInAppMessageDisplayed(inAppMessage) // Convert in-app message to string - val inAppMessageString = inAppMessage.forJsonPut().toString() + val inAppMessageString = escapeStringForJavaScript(inAppMessage.forJsonPut().toString()) brazelog { "In-app message received: $inAppMessageString" } // Send in-app message string back to JavaScript in an `inAppMessageReceived` event @@ -1026,6 +1091,20 @@ open class BrazePlugin : CordovaPlugin() { return categories } + /** + * Map a Kotlin string to a JavaScript-representable version. + * Escape characters are lost in translation, so we need to manually insert them back in. + */ + fun escapeStringForJavaScript(input: String): String { + return input + .replace("\\", "\\\\") + .replace("\"", "\\\"") + .replace("\'", "\\\'") + .replace("\n", "\\n") + .replace("\r", "\\r") + .replace("\t", "\\t") + } + /** * This takes the JSONArray of Any and returns an Array. * diff --git a/src/android/build-extras.gradle b/src/android/build-extras.gradle index 2792fb7..e83b291 100644 --- a/src/android/build-extras.gradle +++ b/src/android/build-extras.gradle @@ -4,7 +4,7 @@ repositories { } dependencies { - implementation 'com.braze:android-sdk-ui:30.3.0' + implementation 'com.braze:android-sdk-ui:32.1.0' implementation 'com.google.firebase:firebase-messaging:23.0.0' } diff --git a/src/ios/BrazePlugin.h b/src/ios/BrazePlugin.h index 2a918d7..aecef04 100644 --- a/src/ios/BrazePlugin.h +++ b/src/ios/BrazePlugin.h @@ -81,6 +81,9 @@ - (void)getFeatureFlagBooleanProperty:(CDVInvokedUrlCommand *)command; - (void)getFeatureFlagStringProperty:(CDVInvokedUrlCommand *)command; - (void)getFeatureFlagNumberProperty:(CDVInvokedUrlCommand *)command; +- (void)getFeatureFlagTimestampProperty:(CDVInvokedUrlCommand *)command; +- (void)getFeatureFlagJSONProperty:(CDVInvokedUrlCommand *)command; +- (void)getFeatureFlagImageProperty:(CDVInvokedUrlCommand *)command; - (void)logFeatureFlagImpression:(CDVInvokedUrlCommand *)command; @end diff --git a/src/ios/BrazePlugin.m b/src/ios/BrazePlugin.m index 0df7dfd..2862fc3 100644 --- a/src/ios/BrazePlugin.m +++ b/src/ios/BrazePlugin.m @@ -33,6 +33,7 @@ @interface BrazePlugin() @implementation BrazePlugin bool isInAppMessageSubscribed; +bool useBrazeUIForInAppMessages; + (Braze *)braze { return _braze; @@ -63,6 +64,7 @@ - (void)pluginInitialize { self.useAutomaticRequestPolicy = settings[@"com.braze.ios_use_automatic_request_policy"]; self.optInWhenPushAuthorized = settings[@"com.braze.should_opt_in_when_push_authorized"]; isInAppMessageSubscribed = NO; + useBrazeUIForInAppMessages = YES; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didFinishLaunchingListener:) name:UIApplicationDidFinishLaunchingNotification object:nil]; @@ -246,6 +248,16 @@ - (void)changeUser:(CDVInvokedUrlCommand *)command { } } +- (void)getUserId:(CDVInvokedUrlCommand *)command { + [self.braze.user idWithCompletion:^(NSString * _Nullable userId) { + if (!userId) { + [self sendCordovaSuccessPluginResultAsNull:command]; + } else { + [self sendCordovaSuccessPluginResultWithString:userId andCommand:command]; + } + }]; +} + - (void)setSdkAuthenticationSignature:(CDVInvokedUrlCommand *)command { NSString *sdkAuthSignature = [command argumentAtIndex:0 withDefault:nil]; if (sdkAuthSignature) { @@ -382,6 +394,23 @@ - (void)setLastKnownLocation:(CDVInvokedUrlCommand *)command { } } +- (void)setLocationCustomAttribute:(CDVInvokedUrlCommand *)command { + NSString *key = [command argumentAtIndex:0 withDefault:nil]; + NSNumber *latitude = [command argumentAtIndex:1 withDefault:nil]; + NSNumber *longitude = [command argumentAtIndex:2 withDefault:nil]; + + if (!latitude || !longitude) { + NSLog(@"Invalid location information with the latitude: %@, longitude: %@", + latitude ? latitude : @"nil", + longitude ? longitude : @"nil"); + } else { + [self.braze.user setLocationCustomAttributeWithKey:key + latitude:[latitude doubleValue] + longitude:[longitude doubleValue]]; + NSLog(@"Location custom attribute set with key: %@, latitude: %@, longitude: %@", key, latitude, longitude); + } +} + - (void)setPushNotificationSubscriptionType:(CDVInvokedUrlCommand *)command { NSString *subscriptionState = [command argumentAtIndex:0 withDefault:nil]; [self.braze.user setPushNotificationSubscriptionState:[self getSubscriptionStateFromString:subscriptionState]]; @@ -795,6 +824,7 @@ - (void)getContentCardsFromServer:(CDVInvokedUrlCommand *)command { [self.braze.contentCards requestRefreshWithCompletion:^(NSArray * _Nullable cards, NSError * _Nullable error) { if (error) { NSLog(@"%@", error.debugDescription); + [self sendCordovaErrorPluginResultWithString:error.debugDescription andCommand:command]; } else { NSLog(@"Got Content Cards from server callback"); [self getContentCardsFromCache:command]; @@ -894,10 +924,7 @@ + (NSString *)getJsonFromExtras:(NSDictionary *)extras { /// Subscribes to in-app message updates. - (void)subscribeToInAppMessage:(CDVInvokedUrlCommand *)command { bool useBrazeUI = [command argumentAtIndex:0 withDefault:nil]; - if (!useBrazeUI) { - // A custom delegate is being used. Do nothing. - return; - } + useBrazeUIForInAppMessages = useBrazeUI; isInAppMessageSubscribed = YES; } @@ -1078,6 +1105,60 @@ - (void)getFeatureFlagNumberProperty:(CDVInvokedUrlCommand *)command { } } +- (void)getFeatureFlagTimestampProperty:(CDVInvokedUrlCommand *)command { + NSString *featureFlagId = [command argumentAtIndex:0 withDefault:nil]; + NSString *propertyKey = [command argumentAtIndex:1 withDefault:nil]; + + BRZFeatureFlag *featureFlag = [self.braze.featureFlags featureFlagWithId:featureFlagId]; + if (!featureFlag) { + [self sendCordovaSuccessPluginResultAsNull:command]; + return; + } + + NSNumber *timestampProperty = [featureFlag timestampPropertyForKey:propertyKey]; + if (timestampProperty) { + [self sendCordovaSuccessPluginResultWithDouble:[timestampProperty doubleValue] andCommand:command]; + } else { + [self sendCordovaSuccessPluginResultAsNull:command]; + } +} + +- (void)getFeatureFlagJSONProperty:(CDVInvokedUrlCommand *)command { + NSString *featureFlagId = [command argumentAtIndex:0 withDefault:nil]; + NSString *propertyKey = [command argumentAtIndex:1 withDefault:nil]; + + BRZFeatureFlag *featureFlag = [self.braze.featureFlags featureFlagWithId:featureFlagId]; + if (!featureFlag) { + [self sendCordovaSuccessPluginResultAsNull:command]; + return; + } + + NSDictionary *jsonProperty = [featureFlag jsonObjectPropertyForKey:propertyKey]; + if (jsonProperty) { + [self sendCordovaSuccessPluginResultWithDictionary:jsonProperty andCommand:command]; + } else { + [self sendCordovaSuccessPluginResultAsNull:command]; + } +} + +- (void)getFeatureFlagImageProperty:(CDVInvokedUrlCommand *)command { + NSString *featureFlagId = [command argumentAtIndex:0 withDefault:nil]; + NSString *propertyKey = [command argumentAtIndex:1 withDefault:nil]; + + BRZFeatureFlag *featureFlag = [self.braze.featureFlags featureFlagWithId:featureFlagId]; + if (!featureFlag) { + [self sendCordovaSuccessPluginResultAsNull:command]; + return; + } + + NSString *imageProperty = [featureFlag imagePropertyForKey:propertyKey]; + if (imageProperty) { + [self sendCordovaSuccessPluginResultWithString:imageProperty andCommand:command]; + } else { + [self sendCordovaSuccessPluginResultAsNull:command]; + } +} + - (void)logFeatureFlagImpression:(CDVInvokedUrlCommand *)command { NSString *featureFlagId = [command argumentAtIndex:0 withDefault:nil]; if (featureFlagId) { @@ -1172,13 +1253,53 @@ - (void)sendCordovaSuccessPluginResultAsNull:(CDVInvokedUrlCommand *)command { // MARK: - Helper Methods /** - Takes an NSString, trim whitespaces, and return the sanitized NSString converted to lowercase. - **/ + * Takes an NSString, trim whitespaces, and return the sanitized NSString converted to lowercase. + */ - (NSString *)sanitizeString:(NSString *)inputString { NSString *trimmedString = [inputString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; return ([trimmedString lowercaseString]); } +/** + * Map an `NSString` to a JavaScript-representable version. + * Escape characters are lost in translation, so we need to manually insert them back in. + */ +- (NSString *)escapeStringForJavaScript:(NSString *)input { + NSMutableString *escapedString = [NSMutableString stringWithString:input]; + + [escapedString replaceOccurrencesOfString:@"\\" + withString:@"\\\\" + options:NSLiteralSearch + range:NSMakeRange(0, [escapedString length])]; + + [escapedString replaceOccurrencesOfString:@"\"" + withString:@"\\\"" + options:NSLiteralSearch + range:NSMakeRange(0, [escapedString length])]; + + [escapedString replaceOccurrencesOfString:@"\'" + withString:@"\\\'" + options:NSLiteralSearch + range:NSMakeRange(0, [escapedString length])]; + + [escapedString replaceOccurrencesOfString:@"\n" + withString:@"\\n" + options:NSLiteralSearch + range:NSMakeRange(0, [escapedString length])]; + + [escapedString replaceOccurrencesOfString:@"\r" + withString:@"\\r" + options:NSLiteralSearch + range:NSMakeRange(0, [escapedString length])]; + + [escapedString replaceOccurrencesOfString:@"\t" + withString:@"\\t" + options:NSLiteralSearch + range:NSMakeRange(0, [escapedString length])]; + + return escapedString; +} + - (BRZTrackingProperty *)convertTrackingProperty:(NSString *)propertyString { if ([propertyString isEqualToString:@"all_custom_attributes"]) { return BRZTrackingProperty.allCustomAttributes; @@ -1224,20 +1345,24 @@ - (BRZTrackingProperty *)convertTrackingProperty:(NSString *)propertyString { // MARK: - BrazeInAppMessageUIDelegate -- (void)inAppMessage:(BrazeInAppMessageUI *)ui - didPresent:(BRZInAppMessageRaw *)message - view:(UIView *)view { - if (!isInAppMessageSubscribed) { - return; - } +- (enum BRZInAppMessageUIDisplayChoice)inAppMessage:(BrazeInAppMessageUI *)ui displayChoiceForMessage:(BRZInAppMessageRaw *)message { // Convert in-app message to string - NSData *inAppMessageData = [message json]; - NSString *inAppMessageString = [[NSString alloc] initWithData:inAppMessageData encoding:NSUTF8StringEncoding]; - NSLog(@"In-app message received: %@", inAppMessageString); + if (isInAppMessageSubscribed) { + NSData *inAppMessageData = [message json]; + NSString *inAppMessageString = [[NSString alloc] initWithData:inAppMessageData encoding:NSUTF8StringEncoding]; + inAppMessageString = [self escapeStringForJavaScript:inAppMessageString]; + NSLog(@"In-app message received: %@", inAppMessageString); - // Send in-app message string back to JavaScript in an `inAppMessageReceived` event - NSString* jsStatement = [NSString stringWithFormat:@"app.inAppMessageReceived('%@');", inAppMessageString]; - [self.commandDelegate evalJs:jsStatement]; + // Send in-app message string back to JavaScript in an `inAppMessageReceived` event + NSString* jsStatement = [NSString stringWithFormat:@"app.inAppMessageReceived('%@');", inAppMessageString]; + [self.commandDelegate evalJs:jsStatement]; + } + + if (useBrazeUIForInAppMessages) { + return BRZInAppMessageUIDisplayChoiceNow; + } else { + return BRZInAppMessageUIDisplayChoiceDiscard; + } } @end diff --git a/www/BrazePlugin.js b/www/BrazePlugin.js index 1076a68..3744170 100644 --- a/www/BrazePlugin.js +++ b/www/BrazePlugin.js @@ -40,6 +40,21 @@ BrazePlugin.prototype.changeUser = function (userId, sdkAuthenticationToken) { cordova.exec(null, null, "BrazePlugin", "changeUser", [userId, sdkAuthenticationToken]); } +/** + * Gets the unique ID stored for the user. + * + * @return A promise containing a string of the user ID. + */ +BrazePlugin.prototype.getUserId = function () { + return new Promise((resolve, reject) => { + cordova.exec((userId) => { + resolve(userId); + }, (error) => { + reject(error); + }, "BrazePlugin", "getUserId"); + }); +} + /** * ** ANDROID ONLY** * @@ -287,6 +302,17 @@ BrazePlugin.prototype.setLastKnownLocation = function (latitude, longitude, alti cordova.exec(null, null, "BrazePlugin", "setLastKnownLocation", [latitude, longitude, altitude, horizontalAccuracy, verticalAccuracy]); } +/** + * Sets a custom location attribute for the user. + * @param {string} key - The identifier of the custom attribute. Limited to 255 characters in length, cannot begin with + * a dollar sign (`$`), and can only contain alphanumeric characters and punctuation. + * @param {double} latitude - The latitude in degrees, must be included in `-90...90`. + * @param {double} longitude - The longitude in degrees, must be included in `-180...180`. + */ +BrazePlugin.prototype.setLocationCustomAttribute = function (key, latitude, longitude) { + cordova.exec(null, null, "BrazePlugin", "setLocationCustomAttribute", [key, latitude, longitude]); +} + /** * Sets whether the user should be sent push campaigns. * @param {NotificationSubscriptionTypes} notificationSubscriptionType - Notification setting (explicitly @@ -363,79 +389,82 @@ BrazePlugin.prototype.getNewsFeed = function (successCallback, errorCallback) { // News Feed methods /** -* Gets the number of unread News Feed Cards. The result is returned as an integer argument to the successCallback function. The card count uses the cards present in the cache. News Feed cards are not refreshed as a result of this call. -*/ + * Gets the number of unread News Feed Cards. The result is returned as an integer argument to the successCallback function. The card count uses the cards present in the cache. News Feed cards are not refreshed as a result of this call. + */ BrazePlugin.prototype.getNewsFeedUnreadCount = function (successCallback, errorCallback) { cordova.exec(successCallback, errorCallback, "BrazePlugin", "getUnreadCardCountForCategories", ['all']); } /** -* Gets the number of News Feed Cards. The result is returned as an integer argument to the successCallback function. The card count uses the cards present in the cache. News Feed cards are not refreshed as a result of this call. -**/ + * Gets the number of News Feed Cards. The result is returned as an integer argument to the successCallback function. The card count uses the cards present in the cache. News Feed cards are not refreshed as a result of this call. + */ BrazePlugin.prototype.getNewsFeedCardCount = function (successCallback, errorCallback) { cordova.exec(successCallback, errorCallback, "BrazePlugin", "getCardCountForCategories", ['all']); } /** -* Gets the number of News Feed Cards for a category. The result is returned as an integer argument to the successCallback function. The card count uses the cards present in the cache. News Feed cards are not refreshed as a result of this call. -**/ + * Gets the number of News Feed Cards for a category. The result is returned as an integer argument to the successCallback function. The card count uses the cards present in the cache. News Feed cards are not refreshed as a result of this call. + */ BrazePlugin.prototype.getCardCountForCategories = function (successCallback, errorCallback, cardCategories) { cordova.exec(successCallback, errorCallback, "BrazePlugin", "getCardCountForCategories", cardCategories); } /** -* Gets the number of unread News Feed Cards for a category. The result is returned as an integer argument to the successCallback function. The card count uses the cards present in the cache. News Feed cards are not refreshed as a result of this call. -*/ + * Gets the number of unread News Feed Cards for a category. The result is returned as an integer argument to the successCallback function. The card count uses the cards present in the cache. News Feed cards are not refreshed as a result of this call. + */ BrazePlugin.prototype.getUnreadCardCountForCategories = function (successCallback, errorCallback, cardCategories) { cordova.exec(successCallback, errorCallback, "BrazePlugin", "getUnreadCardCountForCategories", cardCategories); } /** -* Wipes Data on the Braze SDK. On iOS, the SDK will be disabled for the rest of the app run. -*/ + * Wipes Data on the Braze SDK. On iOS, the SDK will be disabled for the rest of the app run. + */ BrazePlugin.prototype.wipeData = function () { cordova.exec(null, null, "BrazePlugin", "wipeData"); } /** -* Enables the Braze SDK after a previous call to disableSDK(). -* On iOS, the SDK will be enabled only after a subsequent call to startWithApiKey(). -*/ + * Enables the Braze SDK after a previous call to disableSDK(). + * On iOS, the SDK will be enabled only after a subsequent call to startWithApiKey(). + */ BrazePlugin.prototype.enableSdk = function () { cordova.exec(null, null, "BrazePlugin", "enableSdk"); } /** -* Disables the Braze SDK immediately. -*/ + * Disables the Braze SDK immediately. + */ BrazePlugin.prototype.disableSdk = function () { cordova.exec(null, null, "BrazePlugin", "disableSdk"); } /** -* Requests that the Braze SDK immediately flush any pending data. -*/ + * Requests that the Braze SDK immediately flush any pending data. + */ BrazePlugin.prototype.requestImmediateDataFlush = function () { cordova.exec(null, null, "BrazePlugin", "requestImmediateDataFlush"); } /** -* Requests the latest Content Cards from the Braze SDK server. -*/ + * Requests the latest Content Cards from the Braze SDK server. + */ BrazePlugin.prototype.requestContentCardsRefresh = function () { cordova.exec(null, null, "BrazePlugin", "requestContentCardsRefresh"); } /** -* Retrieves Content Cards from the Braze SDK. This will return the latest list of cards from the server. -*/ + * Retrieves Content Cards from the Braze SDK. This will return the latest list of cards from the server. + * + * @param {function} successCallback - The function to call when the cards are successfully retrieved. + * @param {function} errorCallback - The function to call when an error occurs. No-op on Android. + */ BrazePlugin.prototype.getContentCardsFromServer = function (successCallback, errorCallback) { cordova.exec(successCallback, errorCallback, "BrazePlugin", "getContentCardsFromServer"); } /** -* Retrieves Content Cards from the Braze SDK. This will return the latest list of cards from the cache. -*/ + * Retrieves Content Cards from the Braze SDK. This will return the latest list of cards from the cache. + */ BrazePlugin.prototype.getContentCardsFromCache = function (successCallback, errorCallback) { cordova.exec(successCallback, errorCallback, "BrazePlugin", "getContentCardsFromCache"); } @@ -652,6 +681,57 @@ BrazePlugin.prototype.getFeatureFlagNumberProperty = function (flagId, propertyK }) } +/** + * Requests a timestamp property for a given Feature Flag ID and a property key. + * @param {string} flagId - The identifier for the Feature Flag. + * @param {string} propertyKey - The key for the timestamp property. + * + * @return A promise containing the timestamp property requested. This will return null if there is no such property or Feature Flag. + */ +BrazePlugin.prototype.getFeatureFlagTimestampProperty = function (flagId, propertyKey) { + return new Promise((resolve, reject) => { + cordova.exec((timestampProperty) => { + resolve(timestampProperty); + }, (error) => { + reject(error); + }, "BrazePlugin", "getFeatureFlagTimestampProperty", [flagId, propertyKey]); + }) +} + +/** + * Requests a JSON property for a given Feature Flag ID and a property key. + * @param {string} flagId - The identifier for the Feature Flag. + * @param {string} propertyKey - The key for the JSON property. + * + * @return A promise containing the JSON property requested. This will return null if there is no such property or Feature Flag. + */ +BrazePlugin.prototype.getFeatureFlagJSONProperty = function (flagId, propertyKey) { + return new Promise((resolve, reject) => { + cordova.exec((jsonProperty) => { + resolve(jsonProperty); + }, (error) => { + reject(error); + }, "BrazePlugin", "getFeatureFlagJSONProperty", [flagId, propertyKey]); + }) +} + +/** + * Requests an image property for a given Feature Flag ID and a property key. + * @param {string} flagId - The identifier for the Feature Flag. + * @param {string} propertyKey - The key for the image property. + * + * @return A promise containing the image property requested. This will return null if there is no such property or Feature Flag. + */ +BrazePlugin.prototype.getFeatureFlagImageProperty = function (flagId, propertyKey) { + return new Promise((resolve, reject) => { + cordova.exec((imageProperty) => { + resolve(imageProperty); + }, (error) => { + reject(error); + }, "BrazePlugin", "getFeatureFlagImageProperty", [flagId, propertyKey]); + }) +} + /** * Log a Feature Flag impression. * An impression will only be logged if the feature flag is part of a Braze campaign.