diff --git a/CHANGELOG.md b/CHANGELOG.md index 40c2bb8..aedb96a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,28 @@ ⚠️ 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. +## 9.0.0 + +##### Breaking +- Updated the native iOS bridge [from Braze Swift SDK 7.7.0 to 9.0.0](https://github.com/braze-inc/braze-swift-sdk/compare/7.7.0...9.0.0#diff-06572a96a58dc510037d5efa622f9bec8519bc1beab13c9f251e97e657a9d4ed). + +##### Added +- Added support to modify the allow list for Braze tracking properties via the following JavaScript properties and methods: + - `TrackingProperty` string enum + - `TrackingPropertyAllowList` object interface + - `updateTrackingPropertyAllowList` method + - For details, refer to the [Braze iOS Privacy Manifest](https://www.braze.com/docs/developer_guide/platform_integration_guides/swift/privacy_manifest/) documentation. +- Added the `setAdTrackingEnabled` method to set `adTrackingEnabled` flag on iOS and both the `adTrackingEnabled` flag and the Google Advertising ID on Android. +- Added `BrazePlugin.subscribeToInAppMessage()` which allows you to listen for new in-app messages from the JavaScript plugin and choose whether or not to use the default Braze UI to display in-app messages. +- Added support for logging analytics and functionality for in-app messages. + - `BrazePlugin.logInAppMessageImpression(message)` + - `BrazePlugin.logInAppMessageClicked(message)` + - `BrazePlugin.loginAppMessageButtonClicked(message, buttonId)` + - `BrazePlugin.hideCurrentInAppMessage()` +- Added support for manually performing the action of an in-app message when using a custom UI. + - `BrazePlugin.performInAppMessageAction(message)` + - `BrazePlugin.performInAppMessageButtonAction(message, buttonId)` +- Updated the native Android bridge [from Braze Android SDK 30.1.1 to 30.3.0](https://github.com/braze-inc/braze-android-sdk/compare/v30.1.1...v30.3.0#diff-06572a96a58dc510037d5efa622f9bec8519bc1beab13c9f251e97e657a9d4ed). + ## 8.1.0 ##### Added diff --git a/package.json b/package.json index 195c1ec..e04d4b2 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { "name": "braze-cordova-sdk", - "version": "8.1.0", + "version": "9.0.0", "main": "www/BrazePlugin.js" -} +} \ No newline at end of file diff --git a/plugin.xml b/plugin.xml index a01da25..55108a2 100644 --- a/plugin.xml +++ b/plugin.xml @@ -1,6 +1,6 @@ + id="cordova-plugin-braze" version="9.0.0"> Braze Braze Cordova SDK MIT @@ -54,9 +54,9 @@ - - - + + + diff --git a/sample-project/config.xml b/sample-project/config.xml index 5008abd..98550e9 100755 --- a/sample-project/config.xml +++ b/sample-project/config.xml @@ -44,7 +44,6 @@ - @@ -56,7 +55,7 @@ - + - + - + diff --git a/sample-project/www/index.html b/sample-project/www/index.html index 3d04cfd..609b681 100755 --- a/sample-project/www/index.html +++ b/sample-project/www/index.html @@ -82,6 +82,9 @@

Apache Cordova


+ + +
@@ -99,6 +102,8 @@

Apache Cordova

