From 1d10e3aa13b33897b5fcf18aaaa30b14eaae203d Mon Sep 17 00:00:00 2001 From: wesleyorbin Date: Mon, 20 Jul 2020 18:17:36 -0400 Subject: [PATCH] Release version 1.21.0 --- AppboyProject/AppboyProject.js | 12 +- .../java/com/appboyproject/MainActivity.java | 54 +++++ .../AppboyProject.xcodeproj/project.pbxproj | 10 + AppboyProject/ios/AppboyProject/AppDelegate.h | 2 + AppboyProject/ios/AppboyProject/AppDelegate.m | 26 ++- AppboyProject/ios/Podfile | 2 +- AppboyProject/ios/Podfile.lock | 39 ++-- CHANGELOG.md | 18 ++ README.md | 29 ++- __tests__/index.test.js | 127 +++++++++++- android/build.gradle | 2 +- .../appboy/reactbridge/AppboyReactBridge.java | 33 ++++ .../AppboyReactBridge/AppboyReactBridge.m | 28 +++ index.d.ts | 81 +++++++- index.js | 187 ++++++++++++++++++ package.json | 2 +- react-native-appboy-sdk.podspec | 2 +- 17 files changed, 620 insertions(+), 34 deletions(-) diff --git a/AppboyProject/AppboyProject.js b/AppboyProject/AppboyProject.js index 2246050..88f5cc6 100644 --- a/AppboyProject/AppboyProject.js +++ b/AppboyProject/AppboyProject.js @@ -10,7 +10,8 @@ import { Linking, Alert, TextInput, - Platform + Platform, + DeviceEventEmitter } from 'react-native'; const ReactAppboy = require('react-native-appboy-sdk'); @@ -86,6 +87,15 @@ class AppboyProject extends Component { ReactAppboy.addListener(ReactAppboy.Events.CONTENT_CARDS_UPDATED, function() { console.log('Content Cards Updated.'); }) + + this._listener = DeviceEventEmitter.addListener("inAppMessageReceived", function(event) { + let inAppMessage = new ReactAppboy.BrazeInAppMessage(event.inAppMessage); + ReactAppboy.logInAppMessageClicked(inAppMessage); + ReactAppboy.logInAppMessageImpression(inAppMessage); + ReactAppboy.logInAppMessageButtonClicked(inAppMessage, 0); + that._showToast('inAppMessage received in the React layer'); + console.log(inAppMessage); + }) } componentWillUnmount() { diff --git a/AppboyProject/android/app/src/main/java/com/appboyproject/MainActivity.java b/AppboyProject/android/app/src/main/java/com/appboyproject/MainActivity.java index 6b45201..0494a85 100644 --- a/AppboyProject/android/app/src/main/java/com/appboyproject/MainActivity.java +++ b/AppboyProject/android/app/src/main/java/com/appboyproject/MainActivity.java @@ -1,13 +1,23 @@ package com.appboyproject; import com.appboy.Constants; +import com.appboy.models.IInAppMessage; +import com.appboy.models.MessageButton; +import com.appboy.ui.inappmessage.AppboyInAppMessageManager; +import com.appboy.ui.inappmessage.InAppMessageCloser; +import com.appboy.ui.inappmessage.InAppMessageOperation; +import com.appboy.ui.inappmessage.listeners.IInAppMessageManagerListener; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.util.Log; +import android.view.View; import android.widget.Toast; +import com.facebook.react.bridge.WritableMap; +import com.facebook.react.bridge.WritableNativeMap; +import com.facebook.react.modules.core.DeviceEventManagerModule; import com.facebook.react.ReactActivity; import com.facebook.react.ReactPackage; import com.facebook.react.shell.MainReactPackage; @@ -27,6 +37,50 @@ protected void onCreate(Bundle savedInstanceState) { Toast.makeText(this, "Activity opened by deep link: " + data.toString(), Toast.LENGTH_LONG); Log.i(TAG, "Deep link is " + data.toString()); } + class BrazeInAppMessageManagerListener implements IInAppMessageManagerListener { + @Override + public boolean onInAppMessageReceived(IInAppMessage inAppMessage) { + return false; + } + + @Override + public InAppMessageOperation beforeInAppMessageDisplayed(IInAppMessage inAppMessage) { + WritableMap parameters = new WritableNativeMap(); + parameters.putString("inAppMessage", inAppMessage.forJsonPut().toString()); + getReactNativeHost().getReactInstanceManager().getCurrentReactContext() + .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) + .emit("inAppMessageReceived", parameters); + // Note: return InAppMessageOperation.DISCARD if you would like + // to prevent the Braze SDK from displaying the message natively. + return InAppMessageOperation.DISPLAY_NOW; + } + + @Override + public boolean onInAppMessageClicked(IInAppMessage inAppMessage, InAppMessageCloser inAppMessageCloser) { + return false; + } + + @Override + public boolean onInAppMessageButtonClicked(IInAppMessage inAppMessage, MessageButton button, InAppMessageCloser inAppMessageCloser) { + return false; + } + + @Override + public void onInAppMessageDismissed(IInAppMessage inAppMessage) { } + + @Override + public void beforeInAppMessageViewOpened(View inAppMessageView, IInAppMessage inAppMessage) { } + + @Override + public void afterInAppMessageViewOpened(View inAppMessageView, IInAppMessage inAppMessage) { } + + @Override + public void beforeInAppMessageViewClosed(View inAppMessageView, IInAppMessage inAppMessage) { } + + @Override + public void afterInAppMessageViewClosed(IInAppMessage inAppMessage) { } + } + AppboyInAppMessageManager.getInstance().setCustomInAppMessageManagerListener(new BrazeInAppMessageManagerListener()); } /** diff --git a/AppboyProject/ios/AppboyProject.xcodeproj/project.pbxproj b/AppboyProject/ios/AppboyProject.xcodeproj/project.pbxproj index 69ccc7b..e137d1f 100644 --- a/AppboyProject/ios/AppboyProject.xcodeproj/project.pbxproj +++ b/AppboyProject/ios/AppboyProject.xcodeproj/project.pbxproj @@ -413,6 +413,7 @@ "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/ABKContentCardsStoryboard.storyboard", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/ar.lproj/AppboyContentCardsLocalizable.strings", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/Base.lproj/AppboyContentCardsLocalizable.strings", + "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/cs.lproj/AppboyContentCardsLocalizable.strings", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/da.lproj/AppboyContentCardsLocalizable.strings", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/de.lproj/AppboyContentCardsLocalizable.strings", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/en.lproj/AppboyContentCardsLocalizable.strings", @@ -446,6 +447,7 @@ "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/ru.lproj/AppboyContentCardsLocalizable.strings", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/sv.lproj/AppboyContentCardsLocalizable.strings", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/th.lproj/AppboyContentCardsLocalizable.strings", + "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/uk.lproj/AppboyContentCardsLocalizable.strings", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/vi.lproj/AppboyContentCardsLocalizable.strings", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/zh-Hans.lproj/AppboyContentCardsLocalizable.strings", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/zh-Hant.lproj/AppboyContentCardsLocalizable.strings", @@ -454,6 +456,7 @@ "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/zh.lproj/AppboyContentCardsLocalizable.strings", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/ar.lproj", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/Base.lproj", + "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/cs.lproj", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/da.lproj", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/de.lproj", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/en.lproj", @@ -482,6 +485,7 @@ "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/ru.lproj", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/sv.lproj", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/th.lproj", + "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/uk.lproj", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/vi.lproj", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/zh-Hans.lproj", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKContentCards/Resources/zh-Hant.lproj", @@ -502,6 +506,7 @@ "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/ABKNewsFeedCardStoryboard.storyboard", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/ar.lproj/AppboyFeedLocalizable.strings", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/Base.lproj/AppboyFeedLocalizable.strings", + "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/cs.lproj/AppboyFeedLocalizable.strings", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/da.lproj/AppboyFeedLocalizable.strings", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/de.lproj/AppboyFeedLocalizable.strings", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/en.lproj/AppboyFeedLocalizable.strings", @@ -536,6 +541,7 @@ "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/ru.lproj/AppboyFeedLocalizable.strings", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/sv.lproj/AppboyFeedLocalizable.strings", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/th.lproj/AppboyFeedLocalizable.strings", + "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/uk.lproj/AppboyFeedLocalizable.strings", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/vi.lproj/AppboyFeedLocalizable.strings", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/zh-Hans.lproj/AppboyFeedLocalizable.strings", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/zh-Hant.lproj/AppboyFeedLocalizable.strings", @@ -544,6 +550,7 @@ "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/zh.lproj/AppboyFeedLocalizable.strings", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/ar.lproj", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/Base.lproj", + "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/cs.lproj", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/da.lproj", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/de.lproj", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/en.lproj", @@ -572,6 +579,7 @@ "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/ru.lproj", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/sv.lproj", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/th.lproj", + "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/uk.lproj", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/vi.lproj", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/zh-Hans.lproj", "${PODS_ROOT}/Appboy-iOS-SDK/AppboyUI/ABKNewsFeed/Resources/zh-Hant.lproj", @@ -590,6 +598,7 @@ "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/appboy_cc_noimage_lrg@2x.png", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ar.lproj", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Base.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/cs.lproj", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/da.lproj", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/de.lproj", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/en.lproj", @@ -618,6 +627,7 @@ "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ru.lproj", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/sv.lproj", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/th.lproj", + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/uk.lproj", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/vi.lproj", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/zh-Hans.lproj", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/zh-Hant.lproj", diff --git a/AppboyProject/ios/AppboyProject/AppDelegate.h b/AppboyProject/ios/AppboyProject/AppDelegate.h index cadb48c..d5d39ef 100644 --- a/AppboyProject/ios/AppboyProject/AppDelegate.h +++ b/AppboyProject/ios/AppboyProject/AppDelegate.h @@ -1,8 +1,10 @@ #import #import +#import @interface AppDelegate : UIResponder @property (nonatomic, strong) UIWindow *window; +@property (nonatomic, strong) RCTBridge* bridge; @end diff --git a/AppboyProject/ios/AppboyProject/AppDelegate.m b/AppboyProject/ios/AppboyProject/AppDelegate.m index b86362c..afbcd45 100644 --- a/AppboyProject/ios/AppboyProject/AppDelegate.m +++ b/AppboyProject/ios/AppboyProject/AppDelegate.m @@ -2,11 +2,15 @@ #import #import #import +#import +#import #import "AppboyKit.h" #import "AppboyReactUtils.h" @implementation AppDelegate +@synthesize bridge; + - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSURL *jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; @@ -16,6 +20,7 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( initialProperties:nil launchOptions:launchOptions]; + self.bridge = rootView.bridge; self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; UIViewController *rootViewController = [UIViewController new]; rootViewController.view = rootView; @@ -23,7 +28,8 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [self.window makeKeyAndVisible]; [Appboy startWithApiKey:@"d0555d14-3491-4141-a9f0-ffb83e3c2a2f" inApplication:application - withLaunchOptions:launchOptions]; + withLaunchOptions:launchOptions + withAppboyOptions:@{ ABKInAppMessageControllerDelegateKey : self }]; // Register for user notifications if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_9_x_Max) { @@ -52,6 +58,9 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:( [[AppboyReactUtils sharedInstance] populateInitialUrlFromLaunchOptions:launchOptions]; + // In-App Messaging + [Appboy sharedInstance].inAppMessageController.delegate = self; + return YES; } @@ -90,4 +99,19 @@ - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserAct restorationHandler:restorationHandler]; } +// In-app messaging +- (ABKInAppMessageDisplayChoice) beforeInAppMessageDisplayed:(ABKInAppMessage *)inAppMessage { + NSLog(@"Received IAM from Braze in beforeInAppMessageDisplayed delegate."); + NSData *inAppMessageData = [inAppMessage serializeToData]; + NSString *inAppMessageString = [[NSString alloc] initWithData:inAppMessageData encoding:NSUTF8StringEncoding]; + NSDictionary *arguments = @{ + @"inAppMessage" : inAppMessageString + }; + [self.bridge.eventDispatcher + sendDeviceEventWithName:@"inAppMessageReceived" + body:arguments]; + // Note: return ABKDiscardInAppMessage if you would like + // to prevent the Braze SDK from displaying the message natively. + return ABKDisplayInAppMessageNow; +} @end diff --git a/AppboyProject/ios/Podfile b/AppboyProject/ios/Podfile index 491d9af..297ce76 100644 --- a/AppboyProject/ios/Podfile +++ b/AppboyProject/ios/Podfile @@ -2,7 +2,7 @@ platform :ios, '9.0' require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' target 'AppboyProject' do - pod 'Appboy-iOS-SDK', '3.21.3' + pod 'Appboy-iOS-SDK', '3.26.0' # If you want to integrate through Cocoapods instead of manual linking use this: # It already comes with a dependency on `Appboy-iOS-SDK` so you're all set. Remember to diff --git a/AppboyProject/ios/Podfile.lock b/AppboyProject/ios/Podfile.lock index 217a386..a943e06 100644 --- a/AppboyProject/ios/Podfile.lock +++ b/AppboyProject/ios/Podfile.lock @@ -1,17 +1,17 @@ PODS: - - Appboy-iOS-SDK (3.21.3): - - Appboy-iOS-SDK/UI (= 3.21.3) - - Appboy-iOS-SDK/ContentCards (3.21.3): + - Appboy-iOS-SDK (3.26.0): + - Appboy-iOS-SDK/UI (= 3.26.0) + - Appboy-iOS-SDK/ContentCards (3.26.0): - Appboy-iOS-SDK/Core - SDWebImage (~> 5.0) - - Appboy-iOS-SDK/Core (3.21.3) - - Appboy-iOS-SDK/InAppMessage (3.21.3): + - Appboy-iOS-SDK/Core (3.26.0) + - Appboy-iOS-SDK/InAppMessage (3.26.0): - Appboy-iOS-SDK/Core - SDWebImage (~> 5.0) - - Appboy-iOS-SDK/NewsFeed (3.21.3): + - Appboy-iOS-SDK/NewsFeed (3.26.0): - Appboy-iOS-SDK/Core - SDWebImage (~> 5.0) - - Appboy-iOS-SDK/UI (3.21.3): + - Appboy-iOS-SDK/UI (3.26.0): - Appboy-iOS-SDK/ContentCards - Appboy-iOS-SDK/Core - Appboy-iOS-SDK/InAppMessage @@ -199,8 +199,8 @@ PODS: - React-cxxreact (= 0.61.5) - React-jsi (= 0.61.5) - React-jsinspector (0.61.5) - - react-native-appboy-sdk (1.20.0): - - Appboy-iOS-SDK (~> 3.21.3) + - react-native-appboy-sdk (1.21.0): + - Appboy-iOS-SDK (~> 3.26.0) - React - React-RCTActionSheet (0.61.5): - React-Core/RCTActionSheetHeaders (= 0.61.5) @@ -237,13 +237,13 @@ PODS: - React-cxxreact (= 0.61.5) - React-jsi (= 0.61.5) - ReactCommon/jscallinvoker (= 0.61.5) - - SDWebImage (5.5.2): - - SDWebImage/Core (= 5.5.2) - - SDWebImage/Core (5.5.2) + - SDWebImage (5.8.4): + - SDWebImage/Core (= 5.8.4) + - SDWebImage/Core (5.8.4) - Yoga (1.14.0) DEPENDENCIES: - - Appboy-iOS-SDK (= 3.21.3) + - Appboy-iOS-SDK (= 3.26.0) - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) - FBReactNativeSpec (from `../node_modules/react-native/Libraries/FBReactNativeSpec`) @@ -276,8 +276,9 @@ DEPENDENCIES: SPEC REPOS: https://github.com/CocoaPods/Specs.git: - - Appboy-iOS-SDK - boost-for-react-native + trunk: + - Appboy-iOS-SDK - SDWebImage EXTERNAL SOURCES: @@ -335,7 +336,7 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon/yoga" SPEC CHECKSUMS: - Appboy-iOS-SDK: 2600f129c311e14217a2b0e75264bad88214b97c + Appboy-iOS-SDK: ecfcd7edaa1813c5f18e019c8faa171931d51f8f boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2 FBLazyVector: aaeaf388755e4f29cd74acbc9e3b8da6d807c37f @@ -351,7 +352,7 @@ SPEC CHECKSUMS: React-jsi: cb2cd74d7ccf4cffb071a46833613edc79cdf8f7 React-jsiexecutor: d5525f9ed5f782fdbacb64b9b01a43a9323d2386 React-jsinspector: fa0ecc501688c3c4c34f28834a76302233e29dc0 - react-native-appboy-sdk: c07a192dcc08f3e3c19203a2e0253ab32d36655a + react-native-appboy-sdk: adeccdb2362c394c2ab93f6c350ee4220c87e0ec React-RCTActionSheet: 600b4d10e3aea0913b5a92256d2719c0cdd26d76 React-RCTAnimation: 791a87558389c80908ed06cc5dfc5e7920dfa360 React-RCTBlob: d89293cc0236d9cb0933d85e430b0bbe81ad1d72 @@ -362,9 +363,9 @@ SPEC CHECKSUMS: React-RCTText: 9ccc88273e9a3aacff5094d2175a605efa854dbe React-RCTVibration: a49a1f42bf8f5acf1c3e297097517c6b3af377ad ReactCommon: 198c7c8d3591f975e5431bec1b0b3b581aa1c5dd - SDWebImage: 4d5c027c935438f341ed33dbac53ff9f479922ca + SDWebImage: cf6922231e95550934da2ada0f20f2becf2ceba9 Yoga: f2a7cd4280bfe2cca5a7aed98ba0eb3d1310f18b -PODFILE CHECKSUM: ac245fcadc6d9d7a2f662945e62fccd1d450c5ba +PODFILE CHECKSUM: d0a2b254a384a0f3a0067a26aa572948a124f361 -COCOAPODS: 1.9.1 +COCOAPODS: 1.9.3 diff --git a/CHANGELOG.md b/CHANGELOG.md index b2a3178..7e5340b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +## 1.21.0 + +##### Added +- Added support for working with in-app messages in the JavaScript layer. In-App Messages can be instantiated using the `BrazeInAppMessage` class. The resulting object can be passed into the analytics methods: `logInAppMessageClicked`, `logInAppMessageImpression`, and `logInAppMessageButtonClicked` (along with the button index). See the README for additional implementation details or the `AppboyProject` sample app for an integration example. +- Added `ReactAppboy.requestGeofences()` to request a Braze Geofences update for a manually provided GPS coordinate. Automatic Braze Geofence requests must be disabled to properly use this method. + +##### ⚠ Breaking +- Updated the native Android bridge to [Braze Android SDK 8.0.1](https://github.com/Appboy/appboy-android-sdk/blob/master/CHANGELOG.md#801). +- Updated the native iOS bridge to [Braze iOS SDK 3.26.0](https://github.com/Appboy/appboy-ios-sdk/releases/tag/3.26.0). + +##### Changed +- Improved Typescript definitions for `setCustomUserAttribute` and `incrementCustomUserAttribute`. + - Thanks @janczizikow! + +##### Fixed +- Fixed incorrect TypeScript definition for `ContentCard`. + - Thanks @Hannes-Sandahl-Mpya! + ## 1.20.0 ##### ⚠ Breaking diff --git a/README.md b/README.md index d813d47..18fc6e8 100644 --- a/README.md +++ b/README.md @@ -20,28 +20,47 @@ also optionally integrate the iOS bridge using Cocoapods via a local Podspec. The following commands apply to both sample projects and use the `AppboyProject` directory as an example. -``` +```zsh cd AppboyProject/ yarn install + +# In a separate tab: +cd AppboyProject/ +npx react-native start ``` ### iOS Our sample app integrates the native Braze iOS SDK through [Cocoapods](https://guides.cocoapods.org/using/getting-started.html). From the `AppboyProject` directory: -``` +```zsh sudo gem install cocoapods cd ios/ pod install cd ../ -react-native run-ios +npx react-native run-ios ``` ### Android From the `AppboyProject` directory: +```zsh +npx react-native run-android ``` -react-native run-android -``` + +## In-App Messages +### Integration + +Native in-app messages display automatically out of the box on Android and iOS. + +To get the in-app message data implement the `IInAppMessageManagerListener` delegate as described in our public documentation [for Android](https://www.braze.com/docs/developer_guide/platform_integration_guides/android/in-app_messaging/customization/#setting-a-custom-manager-listener) and [for iOS](https://www.braze.com/docs/developer_guide/platform_integration_guides/ios/in-app_messaging/customization/). This data can then be received in the JavaScript layer and used to instantiate a `BrazeInAppMessage`. A sample implementation of this is contained in AppboyProject. + +### Disabling automatic display +To disable automatic in-app message display for Android, your `beforeInAppMessageDisplayed` method implementation should return `InAppMessageOperation.DISCARD`. + +To disable automatic in-app message display for iOS, your `beforeInAppMessageDisplayed` delegate implementation should return `ABKInAppMessageDisplayChoice.discardInAppMessage`. + +### Analytics +To log analytics using your `BrazeInAppMessage`, pass the instance into the `logInAppMessageClicked`, `logInAppMessageImpression`, and `logInAppMessageButtonClicked` (along with the button index) methods available on `ReactAppboy`. ## Style - Generally we try to mimic the Braze Web SDK's Javascript interface where appropriate. diff --git a/__tests__/index.test.js b/__tests__/index.test.js index 798a92c..2a8ba63 100644 --- a/__tests__/index.test.js +++ b/__tests__/index.test.js @@ -67,7 +67,10 @@ jest.mock('NativeModules', () => { requestGeofences: jest.fn(), setLocationCustomAttribute: jest.fn(), requestContentCardsRefresh: jest.fn(), - hideCurrentInAppMessage: jest.fn() + hideCurrentInAppMessage: jest.fn(), + logInAppMessageClicked: jest.fn(), + logInAppMessageImpression: jest.fn(), + logInAppMessageButtonClicked: jest.fn() } }; }); @@ -75,6 +78,8 @@ jest.mock('NativeModules', () => { console.log = jest.fn(); testCallback = jest.fn(); +const testInAppMessageJson = `{\"message\":\"body body\",\"type\":\"MODAL\",\"text_align_message\":\"CENTER\",\"click_action\":\"NONE\",\"message_close\":\"SWIPE\",\"extras\":{\"test\":\"123\",\"foo\":\"bar\"},\"header\":\"hello\",\"text_align_header\":\"CENTER\",\"image_url\":\"https:\\/\\/cdn-staging.braze.com\\/appboy\\/communication\\/marketing\\/slide_up\\/slide_up_message_parameters\\/images\\/5ba53198bf5cea446b153b77\\/0af410cf267a4686ac6cac571bd2be4da4c8e63c\\/original.jpg?1572663749\",\"image_style\":\"TOP\",\"btns\":[{\"id\":0,\"text\":\"button 1\",\"click_action\":\"URI\",\"uri\":\"https:\\/\\/www.google.com\",\"use_webview\":true,\"bg_color\":4294967295,\"text_color\":4279990479,\"border_color\":4279990479},{\"id\":1,\"text\":\"button 2\",\"click_action\":\"NONE\",\"bg_color\":4279990479,\"text_color\":4294967295,\"border_color\":4279990479}],\"close_btn_color\":4291085508,\"bg_color\":4294243575,\"frame_color\":3207803699,\"text_color\":4280624421,\"header_text_color\":4280624421,\"trigger_id\":\"NWJhNTMxOThiZjVjZWE0NDZiMTUzYjZiXyRfbXY9NWJhNTMxOThiZjVjZWE0NDZiMTUzYjc1JnBpPWNtcA==\"}`; + afterEach(() => { jest.clearAllMocks(); }); @@ -463,3 +468,123 @@ test('it adds a listener', () => { nativeEmitter.emit(testEvent); expect(counter).toBe(1); }); + +it('instantiates a BrazeInAppMessage object', () => { + const testMessageBody = "some message body"; + const testMessageType = 'MODAL'; + const testUri = "https:\\/\\/www.sometesturi.com"; + const testImageUrl = "https:\\/\\/www.sometestimageuri.com"; + const testZippedAssetsUrl = "https:\\/\\/www.sometestzippedassets.com"; + const testUseWebView = true; + const testDuration = 42; + const testExtras = '{\"test\":\"123\",\"foo\":\"bar\"}'; + const testClickAction = 'URI'; + const testDismissType = 'SWIPE'; + const testHeader = "some header"; + const testButton0 = '{\"id\":0,\"text\":\"button 1\",\"click_action\":\"URI\",\"uri\":\"https:\\/\\/www.google.com\",\"use_webview\":true,\"bg_color\":4294967295,\"text_color\":4279990479,\"border_color\":4279990479}'; + const testButton1 = '{\"id\":1,\"text\":\"button 2\",\"click_action\":\"NONE\",\"bg_color\":4279990479,\"text_color\":4294967295,\"border_color\":4279990479}'; + const testButtonString = `[${testButton0}, ${testButton1}]`; + const testButtons = []; + testButtons.push(new ReactAppboy.BrazeButton(JSON.parse(testButton0))); + testButtons.push(new ReactAppboy.BrazeButton(JSON.parse(testButton1))); + const testJson = `{\"message\":\"${testMessageBody}\",\"type\":\"${testMessageType}\",\"text_align_message\":\"CENTER\",\"click_action\":\"${testClickAction}\",\"message_close\":\"SWIPE\",\"extras\":${testExtras},\"header\":\"${testHeader}\",\"text_align_header\":\"CENTER\",\"image_url\":\"${testImageUrl}\",\"image_style\":\"TOP\",\"btns\":${testButtonString},\"close_btn_color\":4291085508,\"bg_color\":4294243575,\"frame_color\":3207803699,\"text_color\":4280624421,\"header_text_color\":4280624421,\"trigger_id\":\"NWJhNTMxOThiZjVjZWE0NDZiMTUzYjZiXyRfbXY9NWJhNTMxOThiZjVjZWE0NDZiMTUzYjc1JnBpPWNtcA==\",\"uri\":\"${testUri}\",\"zipped_assets_url\":\"${testZippedAssetsUrl}\",\"duration\":${testDuration},\"message_close\":\"${testDismissType}\",\"use_webview\":${testUseWebView}}` + const inAppMessage = new ReactAppboy.BrazeInAppMessage(testJson); + expect(inAppMessage.message).toBe(testMessageBody); + expect(inAppMessage.messageType).toBe(testMessageType.toLowerCase()); + expect(inAppMessage.uri).toBe(JSON.parse(`"${testUri}"`)); + expect(inAppMessage.useWebView).toBe(testUseWebView); + expect(inAppMessage.zippedAssetsUrl).toBe(JSON.parse(`"${testZippedAssetsUrl}"`)); + expect(inAppMessage.duration).toBe(testDuration); + expect(inAppMessage.extras).toEqual(JSON.parse(testExtras)); + expect(inAppMessage.clickAction).toBe(testClickAction.toLowerCase()); + expect(inAppMessage.dismissType).toBe(testDismissType.toLowerCase()); + expect(inAppMessage.imageUrl).toBe(JSON.parse(`"${testImageUrl}"`)); + expect(inAppMessage.header).toBe(testHeader); + expect(inAppMessage.inAppMessageJsonString).toBe(testJson); + expect(inAppMessage.buttons).toEqual(testButtons); +}); + +it('instantiates a BrazeInAppMessage object with the desired defaults', () => { + const defaultMessageBody = ''; + const defaultMessageType = 'SLIDEUP'; + const defaultUri = ''; + const defaultImageUrl = ''; + const defaultZippedAssetsUrl = ''; + const defaultUseWebView = false; + const defaultDuration = 5; + const defaultExtras = {}; + const defaultClickAction = 'NONE'; + const defaultDismissType = 'AUTO_DISMISS'; + const defaultHeader = ''; + const defaultButtons = []; + const testJson = `{}`; + const inAppMessage = new ReactAppboy.BrazeInAppMessage(testJson); + expect(inAppMessage.message).toBe(defaultMessageBody); + expect(inAppMessage.messageType).toBe(defaultMessageType.toLowerCase()); + expect(inAppMessage.uri).toBe(defaultUri); + expect(inAppMessage.useWebView).toBe(defaultUseWebView); + expect(inAppMessage.zippedAssetsUrl).toBe(defaultZippedAssetsUrl); + expect(inAppMessage.duration).toBe(defaultDuration); + expect(inAppMessage.extras).toEqual(defaultExtras); + expect(inAppMessage.clickAction).toBe(defaultClickAction.toLowerCase()); + expect(inAppMessage.dismissType).toBe(defaultDismissType.toLowerCase()); + expect(inAppMessage.imageUrl).toBe(defaultImageUrl); + expect(inAppMessage.header).toBe(defaultHeader); + expect(inAppMessage.inAppMessageJsonString).toBe(testJson); + expect(inAppMessage.buttons).toEqual(defaultButtons); +}); + +it('returns the original JSON when calling BrazeInAppMessage.toString()', () => { + const inAppMessage = new ReactAppboy.BrazeInAppMessage(testInAppMessageJson); + expect(inAppMessage.toString()).toBe(testInAppMessageJson); +}); + +test('it calls AppboyReactBridge.logInAppMessageClicked', () => { + const inAppMessage = new ReactAppboy.BrazeInAppMessage(testInAppMessageJson); + ReactAppboy.logInAppMessageClicked(inAppMessage); + expect(NativeModules.AppboyReactBridge.logInAppMessageClicked).toBeCalledWith(testInAppMessageJson); +}); + +test('it calls AppboyReactBridge.logInAppMessageImpression', () => { + const inAppMessage = new ReactAppboy.BrazeInAppMessage(testInAppMessageJson); + ReactAppboy.logInAppMessageImpression(inAppMessage); + expect(NativeModules.AppboyReactBridge.logInAppMessageImpression).toBeCalledWith(testInAppMessageJson); +}); + +test('it calls AppboyReactBridge.logInAppMessageButtonClicked', () => { + const inAppMessage = new ReactAppboy.BrazeInAppMessage(testInAppMessageJson); + const testId = 23; + ReactAppboy.logInAppMessageButtonClicked(inAppMessage, testId); + expect(NativeModules.AppboyReactBridge.logInAppMessageButtonClicked).toBeCalledWith(testInAppMessageJson, testId); +}); + +it('instantiates a BrazeButton object', () => { + const testId = 53; + const testClickAction = 'URI'; + const testText = 'some text'; + const testUri = "https:\\/\\/www.sometesturi.com"; + const testUseWebView = true; + const testButtonJson = `{\"id\":${testId},\"text\":\"${testText}\",\"click_action\":\"${testClickAction}\",\"uri\":\"${testUri}\",\"use_webview\":${testUseWebView},\"bg_color\":4294967295,\"text_color\":4279990479,\"border_color\":4279990479}`; + const button = new ReactAppboy.BrazeButton(JSON.parse(testButtonJson)); + expect(button.id).toBe(testId); + expect(button.clickAction).toBe(testClickAction.toLowerCase()); + expect(button.text).toBe(testText); + expect(button.uri).toBe(JSON.parse(`"${testUri}"`)); + expect(button.useWebView).toBe(testUseWebView); + expect(button.toString()).toBe("BrazeButton text:" + button.text + " uri:" + button.uri + " clickAction:" + + button.clickAction.toString() + " useWebView:" + button.useWebView.toString()); +}); + +it('instantiates a BrazeButton object with the desired defaults', () => { + const defaultUri = ''; + const defaultText= ''; + const defaultUseWebView = false; + const defaultClickAction = 'NONE'; + const defaultId = 0; + const inAppMessage = new ReactAppboy.BrazeButton(`{}`); + expect(inAppMessage.uri).toBe(defaultUri); + expect(inAppMessage.useWebView).toBe(defaultUseWebView); + expect(inAppMessage.text).toBe(defaultText); + expect(inAppMessage.clickAction).toBe(defaultClickAction.toLowerCase()); + expect(inAppMessage.id).toBe(defaultId); +}); \ No newline at end of file diff --git a/android/build.gradle b/android/build.gradle index 8d3f34b..70fb9e8 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -17,6 +17,6 @@ android { } dependencies { - api 'com.appboy:android-sdk-ui:7.0.0' + api 'com.appboy:android-sdk-ui:8.0.1' api 'com.facebook.react:react-native:+' } diff --git a/android/src/main/java/com/appboy/reactbridge/AppboyReactBridge.java b/android/src/main/java/com/appboy/reactbridge/AppboyReactBridge.java index 6e331f5..da29163 100644 --- a/android/src/main/java/com/appboy/reactbridge/AppboyReactBridge.java +++ b/android/src/main/java/com/appboy/reactbridge/AppboyReactBridge.java @@ -16,6 +16,9 @@ import com.appboy.models.cards.Card; import com.appboy.models.cards.ShortNewsCard; import com.appboy.models.cards.TextAnnouncementCard; +import com.appboy.models.IInAppMessage; +import com.appboy.models.IInAppMessageImmersive; +import com.appboy.models.MessageButton; import com.appboy.models.outgoing.AppboyProperties; import com.appboy.models.outgoing.AttributionData; import com.appboy.models.outgoing.FacebookUser; @@ -724,6 +727,36 @@ public void hideCurrentInAppMessage() { AppboyInAppMessageManager.getInstance().hideCurrentlyDisplayingInAppMessage(true); } + @ReactMethod + public void logInAppMessageClicked(String inAppMessageString) { + IInAppMessage inAppMessage = Appboy.getInstance(getReactApplicationContext()).deserializeInAppMessageString(inAppMessageString); + if (inAppMessage != null) { + inAppMessage.logClick(); + } + } + + @ReactMethod + public void logInAppMessageImpression(String inAppMessageString) { + IInAppMessage inAppMessage = Appboy.getInstance(getReactApplicationContext()).deserializeInAppMessageString(inAppMessageString); + if (inAppMessage != null) { + inAppMessage.logImpression(); + } + } + + @ReactMethod + public void logInAppMessageButtonClicked(String inAppMessageString, Integer buttonId) { + IInAppMessage inAppMessage = Appboy.getInstance(getReactApplicationContext()).deserializeInAppMessageString(inAppMessageString); + if (inAppMessage instanceof IInAppMessageImmersive) { + IInAppMessageImmersive inAppMessageImmersive = (IInAppMessageImmersive)inAppMessage; + for (MessageButton button : inAppMessageImmersive.getMessageButtons()) { + if (button.getId() == buttonId) { + inAppMessageImmersive.logButtonClick(button); + break; + } + } + } + } + @ReactMethod public void setAttributionData(String network, String campaign, String adGroup, String creative) { AttributionData attributionData = new AttributionData(network, campaign, adGroup, creative); diff --git a/iOS/AppboyReactBridge/AppboyReactBridge/AppboyReactBridge.m b/iOS/AppboyReactBridge/AppboyReactBridge/AppboyReactBridge.m index 56bfb6b..15af1ae 100644 --- a/iOS/AppboyReactBridge/AppboyReactBridge/AppboyReactBridge.m +++ b/iOS/AppboyReactBridge/AppboyReactBridge/AppboyReactBridge.m @@ -330,6 +330,13 @@ - (nullable ABKContentCard *)getContentCardById:(NSString *)idString { return nil; } +- (void) getInAppMessageFromString:(NSString *)inAppMessageJSONString withInAppMessage:(ABKInAppMessage *)inAppMessage { + NSData *inAppMessageData = [inAppMessageJSONString dataUsingEncoding:NSUTF8StringEncoding]; + NSError *e = nil; + id deserializedInAppMessageDict = [NSJSONSerialization JSONObjectWithData:inAppMessageData options:NSJSONReadingMutableContainers error:&e]; + [inAppMessage setValuesForKeysWithDictionary:deserializedInAppMessageDict]; +} + RCT_EXPORT_METHOD(launchContentCards) { RCTLogInfo(@"launchContentCards called"); ABKContentCardsViewController *contentCardsModal = [[ABKContentCardsViewController alloc] init]; @@ -499,5 +506,26 @@ - (ABKCardCategory)getCardCategoryForString:(NSString *)category { [[Appboy sharedInstance].inAppMessageController.inAppMessageUIController hideCurrentInAppMessage:YES]; } +RCT_EXPORT_METHOD(logInAppMessageClicked:(NSString *)inAppMessageString) { + RCTLogInfo(@"logInAppMessageClicked called with value %@", inAppMessageString); + ABKInAppMessage *inAppMessage = [[ABKInAppMessage alloc] init]; + [self getInAppMessageFromString:inAppMessageString withInAppMessage:inAppMessage]; + [inAppMessage logInAppMessageClicked]; +} + +RCT_EXPORT_METHOD(logInAppMessageImpression:(NSString *)inAppMessageString) { + RCTLogInfo(@"logInAppMessageImpression called with value %@", inAppMessageString); + ABKInAppMessage *inAppMessage = [[ABKInAppMessage alloc] init]; + [self getInAppMessageFromString:inAppMessageString withInAppMessage:inAppMessage]; + [inAppMessage logInAppMessageImpression]; +} + +RCT_EXPORT_METHOD(logInAppMessageButtonClicked:(NSString *)inAppMessageString buttonId:(int)buttonId) { + RCTLogInfo(@"logInAppMessageButtonClicked called with value %@", inAppMessageString); + ABKInAppMessageImmersive *inAppMessageImmersive = [[ABKInAppMessageImmersive alloc] init]; + [self getInAppMessageFromString:inAppMessageString withInAppMessage:inAppMessageImmersive]; + [inAppMessageImmersive logInAppMessageClickedWithButtonID:buttonId]; +} + RCT_EXPORT_MODULE(); @end diff --git a/index.d.ts b/index.d.ts index 7372678..cc225c1 100644 --- a/index.d.ts +++ b/index.d.ts @@ -217,7 +217,7 @@ export function logPurchase( */ export function setCustomUserAttribute( key: string, - value: any, + value: number | boolean | string | string[] | Date | null, callback?: Callback ): void; @@ -269,7 +269,7 @@ export function unsetCustomUserAttribute(key: string, callback?: Callback): void */ export function incrementCustomUserAttribute( key: string, - value: any, + value: number, callback?: Callback ): void; @@ -351,7 +351,7 @@ export interface ContentCard { id: string; created: number; expiresAt: number; - type: ContentCardType; + type: ContentCardType[keyof ContentCardType]; viewed: boolean; clicked: boolean; pinned: boolean; @@ -514,8 +514,83 @@ export function setLocationCustomAttribute( */ export function hideCurrentInAppMessage(): void; +/** + * Logs a click for the provided in-app message data + * @param {BrazeInAppMessage} inAppMessage + */ +export function logInAppMessageClicked( + inAppMessage: BrazeInAppMessage +): void; + +/** + * Logs an impression for the provided in-app message data + * @param {BrazeInAppMessage} inAppMessage + */ +export function logInAppMessageImpression( + inAppMessage: BrazeInAppMessage +): void; + +/** + * Logs a button click for the provided in-app message button data + * @param {BrazeInAppMessage} inAppMessage + * @param {number} buttonId + */ +export function logInAppMessageButtonClicked( + inAppMessage: BrazeInAppMessage, + buttonId: number +): void; + +export class BrazeInAppMessage { + constructor(_data: string) + inAppMessageJsonString: string + message: string + header: string + uri: string + imageUrl: string + zippedAssetsUrl: string + useWebView: boolean + duration: number + clickAction: BrazeClickAction[keyof BrazeClickAction] + dismissType: BrazeDismissType[keyof BrazeDismissType] + messageType: BrazeMessageType[keyof BrazeMessageType] + extras: {[key: string]: string} + buttons: [BrazeButton] + toString(): string; +} + +export class BrazeButton { + constructor(_data: string) + text: string + uri: string + useWebView: boolean + clickAction: BrazeClickAction[keyof BrazeClickAction] + id: number + toString(): string; +} + type MonthsAsNumber = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12; +interface BrazeClickAction { + 'NEWS_FEED': 'news_feed', + 'URI': 'uri', + 'NONE': 'none' +} +export const ClickAction: BrazeClickAction; + +interface BrazeDismissType { + 'SWIPE': 'swipe', + 'AUTO_DISMISS': 'auto_dismiss' +} +export const DismissType: BrazeDismissType; + +interface BrazeMessageType { + 'SLIDEUP': 'slideup', + 'MODAL': 'modal', + 'FULL': 'full', + 'HTML_FULL': 'html_full' +} +export const MessageType: BrazeMessageType; + interface BrazeCardCategory { ADVERTISING: 'advertising'; ANNOUNCEMENTS: 'announcements'; diff --git a/index.js b/index.js index db7f24f..dbb0a78 100644 --- a/index.js +++ b/index.js @@ -603,6 +603,34 @@ var ReactAppboy = { AppboyReactBridge.hideCurrentInAppMessage(); }, + /** + * Logs a click for the provided in-app message data + * @param {BrazeInAppMessage} inAppMessage + */ + logInAppMessageClicked: function(inAppMessage) { + const inAppMessageString = inAppMessage.toString(); + AppboyReactBridge.logInAppMessageClicked(inAppMessageString); + }, + + /** + * Logs an impression for the provided in-app message data + * @param {BrazeInAppMessage} inAppMessage + */ + logInAppMessageImpression: function(inAppMessage) { + const inAppMessageString = inAppMessage.toString(); + AppboyReactBridge.logInAppMessageImpression(inAppMessageString); + }, + + /** + * Logs a button click for the provided in-app message button data + * @param {BrazeInAppMessage} inAppMessage + * @param {number} buttonId + */ + logInAppMessageButtonClicked: function(inAppMessage, buttonId) { + const inAppMessageString = inAppMessage.toString(); + AppboyReactBridge.logInAppMessageButtonClicked(inAppMessageString, buttonId); + }, + // Events /** * Subscribes to the specific SDK event. @@ -615,6 +643,147 @@ var ReactAppboy = { return AppboyEventEmitter.addListener(event, subscriber); }, + BrazeInAppMessage: class { + constructor(_data) { + this.inAppMessageJsonString = _data; + let inAppMessageJson = JSON.parse(this.inAppMessageJsonString); + let messageJson = inAppMessageJson["message"]; + if (typeof messageJson === 'string') { + this.message = messageJson; + } else { + this.message = ''; + } + let headerJson = inAppMessageJson["header"]; + if (typeof headerJson === 'string') { + this.header = headerJson; + } else { + this.header = ''; + } + let uriJson = inAppMessageJson["uri"]; + if (typeof uriJson === 'string') { + this.uri = uriJson; + } else { + this.uri = ''; + } + let imageUrlJson = inAppMessageJson["image_url"]; + if (typeof imageUrlJson === 'string') { + this.imageUrl = imageUrlJson; + } else { + this.imageUrl = ''; + } + let zippedAssetsUrlJson = inAppMessageJson["zipped_assets_url"]; + if (typeof zippedAssetsUrlJson === 'string') { + this.zippedAssetsUrl = zippedAssetsUrlJson; + } else { + this.zippedAssetsUrl = ''; + } + let useWebViewJson = inAppMessageJson["use_webview"]; + if (typeof useWebViewJson === 'boolean') { + this.useWebView = useWebViewJson; + } else { + this.useWebView = false; + } + let durationJson = inAppMessageJson["duration"]; + if (typeof durationJson === 'number') { + this.duration = durationJson; + } else { + this.duration = 5; + } + let clickActionJson = inAppMessageJson["click_action"]; + this.clickAction = ReactAppboy.ClickAction['NONE']; + if (typeof clickActionJson === 'string') { + Object.values(ReactAppboy.ClickAction).forEach(action => { + if (action.toLowerCase().endsWith(clickActionJson + .toLowerCase())) { + this.clickAction = action; + } + }); + } + let dismissTypeJson = inAppMessageJson["message_close"]; + this.dismissType = ReactAppboy.DismissType['AUTO_DISMISS']; + if (typeof dismissTypeJson === 'string') { + Object.values(ReactAppboy.DismissType).forEach(type => { + if (type.toLowerCase().endsWith(dismissTypeJson + .toLowerCase())) { + this.dismissType = type; + } + }); + } + let messageTypeJson = inAppMessageJson["type"]; + this.messageType = ReactAppboy.MessageType['SLIDEUP']; + if (typeof messageTypeJson === 'string') { + Object.values(ReactAppboy.MessageType).forEach(type => { + if (type.toLowerCase().endsWith(messageTypeJson + .toLowerCase())) { + this.messageType = type; + } + }); + } + let extrasJson = inAppMessageJson["extras"]; + this.extras = {}; + if (typeof extrasJson === 'object') { + Object.keys(extrasJson).forEach(key=> { + if (typeof extrasJson[key] === 'string') { + this.extras[key] = extrasJson[key]; + } + }); + } + this.buttons = []; + let buttonsJson = inAppMessageJson["btns"]; + if (typeof buttonsJson === 'object' && Array.isArray(buttonsJson)) { + buttonsJson.forEach(buttonJson => { + this.buttons.push(new ReactAppboy.BrazeButton(buttonJson)); + }); + } + } + toString() { + return this.inAppMessageJsonString; + } + }, + + BrazeButton: class { + constructor(buttonJson) { + let textJson = buttonJson['text']; + if (typeof textJson === 'string') { + this.text = textJson; + } else { + this.text = ''; + } + let uriJson = buttonJson['uri']; + if (typeof uriJson === 'string') { + this.uri = uriJson; + } else { + this.uri = ''; + } + let useWebViewJson = buttonJson["use_webview"]; + if (typeof useWebViewJson === 'boolean') { + this.useWebView = useWebViewJson; + } else { + this.useWebView = false; + } + let clickActionJson = buttonJson["click_action"]; + this.clickAction = ReactAppboy.ClickAction['NONE']; + if (typeof clickActionJson === 'string') { + Object.values(ReactAppboy.ClickAction).forEach(action => { + if (action.toLowerCase().endsWith(clickActionJson + .toLowerCase())) { + this.clickAction = action; + } + }); + } + let idJson = buttonJson["id"]; + if (typeof idJson === 'number') { + this.id = idJson; + } else { + this.id = 0; + } + } + toString() { + return "BrazeButton text:" + this.text + " uri:" + this.uri + " clickAction:" + + this.clickAction.toString() + " useWebView:" + this.useWebView.toString(); + } + }, + // Enums CardCategory: { 'ADVERTISING': 'advertising', @@ -649,6 +818,24 @@ var ReactAppboy = { Events: { 'CONTENT_CARDS_UPDATED': 'contentCardsUpdated' }, + + ClickAction: { + 'NEWS_FEED': 'news_feed', + 'URI': 'uri', + 'NONE': 'none' + }, + + DismissType: { + 'SWIPE': 'swipe', + 'AUTO_DISMISS': 'auto_dismiss' + }, + + MessageType: { + 'SLIDEUP': 'slideup', + 'MODAL': 'modal', + 'FULL': 'full', + 'HTML_FULL': 'html_full' + } }; module.exports = ReactAppboy; diff --git a/package.json b/package.json index 9abba56..b55cffd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-appboy-sdk", - "version": "1.20.0", + "version": "1.21.0", "description": "Braze SDK for React Native.", "main": "index.js", "types": "index.d.ts", diff --git a/react-native-appboy-sdk.podspec b/react-native-appboy-sdk.podspec index 242d49f..e5aaaec 100644 --- a/react-native-appboy-sdk.podspec +++ b/react-native-appboy-sdk.podspec @@ -18,6 +18,6 @@ Pod::Spec.new do |s| s.preserve_paths = 'LICENSE.md', 'README.md', 'package.json', 'index.js' s.source_files = 'iOS/**/*.{h,m}' - s.dependency 'Appboy-iOS-SDK', '~> 3.21.3' + s.dependency 'Appboy-iOS-SDK', '~> 3.26.0' s.dependency 'React' end