+ +
diff --git a/sample-project/www/js/index.js b/sample-project/www/js/index.js index 2f30b5e..7691f60 100755 --- a/sample-project/www/js/index.js +++ b/sample-project/www/js/index.js @@ -72,6 +72,10 @@ var app = { document.getElementById("setLastKnownLocationBtn").addEventListener("click", setLastKnownLocation); document.getElementById("getDeviceId").addEventListener("click", getDeviceId); document.getElementById("requestPushPermission").addEventListener("click", requestPushPermission); + document.getElementById("updateTrackingPropertiesBtn").addEventListener("click", updateTrackingProperties); + document.getElementById("enableAdTrackingBtn").addEventListener("click", enableAdTracking); + document.getElementById("subscribeToInAppMessageBtn").addEventListener("click", subscribeToInAppMessage); + document.getElementById("hideCurrentInAppMessageBtn").addEventListener("click", hideCurrentInAppMessage); BrazePlugin.subscribeToSdkAuthenticationFailures(customPluginSuccessCallback(), customPluginErrorCallback); }, // Update DOM on a Received Event @@ -84,6 +88,15 @@ var app = { receivedElement.setAttribute('style', 'display:block;'); console.log('Received Event: ' + id); + }, + // In-App Message Received Event + inAppMessageReceived: function(message) { + console.log('Received in-app message and logging analytics: ' + message); + + // Log In-App Message Events + BrazePlugin.logInAppMessageClicked(message); + BrazePlugin.logInAppMessageImpression(message); + BrazePlugin.logInAppMessageButtonClicked(message, 0); } }; @@ -418,6 +431,15 @@ function logContentCardAnalytics() { }); } +function subscribeToInAppMessage() { + BrazePlugin.subscribeToInAppMessage(true); + showTextBubble("Subscribed to In-App Messages"); +} + +function hideCurrentInAppMessage() { + BrazePlugin.hideCurrentInAppMessage(); +} + function addAlias() { const aliasName = document.getElementById("aliasName").value; const aliasLabel = document.getElementById("aliasLabel").value; @@ -452,6 +474,29 @@ function requestPushPermission() { showTextBubble("requestPushPermission() called"); } +async function updateTrackingProperties() { + const allowList = { + adding: [ + BrazePlugin.TrackingProperty.FIRST_NAME, + BrazePlugin.TrackingProperty.LAST_NAME, + ], + removing: [BrazePlugin.TrackingProperty.DEVICE_DATA], + addingCustomEvents: ['custom-event1', 'custom-event2'], + removingCustomAttributes: ['attr-1'] + }; + BrazePlugin.updateTrackingPropertyAllowList(allowList); + console.log( + `Update tracking allow list with: ${JSON.stringify(allowList)}`, + ); + showTextBubble(`Updated tracking allow list: ${JSON.stringify(allowList)}`); +} + +function enableAdTracking() { + const testAdvertisingID = '123'; + BrazePlugin.setAdTrackingEnabled(true, testAdvertisingID); + showTextBubble(`Ad tracking enabled with ID: ${testAdvertisingID}`); +} + // Other helper functions function showTextBubble(bubbleMessage) { // Get the snackbar DIV diff --git a/src/android/BrazePlugin.kt b/src/android/BrazePlugin.kt index 353ab73..4e72677 100644 --- a/src/android/BrazePlugin.kt +++ b/src/android/BrazePlugin.kt @@ -12,19 +12,30 @@ import com.braze.cordova.ContentCardUtils.mapContentCards import com.braze.cordova.CordovaInAppMessageViewWrapper.CordovaInAppMessageViewWrapperFactory import com.braze.cordova.FeatureFlagUtils.mapFeatureFlags import com.braze.enums.* +import com.braze.enums.inappmessage.ClickAction import com.braze.events.ContentCardsUpdatedEvent import com.braze.events.FeatureFlagsUpdatedEvent import com.braze.events.FeedUpdatedEvent import com.braze.events.IEventSubscriber import com.braze.models.outgoing.AttributionData import com.braze.models.outgoing.BrazeProperties +import com.braze.models.inappmessage.IInAppMessage +import com.braze.models.inappmessage.IInAppMessageImmersive +import com.braze.models.inappmessage.InAppMessageBase +import com.braze.models.inappmessage.InAppMessageImmersiveBase +import com.braze.models.inappmessage.MessageButton import com.braze.support.BrazeLogger.Priority.* import com.braze.support.BrazeLogger.brazelog import com.braze.support.BrazeLogger.logLevel import com.braze.support.requestPushPermissionPrompt +import com.braze.support.toBundle +import com.braze.ui.BrazeDeeplinkHandler +import com.braze.ui.actions.NewsfeedAction import com.braze.ui.activities.BrazeFeedActivity import com.braze.ui.activities.ContentCardsActivity import com.braze.ui.inappmessage.BrazeInAppMessageManager +import com.braze.ui.inappmessage.InAppMessageOperation +import com.braze.ui.inappmessage.listeners.DefaultInAppMessageManagerListener import org.apache.cordova.CallbackContext import org.apache.cordova.CordovaPlugin import org.apache.cordova.CordovaPreferences @@ -42,6 +53,7 @@ open class BrazePlugin : CordovaPlugin() { private var pluginInitializationFinished = false private var disableAutoStartSessions = false private val feedSubscriberMap: MutableMap> = ConcurrentHashMap() + private var inAppMessageDisplayOperation: InAppMessageOperation = InAppMessageOperation.DISPLAY_NOW override fun pluginInitialize() { applicationContext = cordova.activity.applicationContext @@ -145,6 +157,13 @@ open class BrazePlugin : CordovaPlugin() { cordova.activity.requestPushPermissionPrompt() return true } + "updateTrackingPropertyAllowList" -> { + // iOS Only + } + "setAdTrackingEnabled" -> { + runOnBraze { it.setGoogleAdvertisingId(args.getString(1), args.getBoolean(0)) } + return true + } "setUserAttributionData" -> { runOnUser { it.setAttributionData( @@ -312,6 +331,110 @@ open class BrazePlugin : CordovaPlugin() { cordova.activity.startActivity(intent) return true } + "subscribeToInAppMessage" -> { + runOnBraze { + val useBrazeUI = args.getBoolean(0) + inAppMessageDisplayOperation = if (useBrazeUI) { + InAppMessageOperation.DISPLAY_NOW + } else { + InAppMessageOperation.DISPLAY_LATER + } + setDefaultInAppMessageListener() + } + } + "hideCurrentInAppMessage" -> { + BrazeInAppMessageManager.getInstance().hideCurrentlyDisplayingInAppMessage(true) + } + "logInAppMessageImpression" -> { + runOnBraze { + val inAppMessageString = args.getString(0) + brazelog { "logInAppMessageImpression called with value $inAppMessageString" } + it.deserializeInAppMessageString(inAppMessageString)?.logImpression() + } + return true + } + "logInAppMessageClicked" -> { + runOnBraze { + val inAppMessageString = args.getString(0) + brazelog { "logInAppMessageClicked called with value $inAppMessageString" } + it.deserializeInAppMessageString(inAppMessageString)?.logClick() + } + return true + } + "logInAppMessageButtonClicked" -> { + runOnBraze { braze -> + val inAppMessageString = args.getString(0) + val buttonId = args.getInt(1) + brazelog { "logInAppMessageButtonClicked called with value $inAppMessageString, and button: $buttonId" } + val inAppMessage = braze.deserializeInAppMessageString(inAppMessageString) + if (inAppMessage is IInAppMessageImmersive) { + inAppMessage.messageButtons + .firstOrNull { it.id == buttonId } + ?.let { inAppMessage.logButtonClick(it) } + } + } + return true + } + "performInAppMessageAction" -> { + val inAppMessageString = args.getString(0) + val buttonId = args.getInt(1) + runOnBraze { braze -> + brazelog { "performInAppMessageAction called with value $inAppMessageString, and button: $buttonId" } + braze.deserializeInAppMessageString(inAppMessageString)?.let { inAppMessage -> + val activity = cordova.activity + if (activity == null || inAppMessage !is InAppMessageBase) return@runOnBraze + + var button: MessageButton? = null + if (buttonId >= 0 && inAppMessage is InAppMessageImmersiveBase) { + button = inAppMessage.messageButtons.firstOrNull { it.id == buttonId } + } + val clickAction = if (buttonId < 0) { + inAppMessage.clickAction + } else { + button?.clickAction + } + val clickUri = if (buttonId < 0) { + inAppMessage.uri + } else { + button?.uri + } + val openUriInWebView = if (buttonId < 0) { + inAppMessage.openUriInWebView + } else { + button?.openUriInWebview ?: false + } + brazelog { "got action: $clickUri, $openUriInWebView, $clickAction" } + when (clickAction) { + ClickAction.NEWS_FEED -> { + val newsfeedAction = NewsfeedAction( + inAppMessage.extras.toBundle(), + Channel.INAPP_MESSAGE + ) + BrazeDeeplinkHandler.getInstance() + .gotoNewsFeed(activity, newsfeedAction) + } + + ClickAction.URI -> { + if (clickUri != null) { + val uriAction = + BrazeDeeplinkHandler.getInstance().createUriActionFromUri( + clickUri, inAppMessage.extras.toBundle(), + openUriInWebView, Channel.INAPP_MESSAGE + ) + brazelog { "Performing gotoUri $clickUri $openUriInWebView" } + BrazeDeeplinkHandler.getInstance() + .gotoUri(applicationContext, uriAction) + } + } + + else -> { + brazelog { "Unhandled action $clickAction" } + } + } + } + } + return true + } "getFeatureFlag" -> { runOnBraze { val result = it.getFeatureFlag(args.getString(0)) @@ -557,7 +680,7 @@ open class BrazePlugin : CordovaPlugin() { if (notificationChannelDescription.isNotBlank()) { configBuilder.setDefaultNotificationChannelDescription(notificationChannelDescription) } else { - brazelog (W) { "Invalid default notification channel description. Default notification description not set." } + brazelog (W) { "Invalid default notification channel description. Default notification description not set." } } } @@ -812,6 +935,28 @@ open class BrazePlugin : CordovaPlugin() { return true } + private fun setDefaultInAppMessageListener() { + BrazeInAppMessageManager.getInstance().setCustomInAppMessageManagerListener( + object : DefaultInAppMessageManagerListener() { + override fun beforeInAppMessageDisplayed(inAppMessage: IInAppMessage): InAppMessageOperation { + super.beforeInAppMessageDisplayed(inAppMessage) + + // Convert in-app message to string + val inAppMessageString = inAppMessage.forJsonPut().toString() + brazelog { "In-app message received: $inAppMessageString" } + + // Send in-app message string back to JavaScript in an `inAppMessageReceived` event + val jsStatement = "app.inAppMessageReceived('$inAppMessageString');" + cordova.activity.runOnUiThread { + webView.engine.evaluateJavascript(jsStatement, null) + } + + return inAppMessageDisplayOperation + } + } + ) + } + companion object { // Preference keys found in the config.xml private const val BRAZE_API_KEY_PREFERENCE = "com.braze.api_key" diff --git a/src/android/build-extras.gradle b/src/android/build-extras.gradle index 6920a09..2792fb7 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.1.1' + implementation 'com.braze:android-sdk-ui:30.3.0' implementation 'com.google.firebase:firebase-messaging:23.0.0' } diff --git a/src/ios/BrazePlugin.h b/src/ios/BrazePlugin.h index b2ec688..2a918d7 100644 --- a/src/ios/BrazePlugin.h +++ b/src/ios/BrazePlugin.h @@ -17,6 +17,8 @@ - (void)changeUser:(CDVInvokedUrlCommand *)command; - (void)setSdkAuthenticationSignature:(CDVInvokedUrlCommand *)command; - (void)subscribeToSdkAuthenticationFailures:(CDVInvokedUrlCommand *)command; +- (void)subscribeToInAppMessage:(CDVInvokedUrlCommand *)command; +- (void)hideCurrentInAppMessage:(CDVInvokedUrlCommand *)command; - (void)logCustomEvent:(CDVInvokedUrlCommand *)command; - (void)logPurchase:(CDVInvokedUrlCommand *)command; - (void)disableSdk:(CDVInvokedUrlCommand *)command; @@ -24,6 +26,8 @@ - (void)wipeData:(CDVInvokedUrlCommand *)command; - (void)requestImmediateDataFlush:(CDVInvokedUrlCommand *)command; - (void)getDeviceId:(CDVInvokedUrlCommand *)command; +- (void)updateTrackingPropertyAllowList:(CDVInvokedUrlCommand *)command; +- (void)setAdTrackingEnabled:(CDVInvokedUrlCommand *)command; /*-------Braze.User-------*/ - (void)setFirstName:(CDVInvokedUrlCommand *)command; diff --git a/src/ios/BrazePlugin.m b/src/ios/BrazePlugin.m index 8fc92ea..30b2395 100644 --- a/src/ios/BrazePlugin.m +++ b/src/ios/BrazePlugin.m @@ -6,7 +6,7 @@ @import BrazeUI; @import UserNotifications; -@interface BrazePlugin() +@interface BrazePlugin() @property NSString *APIKey; @property NSString *disableAutomaticPushRegistration; @property NSString *disableAutomaticPushHandling; @@ -32,6 +32,8 @@ @interface BrazePlugin() @implementation BrazePlugin +bool isInAppMessageSubscribed; + + (Braze *)braze { return _braze; } @@ -60,6 +62,7 @@ - (void)pluginInitialize { self.flushInterval = settings[@"com.braze.ios_flush_interval_seconds"]; self.useAutomaticRequestPolicy = settings[@"com.braze.ios_use_automatic_request_policy"]; self.optInWhenPushAuthorized = settings[@"com.braze.should_opt_in_when_push_authorized"]; + isInAppMessageSubscribed = NO; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didFinishLaunchingListener:) name:UIApplicationDidFinishLaunchingNotification object:nil]; @@ -177,11 +180,15 @@ - (void)didFinishLaunchingListener:(NSNotification *)notification { // Initialize Braze with set configurations self.braze = [[Braze alloc] initWithConfiguration:configuration]; - self.braze.inAppMessagePresenter = [[BrazeInAppMessageUI alloc] init]; self.subscriptions = [NSMutableArray array]; [BrazePlugin setBraze:self.braze]; NSLog(@"Braze initialized with set configurations."); + // In-App Message UI + BrazeInAppMessageUI *inAppMessageUI = [[BrazeInAppMessageUI alloc] init]; + inAppMessageUI.delegate = self; + self.braze.inAppMessagePresenter = inAppMessageUI; + // Set the IDFA delegate for the plugin if ([[self sanitizeString:self.enableIDFACollection] isEqualToString:@"yes"]) { NSLog(@"IDFA collection enabled. Setting values for ad tracking."); @@ -558,6 +565,72 @@ - (void)getDeviceId:(CDVInvokedUrlCommand *)command { [self sendCordovaSuccessPluginResultWithString:deviceId andCommand:command]; } +- (void)updateTrackingPropertyAllowList:(CDVInvokedUrlCommand *)command { + NSDictionary* allowList = [command argumentAtIndex:0]; + NSArray *adding = allowList[@"adding"]; + NSArray *removing = allowList[@"removing"]; + NSArray *addingCustomEvents = allowList[@"addingCustomEvents"]; + NSArray *removingCustomEvents = allowList[@"removingCustomEvents"]; + NSArray *addingCustomAttributes = allowList[@"addingCustomAttributes"]; + NSArray *removingCustomAttributes = allowList[@"removingCustomAttributes"]; + + NSMutableSet *addingSet = [NSMutableSet set]; + NSMutableSet *removingSet = [NSMutableSet set]; + + for (NSString *propertyString in adding) { + [addingSet addObject:[self convertTrackingProperty:(propertyString)]]; + } + + for (NSString *propertyString in removing) { + [removingSet addObject:[self convertTrackingProperty:(propertyString)]]; + } + + // Parse custom strings + if (addingCustomEvents.count > 0) { + NSSet *customEvents = [NSSet setWithArray:addingCustomEvents]; + [addingSet addObject:[BRZTrackingProperty customEventWithEvents:customEvents]]; + } + if (removingCustomEvents.count > 0) { + NSSet *customEvents = [NSSet setWithArray:removingCustomEvents]; + [removingSet addObject:[BRZTrackingProperty customAttributeWithAttributes:customEvents]]; + } + if (addingCustomAttributes.count > 0) { + NSSet *customAttributes = [NSSet setWithArray:addingCustomAttributes]; + [addingSet addObject:[BRZTrackingProperty customAttributeWithAttributes:customAttributes]]; + } + if (removingCustomAttributes.count > 0) { + NSSet *customAttributes = [NSSet setWithArray:removingCustomAttributes]; + [removingSet addObject:[BRZTrackingProperty customAttributeWithAttributes:customAttributes]]; + } + + NSLog(@"Updating tracking allow list by adding: %@, removing %@", addingSet, removingSet); + [self.braze updateTrackingAllowListAdding:addingSet removing:removingSet]; +} + +- (void)setAdTrackingEnabled:(CDVInvokedUrlCommand *)command { + id argument = [command argumentAtIndex:0 withDefault:nil]; + + if (argument == nil) { + NSLog(@"Error: No argument provided for setAdTrackingEnabled."); + return; + } + + if (![argument isKindOfClass:[NSNumber class]]) { + NSLog(@"Error: Expected argument to be a boolean value for setAdTrackingEnabled."); + return; + } + + BOOL adTrackingEnabled = [argument boolValue]; + + if (adTrackingEnabled) { + [self.braze setAdTrackingEnabled:YES]; + NSLog(@"Ad tracking enabled."); + } else { + [self.braze setAdTrackingEnabled:NO]; + NSLog(@"Ad tracking disabled."); + } +} + // MARK: - BrazeUI - (void)launchNewsFeed:(CDVInvokedUrlCommand *)command { NSLog(@"News Feed UI not supported on iOS."); @@ -812,6 +885,104 @@ + (NSString *)getJsonFromExtras:(NSDictionary *)extras { } } +// MARK: - In-App Messages + +/// 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; + } + isInAppMessageSubscribed = YES; +} + +/// Hides the currently displayed in-app message. +- (void)hideCurrentInAppMessage:(CDVInvokedUrlCommand *)command { + [(BrazeInAppMessageUI *)self.braze.inAppMessagePresenter dismiss]; +} + +/// Logs an in-app message impression. +- (void)logInAppMessageImpression:(CDVInvokedUrlCommand *)command { + NSString *inAppMessageString = [command argumentAtIndex:0 withDefault:nil]; + NSLog(@"logInAppMessageImpression called with value %@", inAppMessageString); + BRZInAppMessageRaw *inAppMessage = [self getInAppMessageFromString:inAppMessageString]; + if (inAppMessage) { + [inAppMessage logImpressionUsing:self.braze]; + } else { + NSLog(@"logInAppMessageImpression could not parse inAppMessage. Not logging impression."); + } +} + +/// Logs when an in-app message was clicked. +- (void)logInAppMessageClicked:(CDVInvokedUrlCommand *)command { + NSString *inAppMessageString = [command argumentAtIndex:0 withDefault:nil]; + NSLog(@"logInAppMessageClicked called with value %@", inAppMessageString); + BRZInAppMessageRaw *inAppMessage = [self getInAppMessageFromString:inAppMessageString]; + if (inAppMessage) { + [inAppMessage logClickWithButtonId:nil using:self.braze]; + } else { + NSLog(@"logInAppMessageClicked could not parse inAppMessage. Not logging click."); + } +} + +/// Logs when an in-app message button was clicked. +- (void)logInAppMessageButtonClicked:(CDVInvokedUrlCommand *)command { + NSString *inAppMessageString = [command argumentAtIndex:0 withDefault:nil]; + NSNumber *button = [command argumentAtIndex:1 withDefault:0]; + NSLog(@"logInAppMessageButtonClicked called with value %@, button: %@", inAppMessageString, button); + BRZInAppMessageRaw *inAppMessage = [self getInAppMessageFromString:inAppMessageString]; + double buttonId = [button doubleValue]; + if (inAppMessage) { + [inAppMessage logClickWithButtonId:[@(buttonId) stringValue] using:self.braze]; + } else { + NSLog(@"logInAppMessageButtonClicked could not parse inAppMessage. Not logging button click."); + } +} + +/// Process and perform in-app message click actions. +- (void)performInAppMessageAction:(CDVInvokedUrlCommand *)command { + NSString *inAppMessageString = [command argumentAtIndex:0 withDefault:nil]; + NSNumber *button = [command argumentAtIndex:1 withDefault:0]; + NSLog(@"performInAppMessageAction called with value %@, and button %@", inAppMessageString, button); + BRZInAppMessageRaw *inAppMessage = [self getInAppMessageFromString:inAppMessageString]; + + double buttonId = [button doubleValue]; + + if (inAppMessage) { + NSURL* url = nil; + BOOL useWebView = NO; + BRZInAppMessageRawClickAction clickAction = BRZInAppMessageRawClickActionURL; + + if (buttonId < 0) { + url = inAppMessage.url; + useWebView = inAppMessage.useWebView; + clickAction = inAppMessage.clickAction; + } else { + for(int i = 0; i < inAppMessage.buttons.count; i++) { + if (inAppMessage.buttons[i].identifier == buttonId) { + url = inAppMessage.buttons[i].url; + useWebView = inAppMessage.buttons[i].useWebView; + clickAction = inAppMessage.buttons[i].clickAction; + } + } + } + + NSLog(@"performInAppMessageAction trying %@", inAppMessage.url); + inAppMessage.context = [[BRZInAppMessageContext alloc] initWithMessageRaw:inAppMessage using:self.braze]; + [inAppMessage.context processClickAction:clickAction url:url useWebView:useWebView]; + } else { + NSLog(@"performInAppMessageAction could not parse inAppMessage. Not performing action."); + } +} + +/// Returns the in-app message for the JSON string. If the JSON fails decoding, returns nil. +- (BRZInAppMessageRaw *)getInAppMessageFromString:(NSString *)inAppMessageJSONString { + NSData *inAppMessageData = [inAppMessageJSONString dataUsingEncoding:NSUTF8StringEncoding]; + BRZInAppMessageRaw *message = [BRZInAppMessageRaw decodingWithJson:inAppMessageData]; + return message; +} + // MARK: - Feature Flags - (void)getFeatureFlag:(CDVInvokedUrlCommand *)command { NSString *featureFlagId = [command argumentAtIndex:0 withDefault:nil]; @@ -1004,4 +1175,65 @@ - (NSString *)sanitizeString:(NSString *)inputString { return ([trimmedString lowercaseString]); } +- (BRZTrackingProperty *)convertTrackingProperty:(NSString *)propertyString { + if ([propertyString isEqualToString:@"all_custom_attributes"]) { + return BRZTrackingProperty.allCustomAttributes; + } else if ([propertyString isEqualToString:@"all_custom_events"]) { + return BRZTrackingProperty.allCustomEvents; + } else if ([propertyString isEqualToString:@"analytics_events"]) { + return BRZTrackingProperty.analyticsEvents; + } else if ([propertyString isEqualToString:@"attribution_data"]) { + return BRZTrackingProperty.attributionData; + } else if ([propertyString isEqualToString:@"country"]) { + return BRZTrackingProperty.country; + } else if ([propertyString isEqualToString:@"dob"]) { + return BRZTrackingProperty.dateOfBirth; + } else if ([propertyString isEqualToString:@"device_data"]) { + return BRZTrackingProperty.deviceData; + } else if ([propertyString isEqualToString:@"email"]) { + return BRZTrackingProperty.email; + } else if ([propertyString isEqualToString:@"email_subscription_state"]) { + return BRZTrackingProperty.emailSubscriptionState; + } else if ([propertyString isEqualToString:@"everything"]) { + return BRZTrackingProperty.everything; + } else if ([propertyString isEqualToString:@"first_name"]) { + return BRZTrackingProperty.firstName; + } else if ([propertyString isEqualToString:@"gender"]) { + return BRZTrackingProperty.gender; + } else if ([propertyString isEqualToString:@"home_city"]) { + return BRZTrackingProperty.homeCity; + } else if ([propertyString isEqualToString:@"language"]) { + return BRZTrackingProperty.language; + } else if ([propertyString isEqualToString:@"last_name"]) { + return BRZTrackingProperty.lastName; + } else if ([propertyString isEqualToString:@"notification_subscription_state"]) { + return BRZTrackingProperty.notificationSubscriptionState; + } else if ([propertyString isEqualToString:@"phone_number"]) { + return BRZTrackingProperty.phoneNumber; + } else if ([propertyString isEqualToString:@"push_token"]) { + return BRZTrackingProperty.pushToken; + } else { + NSLog(@"Invalid tracking property: %@", propertyString); + return nil; + } +} + +// MARK: - BrazeInAppMessageUIDelegate + +- (void)inAppMessage:(BrazeInAppMessageUI *)ui + didPresent:(BRZInAppMessageRaw *)message + view:(UIView *)view { + if (!isInAppMessageSubscribed) { + return; + } + // Convert in-app message to string + NSData *inAppMessageData = [message json]; + NSString *inAppMessageString = [[NSString alloc] initWithData:inAppMessageData encoding:NSUTF8StringEncoding]; + 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]; +} + @end diff --git a/www/BrazePlugin.js b/www/BrazePlugin.js index d2da64d..1076a68 100644 --- a/www/BrazePlugin.js +++ b/www/BrazePlugin.js @@ -37,7 +37,7 @@ var BrazePlugin = function () { * @param {string} sdkAuthenticationToken - A JWT token used for SDK Authentication. */ BrazePlugin.prototype.changeUser = function (userId, sdkAuthenticationToken) { - cordova.exec(null, null, "BrazePlugin", "changeUser", [userId, sdkAuthenticationToken]); + cordova.exec(null, null, "BrazePlugin", "changeUser", [userId, sdkAuthenticationToken]); } /** @@ -48,7 +48,7 @@ BrazePlugin.prototype.changeUser = function (userId, sdkAuthenticationToken) { * @param {string} pushToken - The registration ID / push token. */ BrazePlugin.prototype.setRegisteredPushToken = function (pushToken) { - cordova.exec(null, null, "BrazePlugin", "setRegisteredPushToken", [pushToken]); + cordova.exec(null, null, "BrazePlugin", "setRegisteredPushToken", [pushToken]); } /** @@ -57,7 +57,57 @@ BrazePlugin.prototype.setRegisteredPushToken = function (pushToken) { * Requests the push permission prompt to be shown to the user. */ BrazePlugin.prototype.requestPushPermission = function () { - cordova.exec(null, null, "BrazePlugin", "requestPushPermission"); + cordova.exec(null, null, "BrazePlugin", "requestPushPermission"); +} + +/** + * Updates the list of data types you wish to declare or remove as tracked user data. + * + * For more details, refer to Braze's [Privacy Manifest documentation] + * (https://www.braze.com/docs/developer_guide/platform_integration_guides/swift/privacy_manifest/). + * + * No-op on Android. + * + * @param {TrackingPropertyAllowList} allowList - The list of tracking properties to update. + * + */ +BrazePlugin.prototype.updateTrackingPropertyAllowList = async function (allowList) { + if (allowList.adding && !isValidTrackingPropertyArray(allowList.adding)) { + console.log("'adding' property must be an array of strings. Setting array to empty."); + allowList.adding = []; + } + if (allowList.removing && !isValidTrackingPropertyArray(allowList.removing)) { + console.log("'removing' property must be an array of strings. Setting array to empty."); + allowList.removing = []; + } + if (allowList.addingCustomEvents && !isValidTrackingPropertyArray(allowList.addingCustomEvents)) { + console.log("'addingCustomEvents' property must be an array of strings. Setting array to empty."); + allowList.addingCustomEvents = []; + } + if (allowList.removingCustomEvents && !isValidTrackingPropertyArray(allowList.removingCustomEvents)) { + console.log("'removingCustomEvents' property must be an array of strings. Setting array to empty."); + allowList.removingCustomEvents = []; + } + if (allowList.addingCustomAttributes && !isValidTrackingPropertyArray(allowList.addingCustomAttributes)) { + console.log("'addingCustomAttributes' property must be an array of strings. Setting array to empty."); + allowList.addingCustomAttributes = []; + } + if (allowList.removingCustomAttributes && !isValidTrackingPropertyArray(allowList.removingCustomAttributes)) { + console.log("'removingCustomAttributes' property must be an array of strings. Setting array to empty."); + allowList.removingCustomAttributes = []; + } + cordova.exec(null, null, "BrazePlugin", "updateTrackingPropertyAllowList", [allowList]); +} + +/** + * Informs Braze whether ad-tracking has been enabled for this device. + * Note that the SDK does not automatically collect this data. + * + * @param {string} adTrackingEnabled - Whether ad-tracking is enabled. + * @param {string} googleAdvertisingId - The Google Advertising ID. (Android only) + */ +BrazePlugin.prototype.setAdTrackingEnabled = function (adTrackingEnabled, googleAdvertisingId) { + cordova.exec(null, null, "BrazePlugin", "setAdTrackingEnabled", [adTrackingEnabled, googleAdvertisingId]); } /** @@ -71,7 +121,7 @@ BrazePlugin.prototype.requestPushPermission = function () { * Values can be numeric, boolean, or strings 255 characters or shorter. */ BrazePlugin.prototype.logCustomEvent = function (eventName, eventProperties) { - cordova.exec(null, null, "BrazePlugin", "logCustomEvent", [eventName, eventProperties]); + cordova.exec(null, null, "BrazePlugin", "logCustomEvent", [eventName, eventProperties]); } /** @@ -99,14 +149,14 @@ BrazePlugin.prototype.logCustomEvent = function (eventName, eventProperties) { * Values can be numeric, boolean, or strings 255 characters or shorter. */ BrazePlugin.prototype.logPurchase = function (productId, price, currencyCode, quantity, purchaseProperties) { - cordova.exec(null, null, "BrazePlugin", "logPurchase", [productId, price, currencyCode, quantity, purchaseProperties]); + cordova.exec(null, null, "BrazePlugin", "logPurchase", [productId, price, currencyCode, quantity, purchaseProperties]); } /** * Sets the attribution information for the user. For in apps that have an install tracking integration. */ BrazePlugin.prototype.setUserAttributionData = function (network, campaign, adgroup, creative) { - cordova.exec(null, null, "BrazePlugin", "setUserAttributionData", [network, campaign, adgroup, creative]); + cordova.exec(null, null, "BrazePlugin", "setUserAttributionData", [network, campaign, adgroup, creative]); } /** @@ -119,30 +169,30 @@ BrazePlugin.prototype.setUserAttributionData = function (network, campaign, adgr * Passing a null value will remove this custom attribute from the user. */ BrazePlugin.prototype.setCustomUserAttribute = function (key, value, merge = false) { - var valueType = typeof(value); - if (value instanceof Date) { - cordova.exec(null, null, "BrazePlugin", "setDateCustomUserAttribute", [key, Math.floor(value.getTime() / 1000)]); - } else if (value instanceof Array) { - if (value.every(item => typeof(item) === "string")) { - cordova.exec(null, null, "BrazePlugin", "setCustomUserAttributeArray", [key, value]); - } else if (value.every(item => item instanceof Object)) { - cordova.exec(null, null, "BrazePlugin", "setCustomUserAttributeObjectArray", [key, value]); - } else { - console.log(`User attribute ${value} was not a valid array. Custom attribute arrays can only contain all strings or all objects.`); - } - } else if (value instanceof Object) { - cordova.exec(null, null, "BrazePlugin", "setCustomUserAttributeObject", [key, value, merge]); - } else if (valueType === "boolean") { - cordova.exec(null, null, "BrazePlugin", "setBoolCustomUserAttribute", [key, value]); - } else if (valueType === "string") { - cordova.exec(null, null, "BrazePlugin", "setStringCustomUserAttribute", [key, value]); - } else if (valueType === "number") { - if (parseInt(value) === parseFloat(value)) { - cordova.exec(null, null, "BrazePlugin", "setIntCustomUserAttribute", [key, value]); - } else { - cordova.exec(null, null, "BrazePlugin", "setDoubleCustomUserAttribute", [key, value]); - } - } + var valueType = typeof (value); + if (value instanceof Date) { + cordova.exec(null, null, "BrazePlugin", "setDateCustomUserAttribute", [key, Math.floor(value.getTime() / 1000)]); + } else if (value instanceof Array) { + if (value.every(item => typeof (item) === "string")) { + cordova.exec(null, null, "BrazePlugin", "setCustomUserAttributeArray", [key, value]); + } else if (value.every(item => item instanceof Object)) { + cordova.exec(null, null, "BrazePlugin", "setCustomUserAttributeObjectArray", [key, value]); + } else { + console.log(`User attribute ${value} was not a valid array. Custom attribute arrays can only contain all strings or all objects.`); + } + } else if (value instanceof Object) { + cordova.exec(null, null, "BrazePlugin", "setCustomUserAttributeObject", [key, value, merge]); + } else if (valueType === "boolean") { + cordova.exec(null, null, "BrazePlugin", "setBoolCustomUserAttribute", [key, value]); + } else if (valueType === "string") { + cordova.exec(null, null, "BrazePlugin", "setStringCustomUserAttribute", [key, value]); + } else if (valueType === "number") { + if (parseInt(value) === parseFloat(value)) { + cordova.exec(null, null, "BrazePlugin", "setIntCustomUserAttribute", [key, value]); + } else { + cordova.exec(null, null, "BrazePlugin", "setDoubleCustomUserAttribute", [key, value]); + } + } } /** @@ -155,7 +205,7 @@ BrazePlugin.prototype.setCustomUserAttribute = function (key, value, merge = fal * @param {integer} - May be negative to decrement. */ BrazePlugin.prototype.incrementCustomUserAttribute = function (key, value) { - cordova.exec(null, null, "BrazePlugin", "incrementCustomUserAttribute", [key, value]); + cordova.exec(null, null, "BrazePlugin", "incrementCustomUserAttribute", [key, value]); } /** @@ -163,7 +213,7 @@ BrazePlugin.prototype.incrementCustomUserAttribute = function (key, value) { * @param {string} firstName - Limited to 255 characters in length. */ BrazePlugin.prototype.setFirstName = function (firstName) { - cordova.exec(null, null, "BrazePlugin", "setFirstName", [firstName]); + cordova.exec(null, null, "BrazePlugin", "setFirstName", [firstName]); } /** @@ -171,7 +221,7 @@ BrazePlugin.prototype.setFirstName = function (firstName) { * @param {string} lastName - Limited to 255 characters in length. */ BrazePlugin.prototype.setLastName = function (lastName) { - cordova.exec(null, null, "BrazePlugin", "setLastName", [lastName]); + cordova.exec(null, null, "BrazePlugin", "setLastName", [lastName]); } /** @@ -179,7 +229,7 @@ BrazePlugin.prototype.setLastName = function (lastName) { * @param {string} email - Must pass RFC-5322 email address validation. */ BrazePlugin.prototype.setEmail = function (email) { - cordova.exec(null, null, "BrazePlugin", "setEmail", [email]); + cordova.exec(null, null, "BrazePlugin", "setEmail", [email]); } /** @@ -187,7 +237,7 @@ BrazePlugin.prototype.setEmail = function (email) { * @param {ab.User.Genders} gender - Generally 'm' or 'f'. */ BrazePlugin.prototype.setGender = function (gender) { - cordova.exec(null, null, "BrazePlugin", "setGender", [gender]); + cordova.exec(null, null, "BrazePlugin", "setGender", [gender]); } /** @@ -195,7 +245,7 @@ BrazePlugin.prototype.setGender = function (gender) { * @param {string} country - Limited to 255 characters in length. */ BrazePlugin.prototype.setCountry = function (country) { - cordova.exec(null, null, "BrazePlugin", "setCountry", [country]); + cordova.exec(null, null, "BrazePlugin", "setCountry", [country]); } /** @@ -203,7 +253,7 @@ BrazePlugin.prototype.setCountry = function (country) { * @param {string} homeCity - Limited to 255 characters in length. */ BrazePlugin.prototype.setHomeCity = function (homeCity) { - cordova.exec(null, null, "BrazePlugin", "setHomeCity", [homeCity]); + cordova.exec(null, null, "BrazePlugin", "setHomeCity", [homeCity]); } /** @@ -212,7 +262,7 @@ BrazePlugin.prototype.setHomeCity = function (homeCity) { * contains only numbers, whitespace, and the following special characters +.-() */ BrazePlugin.prototype.setPhoneNumber = function (phoneNumber) { - cordova.exec(null, null, "BrazePlugin", "setPhoneNumber", [phoneNumber]); + cordova.exec(null, null, "BrazePlugin", "setPhoneNumber", [phoneNumber]); } /** @@ -222,7 +272,7 @@ BrazePlugin.prototype.setPhoneNumber = function (phoneNumber) { * @param {integer} day */ BrazePlugin.prototype.setDateOfBirth = function (year, month, day) { - cordova.exec(null, null, "BrazePlugin", "setDateOfBirth", [year, month, day]); + cordova.exec(null, null, "BrazePlugin", "setDateOfBirth", [year, month, day]); } /** @@ -234,7 +284,7 @@ BrazePlugin.prototype.setDateOfBirth = function (year, month, day) { * @param {double} verticalAccuracy (optional) */ BrazePlugin.prototype.setLastKnownLocation = function (latitude, longitude, altitude, horizontalAccuracy, verticalAccuracy) { - cordova.exec(null, null, "BrazePlugin", "setLastKnownLocation", [latitude, longitude, altitude, horizontalAccuracy, verticalAccuracy]); + cordova.exec(null, null, "BrazePlugin", "setLastKnownLocation", [latitude, longitude, altitude, horizontalAccuracy, verticalAccuracy]); } /** @@ -243,7 +293,7 @@ BrazePlugin.prototype.setLastKnownLocation = function (latitude, longitude, alti * opted-in, subscribed, or unsubscribed). */ BrazePlugin.prototype.setPushNotificationSubscriptionType = function (notificationSubscriptionType) { - cordova.exec(null, null, "BrazePlugin", "setPushNotificationSubscriptionType", [notificationSubscriptionType]); + cordova.exec(null, null, "BrazePlugin", "setPushNotificationSubscriptionType", [notificationSubscriptionType]); } /** @@ -252,7 +302,7 @@ BrazePlugin.prototype.setPushNotificationSubscriptionType = function (notificati * opted-in, subscribed, or unsubscribed). */ BrazePlugin.prototype.setEmailNotificationSubscriptionType = function (notificationSubscriptionType) { - cordova.exec(null, null, "BrazePlugin", "setEmailNotificationSubscriptionType", [notificationSubscriptionType]); + cordova.exec(null, null, "BrazePlugin", "setEmailNotificationSubscriptionType", [notificationSubscriptionType]); } /** @@ -263,7 +313,7 @@ BrazePlugin.prototype.setEmailNotificationSubscriptionType = function (notificat * begin with a $, and can only contain alphanumeric characters and punctuation. */ BrazePlugin.prototype.addToCustomUserAttributeArray = function (key, value) { - cordova.exec(null, null, "BrazePlugin", "addToCustomAttributeArray", [key, value]); + cordova.exec(null, null, "BrazePlugin", "addToCustomAttributeArray", [key, value]); } /** @@ -274,7 +324,7 @@ BrazePlugin.prototype.addToCustomUserAttributeArray = function (key, value) { * cannot beging with a $, and can only contain alphanumeric characters and punctuation. */ BrazePlugin.prototype.removeFromCustomUserAttributeArray = function (key, value) { - cordova.exec(null, null, "BrazePlugin", "removeFromCustomAttributeArray", [key, value]); + cordova.exec(null, null, "BrazePlugin", "removeFromCustomAttributeArray", [key, value]); } /** @@ -283,7 +333,7 @@ BrazePlugin.prototype.removeFromCustomUserAttributeArray = function (key, value) * a $, and can only contain alphanumeric characters and punctuation. */ BrazePlugin.prototype.unsetCustomUserAttribute = function (key) { - cordova.exec(null, null, "BrazePlugin", "unsetCustomUserAttribute", [key]); + cordova.exec(null, null, "BrazePlugin", "unsetCustomUserAttribute", [key]); } /** @@ -292,7 +342,7 @@ BrazePlugin.prototype.unsetCustomUserAttribute = function (key) { * @param {string} label - A label for the alias. e.g. the source of the alias, like "internal_id" */ BrazePlugin.prototype.addAlias = function (alias, label) { - cordova.exec(null, null, "BrazePlugin", "addAlias", [alias, label]); + cordova.exec(null, null, "BrazePlugin", "addAlias", [alias, label]); } // Other @@ -300,14 +350,14 @@ BrazePlugin.prototype.addAlias = function (alias, label) { * Launches the News Feed UI element. */ BrazePlugin.prototype.launchNewsFeed = function () { - cordova.exec(null, null, "BrazePlugin", "launchNewsFeed", []); + cordova.exec(null, null, "BrazePlugin", "launchNewsFeed", []); } /** * Returns array of serialized card items */ BrazePlugin.prototype.getNewsFeed = function (successCallback, errorCallback) { - cordova.exec(successCallback, errorCallback, "BrazePlugin", "getNewsFeed", ['all']); + cordova.exec(successCallback, errorCallback, "BrazePlugin", "getNewsFeed", ['all']); } // News Feed methods @@ -316,35 +366,35 @@ BrazePlugin.prototype.getNewsFeed = function (successCallback, errorCallback) { * 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']); + 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. **/ BrazePlugin.prototype.getNewsFeedCardCount = function (successCallback, errorCallback) { - cordova.exec(successCallback, errorCallback, "BrazePlugin", "getCardCountForCategories", ['all']); + 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. **/ BrazePlugin.prototype.getCardCountForCategories = function (successCallback, errorCallback, cardCategories) { - cordova.exec(successCallback, errorCallback, "BrazePlugin", "getCardCountForCategories", 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. */ BrazePlugin.prototype.getUnreadCardCountForCategories = function (successCallback, errorCallback, cardCategories) { - cordova.exec(successCallback, errorCallback, "BrazePlugin", "getUnreadCardCountForCategories", 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. */ BrazePlugin.prototype.wipeData = function () { - cordova.exec(null, null, "BrazePlugin", "wipeData"); + cordova.exec(null, null, "BrazePlugin", "wipeData"); } /** @@ -352,98 +402,155 @@ BrazePlugin.prototype.wipeData = function () { * On iOS, the SDK will be enabled only after a subsequent call to startWithApiKey(). */ BrazePlugin.prototype.enableSdk = function () { - cordova.exec(null, null, "BrazePlugin", "enableSdk"); + cordova.exec(null, null, "BrazePlugin", "enableSdk"); } /** * Disables the Braze SDK immediately. */ BrazePlugin.prototype.disableSdk = function () { - cordova.exec(null, null, "BrazePlugin", "disableSdk"); + cordova.exec(null, null, "BrazePlugin", "disableSdk"); } /** * Requests that the Braze SDK immediately flush any pending data. */ BrazePlugin.prototype.requestImmediateDataFlush = function () { - cordova.exec(null, null, "BrazePlugin", "requestImmediateDataFlush"); + cordova.exec(null, null, "BrazePlugin", "requestImmediateDataFlush"); } /** * Requests the latest Content Cards from the Braze SDK server. */ BrazePlugin.prototype.requestContentCardsRefresh = function () { - cordova.exec(null, null, "BrazePlugin", "requestContentCardsRefresh"); + cordova.exec(null, null, "BrazePlugin", "requestContentCardsRefresh"); } /** * Retrieves Content Cards from the Braze SDK. This will return the latest list of cards from the server. */ BrazePlugin.prototype.getContentCardsFromServer = function (successCallback, errorCallback) { - cordova.exec(successCallback, errorCallback, "BrazePlugin", "getContentCardsFromServer"); + cordova.exec(successCallback, errorCallback, "BrazePlugin", "getContentCardsFromServer"); } /** * 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"); + cordova.exec(successCallback, errorCallback, "BrazePlugin", "getContentCardsFromCache"); } /** * Launches a default Content Cards UI element. */ BrazePlugin.prototype.launchContentCards = function () { - cordova.exec(null, null, "BrazePlugin", "launchContentCards"); + cordova.exec(null, null, "BrazePlugin", "launchContentCards"); } /** * Logs a click for the given Content Card id. */ BrazePlugin.prototype.logContentCardClicked = function (cardId) { - cordova.exec(null, null, "BrazePlugin", "logContentCardClicked", [cardId]); + cordova.exec(null, null, "BrazePlugin", "logContentCardClicked", [cardId]); } /** * Logs an impression for the given Content Card id. */ BrazePlugin.prototype.logContentCardImpression = function (cardId) { - cordova.exec(null, null, "BrazePlugin", "logContentCardImpression", [cardId]); + cordova.exec(null, null, "BrazePlugin", "logContentCardImpression", [cardId]); } /** * Logs a dismissal for the given Content Card id. */ BrazePlugin.prototype.logContentCardDismissed = function (cardId) { - cordova.exec(null, null, "BrazePlugin", "logContentCardDismissed", [cardId]); + cordova.exec(null, null, "BrazePlugin", "logContentCardDismissed", [cardId]); +} + +/** + * Subscribes to in app messages + * @param {boolean} useBrazeUI - Whether to use Braze's UI for in app messages + */ +BrazePlugin.prototype.subscribeToInAppMessage = function (successCallback, errorCallback, useBrazeUI = true) { + cordova.exec(successCallback, errorCallback, "BrazePlugin", "subscribeToInAppMessage", [useBrazeUI]); +} + +/** + * Hides the currently displayed in-app message. + */ +BrazePlugin.prototype.hideCurrentInAppMessage = function () { + cordova.exec(null, null, "BrazePlugin", "hideCurrentInAppMessage"); +} + +/** + * Logs an impression for the provided in-app message data. + * @param {BrazeInAppMessage} inAppMessage + */ +BrazePlugin.prototype.logInAppMessageImpression = function (inAppMessage) { + cordova.exec(null, null, "BrazePlugin", "logInAppMessageImpression", [inAppMessage]); +} + +/** + * Logs a click for the provided in-app message data. + * @param {BrazeInAppMessage} inAppMessage + */ +BrazePlugin.prototype.logInAppMessageClicked = function (inAppMessage) { + cordova.exec(null, null, "BrazePlugin", "logInAppMessageClicked", [inAppMessage]); +} + +/** + * Logs a button click for the provided in-app message button data. + * @param {BrazeInAppMessage} inAppMessage + * @param {integer} buttonId + */ +BrazePlugin.prototype.logInAppMessageButtonClicked = function (inAppMessage, buttonId) { + cordova.exec(null, null, "BrazePlugin", "logInAppMessageButtonClicked", [inAppMessage, buttonId]); +} + +/** + * Performs the action for an in-app message. + * @param {BrazeInAppMessage} inAppMessage + */ +BrazePlugin.prototype.performInAppMessageAction = function (inAppMessage) { + cordova.exec(null, null, "BrazePlugin", "performInAppMessageAction", [inAppMessage, -1]); +} + +/** + * Performs the action for an in-app message button. + * @param {BrazeInAppMessage} inAppMessage + * @param {integer} buttonId + */ +BrazePlugin.prototype.performInAppMessageButtonAction = function (inAppMessage, buttonId) { + cordova.exec(null, null, "BrazePlugin", "performInAppMessageAction", [inAppMessage, buttonId]); } /** * Sets the language for a user. Language Strings should be valid ISO 639-1 language codes. See loc.gov/standards/iso639-2/php/code_list.php. */ BrazePlugin.prototype.setLanguage = function (language) { - cordova.exec(null, null, "BrazePlugin", "setLanguage", [language]); + cordova.exec(null, null, "BrazePlugin", "setLanguage", [language]); } /** * Adds user to given subscription group. */ BrazePlugin.prototype.addToSubscriptionGroup = function (groupId) { - cordova.exec(null, null, "BrazePlugin", "addToSubscriptionGroup", [groupId]); + cordova.exec(null, null, "BrazePlugin", "addToSubscriptionGroup", [groupId]); } /** * Removes user from given subscription group. */ BrazePlugin.prototype.removeFromSubscriptionGroup = function (groupId) { - cordova.exec(null, null, "BrazePlugin", "removeFromSubscriptionGroup", [groupId]); + cordova.exec(null, null, "BrazePlugin", "removeFromSubscriptionGroup", [groupId]); } /** * @return An app specific ID that is stored on the device. */ BrazePlugin.prototype.getDeviceId = function (successCallback, errorCallback) { - cordova.exec(successCallback, errorCallback, "BrazePlugin", "getDeviceId"); + cordova.exec(successCallback, errorCallback, "BrazePlugin", "getDeviceId"); } /** @@ -454,13 +561,13 @@ BrazePlugin.prototype.getDeviceId = function (successCallback, errorCallback) { * @return A promise containing the [FeatureFlag] of the requested ID, or null if the Feature Flag does not exist. */ BrazePlugin.prototype.getFeatureFlag = function (id) { - return new Promise((resolve, reject) => { - cordova.exec((featureFlag) => { - resolve(featureFlag); - }, (error) => { - reject(error); - }, "BrazePlugin", "getFeatureFlag", [id]); - }); + return new Promise((resolve, reject) => { + cordova.exec((featureFlag) => { + resolve(featureFlag); + }, (error) => { + reject(error); + }, "BrazePlugin", "getFeatureFlag", [id]); + }); } /** @@ -471,27 +578,27 @@ BrazePlugin.prototype.getFeatureFlag = function (id) { * cached list of feature flags cannot be retrieved, returns empty list. */ BrazePlugin.prototype.getAllFeatureFlags = function () { - return new Promise((resolve, reject) => { - cordova.exec((featureFlags) => { - resolve(featureFlags); - }, (error) => { - reject(error); - }, "BrazePlugin", "getAllFeatureFlags"); - }); + return new Promise((resolve, reject) => { + cordova.exec((featureFlags) => { + resolve(featureFlags); + }, (error) => { + reject(error); + }, "BrazePlugin", "getAllFeatureFlags"); + }); } /** * Requests a refresh of Feature Flags from the Braze server. */ BrazePlugin.prototype.refreshFeatureFlags = function () { - cordova.exec(null, null, "BrazePlugin", "refreshFeatureFlags"); + cordova.exec(null, null, "BrazePlugin", "refreshFeatureFlags"); } /** * Subscribes to Feature Flags events. The subscriber callback will be called when Feature Flags are updated. */ BrazePlugin.prototype.subscribeToFeatureFlagsUpdates = function (flagId, propertyKey, successCallback, errorCallback) { - cordova.exec(successCallback, errorCallback, "BrazePlugin", "subscribeToFeatureFlagUpdates", [flagId, propertyKey]); + cordova.exec(successCallback, errorCallback, "BrazePlugin", "subscribeToFeatureFlagUpdates", [flagId, propertyKey]); } /** @@ -501,14 +608,14 @@ BrazePlugin.prototype.subscribeToFeatureFlagsUpdates = function (flagId, propert * * @return A promise containing the boolean property requested. This will return null if there is no such property or Feature Flag. */ -BrazePlugin.prototype.getFeatureFlagBooleanProperty = function(flagId, propertyKey) { - return new Promise((resolve, reject) => { - cordova.exec((property) => { - resolve(property); - }, (error) => { - reject(error); - }, "BrazePlugin", "getFeatureFlagBooleanProperty", [flagId, propertyKey]); - }) +BrazePlugin.prototype.getFeatureFlagBooleanProperty = function (flagId, propertyKey) { + return new Promise((resolve, reject) => { + cordova.exec((property) => { + resolve(property); + }, (error) => { + reject(error); + }, "BrazePlugin", "getFeatureFlagBooleanProperty", [flagId, propertyKey]); + }) } /** @@ -518,14 +625,14 @@ BrazePlugin.prototype.getFeatureFlagBooleanProperty = function(flagId, propertyK * * @return A promise containing the string property requested. This will return null if there is no such property or Feature Flag. */ -BrazePlugin.prototype.getFeatureFlagStringProperty = function(flagId, propertyKey) { - return new Promise((resolve, reject) => { - cordova.exec((stringProperty) => { - resolve(stringProperty); - }, (error) => { - reject(error); - }, "BrazePlugin", "getFeatureFlagStringProperty", [flagId, propertyKey]); - }) +BrazePlugin.prototype.getFeatureFlagStringProperty = function (flagId, propertyKey) { + return new Promise((resolve, reject) => { + cordova.exec((stringProperty) => { + resolve(stringProperty); + }, (error) => { + reject(error); + }, "BrazePlugin", "getFeatureFlagStringProperty", [flagId, propertyKey]); + }) } /** @@ -535,14 +642,14 @@ BrazePlugin.prototype.getFeatureFlagStringProperty = function(flagId, propertyKe * * @return A promise containing the number property requested. This will return null if there is no such property or Feature Flag. */ -BrazePlugin.prototype.getFeatureFlagNumberProperty = function(flagId, propertyKey) { - return new Promise((resolve, reject) => { - cordova.exec((numberProperty) => { - resolve(numberProperty); - }, (error) => { - reject(error); - }, "BrazePlugin", "getFeatureFlagNumberProperty", [flagId, propertyKey]); - }) +BrazePlugin.prototype.getFeatureFlagNumberProperty = function (flagId, propertyKey) { + return new Promise((resolve, reject) => { + cordova.exec((numberProperty) => { + resolve(numberProperty); + }, (error) => { + reject(error); + }, "BrazePlugin", "getFeatureFlagNumberProperty", [flagId, propertyKey]); + }) } /** @@ -551,45 +658,81 @@ BrazePlugin.prototype.getFeatureFlagNumberProperty = function(flagId, propertyKe * A feature flag impression can only be logged once per session for a given ID. * @param {string} flagId - The identifier for the Feature Flag. */ -BrazePlugin.prototype.logFeatureFlagImpression = function(flagId) { - cordova.exec(null, null, "BrazePlugin", "logFeatureFlagImpression", [flagId]); +BrazePlugin.prototype.logFeatureFlagImpression = function (flagId) { + cordova.exec(null, null, "BrazePlugin", "logFeatureFlagImpression", [flagId]); } /** * @return Starts SDK session tracking if previously disabled. Only used for Android. */ BrazePlugin.prototype.startSessionTracking = function () { - cordova.exec(null, null, "BrazePlugin", "startSessionTracking"); + cordova.exec(null, null, "BrazePlugin", "startSessionTracking"); } BrazePlugin.prototype['NotificationSubscriptionTypes'] = { - "OPTED_IN": 'opted_in', - "SUBSCRIBED": 'subscribed', - "UNSUBSCRIBED": 'unsubscribed' + "OPTED_IN": 'opted_in', + "SUBSCRIBED": 'subscribed', + "UNSUBSCRIBED": 'unsubscribed' }; BrazePlugin.prototype['Genders'] = { - "FEMALE": 'f', - "MALE": 'm', - "NOT_APPLICABLE": 'n', - "OTHER": 'o', - "PREFER_NOT_TO_SAY": 'p', - "UNKNOWN": 'u' + "FEMALE": 'f', + "MALE": 'm', + "NOT_APPLICABLE": 'n', + "OTHER": 'o', + "PREFER_NOT_TO_SAY": 'p', + "UNKNOWN": 'u' }; BrazePlugin.prototype['CardCategories'] = { - "ADVERTISING": 'advertising', - "ANNOUNCEMENTS": 'announcements', - "NEWS": 'news', - "SOCIAL": 'social', - "NO_CATEGORY": 'no_category', - "ALL" : 'all' + "ADVERTISING": 'advertising', + "ANNOUNCEMENTS": 'announcements', + "NEWS": 'news', + "SOCIAL": 'social', + "NO_CATEGORY": 'no_category', + "ALL": 'all' }; BrazePlugin.prototype['ContentCardTypes'] = { - 'CLASSIC': 'Classic', - 'IMAGE_ONLY': 'ImageOnly', - 'CAPTIONED': 'Captioned' + 'CLASSIC': 'Classic', + 'IMAGE_ONLY': 'ImageOnly', + 'CAPTIONED': 'Captioned' +}; + +BrazePlugin.prototype['TrackingProperty'] = { + 'ALL_CUSTOM_ATTRIBUTES': 'all_custom_attributes', + 'ALL_CUSTOM_EVENTS': 'all_custom_events', + 'ANALYTICS_EVENTS': 'analytics_events', + 'ATTRIBUTION_DATA': 'attribution_data', + 'COUNTRY': 'country', + 'DATE_OF_BIRTH': 'dob', + 'DEVICE_DATA': 'device_data', + 'EMAIL': 'email', + 'EMAIL_SUBSCRIPTION_STATE': 'email_subscription_state', + 'EVERYTHING': 'everything', + 'FIRST_NAME': 'first_name', + 'GENDER': 'gender', + 'HOME_CITY': 'home_city', + 'LANGUAGE': 'language', + 'LAST_NAME': 'last_name', + 'NOTIFICATION_SUBSCRIPTION_STATE': 'notification_subscription_state', + 'PHONE_NUMBER': 'phone_number', + 'PUSH_TOKEN': 'push_token' +}; + +BrazePlugin.prototype['TrackingPropertyAllowList'] = { + /* Tracking properties you wish to add to your allowlist */ + adding: [], + /* Tracking properties you wish to remove from your allowlist */ + removing: [], + /* Custom event strings you wish to add to your current allowlist. */ + addingCustomEvents: [], + /* Custom event strings you wish to remove from your current allowlist. */ + removingCustomEvents: [], + /* Custom attribute strings you wish to add to your current allowlist. */ + addingCustomAttributes: [], + /* Custom attribute strings you wish to remove from your current allowlist. */ + removingCustomAttributes: [] }; /** @@ -599,7 +742,7 @@ BrazePlugin.prototype['ContentCardTypes'] = { * @param {string} jwtToken - SDK Authentication JWT token. */ BrazePlugin.prototype.setSdkAuthenticationSignature = function (jwtToken) { - cordova.exec(null, null, "BrazePlugin", "setSdkAuthenticationSignature", [jwtToken]); + cordova.exec(null, null, "BrazePlugin", "setSdkAuthenticationSignature", [jwtToken]); } /** @@ -612,7 +755,19 @@ BrazePlugin.prototype.setSdkAuthenticationSignature = function (jwtToken) { * (string) "userId" */ BrazePlugin.prototype.subscribeToSdkAuthenticationFailures = function (successCallback, errorCallback) { - cordova.exec(successCallback, errorCallback, "BrazePlugin", "subscribeToSdkAuthenticationFailures"); + cordova.exec(successCallback, errorCallback, "BrazePlugin", "subscribeToSdkAuthenticationFailures"); +} + +// Helper Functions + +/** + * Validates an array to be processed in the `TrackingPropertyAllowList`. + * + * @param {array} array + * @returns Whether the array is valid according to the tracking property allow list. + */ +function isValidTrackingPropertyArray(array) { + return Array.isArray(array) && array.every(item => typeof item === 'string'); } var AppboyPlugin = BrazePlugin;