diff --git a/CHANGELOG.md b/CHANGELOG.md index 10f9d70..e884b14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ ⚠️ In version 3.0.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 3.0.0 to a version above 3.0.0, please read [the instructions](https://github.com/braze-inc/braze-flutter-sdk/blob/master/CHANGELOG.md#300) to ensure a smooth transition and backward compatibility. +## 10.0.0 + +##### Breaking +- Updates the native iOS bridge [from Braze Swift SDK 8.4.0 to 9.0.0](https://github.com/braze-inc/braze-swift-sdk/compare/8.4.0...9.0.0#diff-06572a96a58dc510037d5efa622f9bec8519bc1beab13c9f251e97e657a9d4ed). + +##### Added +- Adds the `getDeviceId` method to replace `getInstallTrackingId`, which is now deprecated. + +##### Fixed +- Fixes an issue where StrictMode DiskReadViolation was triggered on Android. + - Thanks @radivojeostojic for pointing this out. + ## 9.0.0 ##### Breaking @@ -136,7 +148,7 @@ ## 3.1.0 ##### Breaking -- The native Android bridge uses [Braze Android SDK 24.2.0](https://github.com/Appboy/appboy-android-sdk/blob/master/CHANGELOG.md#2420). +- The native Android bridge uses [Braze Android SDK 24.2.0](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#2420). - The native iOS bridge uses [Braze iOS SDK 5.9.0](https://github.com/braze-inc/braze-swift-sdk/blob/main/CHANGELOG.md#590). - The minimum iOS deployment target is 11.0. @@ -177,13 +189,13 @@ - This feature must be enabled by setting `replayCallbacksConfigKey: true` in `customConfigs` for the `BrazePlugin`. ##### Changed -- The native Android bridge uses [Braze Android SDK 23.3.0](https://github.com/Appboy/appboy-android-sdk/blob/master/CHANGELOG.md#2330). +- The native Android bridge uses [Braze Android SDK 23.3.0](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#2330). - Updates the parameter type for `subscribeToInAppMessages()` and `subscribeToContentCards()` to accept a `Function` instead of a `void`. ## 2.6.0 ##### Breaking -- The native Android bridge uses [Braze Android SDK 23.2.0](https://github.com/Appboy/appboy-android-sdk/blob/master/CHANGELOG.md#2320). +- The native Android bridge uses [Braze Android SDK 23.2.0](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#2320). - The native iOS bridge uses [Braze iOS SDK 4.5.1](https://github.com/Appboy/appboy-ios-sdk/blob/master/CHANGELOG.md#451). - `process(inAppMessage)` is renamed to `processInAppMessage(inAppMessage)` in the iOS layer. @@ -198,7 +210,7 @@ ## 2.5.0 ##### Breaking -- The native Android bridge uses [Braze Android SDK 21.0.0](https://github.com/Appboy/appboy-android-sdk/blob/master/CHANGELOG.md#2100). +- The native Android bridge uses [Braze Android SDK 21.0.0](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#2100). - Removes `logContentCardsDisplayed()`. This method was not part of the recommended Content Cards integration and can be safely removed. ##### Added @@ -210,7 +222,7 @@ ## 2.4.0 ##### Breaking -- The native Android bridge uses [Braze Android SDK 20.0.0](https://github.com/Appboy/appboy-android-sdk/blob/master/CHANGELOG.md#2000). +- The native Android bridge uses [Braze Android SDK 20.0.0](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#2000). - Removes `setAvatarImageUrl()`. ##### Changed @@ -219,7 +231,7 @@ ## 2.3.0 ##### Breaking -- The native Android bridge uses [Braze Android SDK 17.0.0](https://github.com/Appboy/appboy-android-sdk/blob/master/CHANGELOG.md#1700). +- The native Android bridge uses [Braze Android SDK 17.0.0](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#1700). - The minimum supported Android SDK version is 19. - Removes support for Android V1 Embedding APIs. Please reference [the Flutter migration guide](https://flutter.dev/docs/development/packages-and-plugins/plugin-api-migration) to update to the V2 APIs. @@ -239,7 +251,7 @@ ## 2.2.0 ##### Breaking -- The native Android bridge uses [Braze Android SDK 16.0.0](https://github.com/Appboy/appboy-android-sdk/blob/master/CHANGELOG.md#1600). +- The native Android bridge uses [Braze Android SDK 16.0.0](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#1600). - The native iOS bridge uses [Braze iOS SDK 4.4.0](https://github.com/Appboy/appboy-ios-sdk/blob/master/CHANGELOG.md#440). - Streamlines the Android integration process to not involve any manual writing of code to automatically register for sessions, in-app messages, or Content Card updates from the native SDK. - To migrate, remove any manual calls to `registerActivityLifecycleCallbacks()`, `subscribeToContentCardsUpdates()`, and `setCustomInAppMessageManagerListener()`. @@ -262,7 +274,7 @@ ##### Breaking - The native iOS bridge uses [Braze iOS SDK 4.3.2](https://github.com/Appboy/appboy-ios-sdk/blob/master/CHANGELOG.md#432). -- The native Android bridge uses [Braze Android SDK 15.0.0](https://github.com/Appboy/appboy-android-sdk/blob/master/CHANGELOG.md#1500). +- The native Android bridge uses [Braze Android SDK 15.0.0](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#1500). ##### Added - Adds `logContentCardsDisplayed()` to manually log an impression when displaying Content Cards in a custom UI. @@ -277,7 +289,7 @@ - Passing through `null` as a value for user attributes is no longer supported. - The only attribute that is able to be unset is `email` by passing in `null` into `setEmail`. - The methods `logEvent` and `logPurchase` now take an optional `properties` parameter. -- The native Android bridge uses [Braze Android SDK 14.0.0](https://github.com/Appboy/appboy-android-sdk/blob/master/CHANGELOG.md#1400). +- The native Android bridge uses [Braze Android SDK 14.0.0](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#1400). - The minimum supported Dart version is `2.12.0`. ##### Changed @@ -287,7 +299,7 @@ ##### Breaking - The native iOS bridge uses [Braze iOS SDK 4.0.2](https://github.com/Appboy/appboy-ios-sdk/blob/master/CHANGELOG.md#402). -- The native Android bridge uses [Braze Android SDK 13.1.2](https://github.com/Appboy/appboy-android-sdk/blob/master/CHANGELOG.md#1312). +- The native Android bridge uses [Braze Android SDK 13.1.2](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#1312). - The minimum supported Flutter version is 1.10.0. ##### Added @@ -297,7 +309,7 @@ ## 1.4.0 ##### Breaking -- The native Android bridge uses [Braze Android SDK 13.0.0](https://github.com/Appboy/appboy-android-sdk/blob/master/CHANGELOG.md#1300). +- The native Android bridge uses [Braze Android SDK 13.0.0](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#1300). - The native iOS bridge uses [Braze iOS SDK 3.34.0](https://github.com/Appboy/appboy-ios-sdk/blob/master/CHANGELOG.md#3340). ##### Added @@ -309,7 +321,7 @@ ## 1.3.0 ##### Breaking -- The native Android bridge uses [Braze Android SDK 12.0.0](https://github.com/Appboy/appboy-android-sdk/blob/master/CHANGELOG.md#1200). +- The native Android bridge uses [Braze Android SDK 12.0.0](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#1200). - The native iOS bridge uses [Braze iOS SDK 3.31.0](https://github.com/Appboy/appboy-ios-sdk/blob/master/CHANGELOG.md#3310). ##### Added @@ -327,7 +339,7 @@ ## 1.1.0 ##### Breaking -- The native Android bridge uses [Braze Android SDK 11.0.0](https://github.com/Appboy/appboy-android-sdk/blob/master/CHANGELOG.md#1100). +- The native Android bridge uses [Braze Android SDK 11.0.0](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#1100). - The native iOS bridge uses [Braze iOS SDK 3.29.1](https://github.com/Appboy/appboy-ios-sdk/blob/master/CHANGELOG.md#3291). ## 1.0.0 @@ -343,7 +355,7 @@ ## 0.10.0 ##### Breaking -- The native Android bridge uses [Braze Android SDK 8.1.0](https://github.com/Appboy/appboy-android-sdk/blob/master/CHANGELOG.md#810). +- The native Android bridge uses [Braze Android SDK 8.1.0](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#810). - The native iOS bridge uses [Braze iOS SDK 3.26.0](https://github.com/Appboy/appboy-ios-sdk/blob/master/CHANGELOG.md#3260). ##### Fixed @@ -352,15 +364,15 @@ ## 0.9.0 ##### Breaking -- The native Android bridge uses [Braze Android SDK 7.0.0](https://github.com/Appboy/appboy-android-sdk/blob/master/CHANGELOG.md#700). +- The native Android bridge uses [Braze Android SDK 7.0.0](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#700). - The native iOS bridge uses [Braze iOS SDK 3.22.0](https://github.com/Appboy/appboy-ios-sdk/blob/master/CHANGELOG.md#3220). ## 0.8.0 ##### Breaking - The native iOS bridge uses [Braze iOS SDK 3.21.3](https://github.com/Appboy/appboy-ios-sdk/blob/master/CHANGELOG.md#3213). -- The native Android bridge uses [Braze Android SDK 4.0.2](https://github.com/Appboy/appboy-android-sdk/blob/master/CHANGELOG.md#402). - - If you are using a custom `IInAppMessageManagerListener`, then you will need to define new methods added to that interface in [Braze Android SDK 4.0.0](https://github.com/Appboy/appboy-android-sdk/blob/master/CHANGELOG.md#400). See the `MainActivity.kt` file of our sample app for a reference example. +- The native Android bridge uses [Braze Android SDK 4.0.2](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#402). + - If you are using a custom `IInAppMessageManagerListener`, then you will need to define new methods added to that interface in [Braze Android SDK 4.0.0](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#400). See the `MainActivity.kt` file of our sample app for a reference example. ## 0.7.0 @@ -384,7 +396,7 @@ ## 0.6.0 ##### Changed -- The native Android bridge uses [Braze Android SDK 3.8.0](https://github.com/Appboy/appboy-android-sdk/blob/master/CHANGELOG.md#380). +- The native Android bridge uses [Braze Android SDK 3.8.0](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#380). - Updated the native iOS bridge to [Braze iOS SDK 3.20.4](https://github.com/Appboy/appboy-ios-sdk/releases/tag/3.20.4). ## 0.5.2 @@ -422,7 +434,7 @@ with ##### Breaking - The native iOS bridge uses [Braze iOS SDK 3.18.0](https://github.com/Appboy/appboy-ios-sdk/blob/master/CHANGELOG.md#3180). -- The native Android bridge uses [Braze Android SDK 3.6.0](https://github.com/Appboy/appboy-android-sdk/blob/master/CHANGELOG.md#360). +- The native Android bridge uses [Braze Android SDK 3.6.0](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#360). ##### Added - Added the following new field to `BrazeInAppMessage`: `zippedAssetsUrl`. @@ -432,7 +444,7 @@ with ##### Breaking - The native iOS bridge uses [Braze iOS SDK 3.15.0](https://github.com/Appboy/appboy-ios-sdk/blob/master/CHANGELOG.md#3150). -- The native Android bridge uses [Braze Android SDK 3.5.0](https://github.com/Appboy/appboy-android-sdk/blob/master/CHANGELOG.md#350). +- The native Android bridge uses [Braze Android SDK 3.5.0](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#350). - Support for the Android configuration parameter `com_appboy_inapp_show_inapp_messages_automatically` has been removed. - To control whether an in-app message object should be displayed natively or not, create and register an instance of `IInAppMessageManagerListener` in your native Android code and implement decisioning in the `beforeInAppMessageDisplayed` method. See `MainActivity` in our sample app for an example. - On Android, in-app message objects are no longer sent automatically to the Dart in-app message callback after calling `BrazePlugin.setBrazeInAppMessageCallback()` in your Dart code. @@ -454,7 +466,7 @@ with ##### Breaking - The native iOS bridge uses [Braze iOS SDK 3.14.0](https://github.com/Appboy/appboy-ios-sdk/blob/master/CHANGELOG.md#3140). -- The native Android bridge uses [Braze Android SDK 3.2.1](https://github.com/Appboy/appboy-android-sdk/blob/master/CHANGELOG.md#321). +- The native Android bridge uses [Braze Android SDK 3.2.1](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#321). ##### Added - Adds `addAlias()` to the public API interface. @@ -484,4 +496,4 @@ with ## 0.0.1 - Initial release. - The native iOS bridge uses [Braze iOS SDK 3.12.0](https://github.com/Appboy/appboy-ios-sdk/releases/tag/3.12.0). -- The native Android bridge uses [Braze Android SDK 3.1.0](https://github.com/Appboy/appboy-android-sdk/blob/master/CHANGELOG.md#310). +- The native Android bridge uses [Braze Android SDK 3.1.0](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#310). diff --git a/android/build.gradle b/android/build.gradle index 14c7a90..00bd950 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -53,4 +53,10 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation "com.braze:android-sdk-ui:30.3.0" + + androidTestImplementation "org.mockito:mockito-android:3.12.4" + androidTestImplementation "junit:junit:4.13.2" + androidTestImplementation "org.mockito:mockito-core:3.12.4" + androidTestImplementation "org.mockito.kotlin:mockito-kotlin:3.2.0" + androidTestImplementation("androidx.test:runner:1.5.2") } diff --git a/android/src/androidTest/kotlin/FlutterConfigurationTest.kt b/android/src/androidTest/kotlin/FlutterConfigurationTest.kt new file mode 100644 index 0000000..ea59d53 --- /dev/null +++ b/android/src/androidTest/kotlin/FlutterConfigurationTest.kt @@ -0,0 +1,138 @@ +import android.content.Context +import android.content.res.Resources +import com.braze.brazeplugin.FlutterConfiguration +import com.braze.ui.inappmessage.InAppMessageOperation +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Test +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.mock + +class FlutterConfigurationTest { + + @Test + fun whenBooleanValueExistsInResources_isAutomaticInitializationEnabled_returnsValue() { + val key = "com_braze_flutter_enable_automatic_integration_initializer" + val testResId = 1234 + val value = false + val testPackageName = "foo.bar.braze" + val mockResources = mock() { + on { getIdentifier(key, "bool", testPackageName) } doReturn 1234 + on { getBoolean(testResId) } doReturn value + } + + val context: Context = mock() { + on { resources } doReturn mockResources + on { packageName } doReturn testPackageName + } + val flutterConfiguration = FlutterConfiguration(context) + assertEquals( + value, + flutterConfiguration.isAutomaticInitializationEnabled() + ) + } + + @Test + fun whenBooleanValueDoesNotExistInResources_isAutomaticInitializationEnabled_returnsTrue() { + val key = "com_braze_flutter_enable_automatic_integration_initializer" + val testResId = 1234 + val testPackageName = "foo.bar.braze" + val mockResources = mock() { + on { getIdentifier(key, "bool", testPackageName) } doReturn 0 + } + + val context: Context = mock() { + on { resources } doReturn mockResources + on { packageName } doReturn testPackageName + } + val flutterConfiguration = FlutterConfiguration(context) + assertTrue( + flutterConfiguration.isAutomaticInitializationEnabled() + ) + } + + @Test + fun whenStringValueExistsInResources_automaticIntegrationInAppMessageOperation_returnsValue() { + val key = "com_braze_flutter_automatic_integration_iam_operation" + val testResId = 1234 + val value = "DISCARD" + val testPackageName = "foo.bar.braze" + val mockResources = mock() { + on { getIdentifier(key, "string", testPackageName) } doReturn 1234 + on { getString(testResId) } doReturn value + } + + val context: Context = mock() { + on { resources } doReturn mockResources + on { packageName } doReturn testPackageName + } + val flutterConfiguration = FlutterConfiguration(context) + assertEquals( + InAppMessageOperation.DISCARD, + flutterConfiguration.automaticIntegrationInAppMessageOperation() + ) + } + + @Test + fun whenStringValueDoesNotExistInResources_automaticIntegrationInAppMessageOperation_returnsDisplayNow() { + val key = "com_braze_flutter_automatic_integration_iam_operation" + val testPackageName = "foo.bar.braze" + val mockResources = mock() { + on { getIdentifier(key, "string", testPackageName) } doReturn 1234 + } + + val context: Context = mock() { + on { resources } doReturn mockResources + on { packageName } doReturn testPackageName + } + val flutterConfiguration = FlutterConfiguration(context) + assertEquals( + InAppMessageOperation.DISPLAY_NOW, + flutterConfiguration.automaticIntegrationInAppMessageOperation() + ) + } + + @Test + fun whenStringValueIsGarbage_automaticIntegrationInAppMessageOperation_returnsDisplayNow() { + val key = "com_braze_flutter_automatic_integration_iam_operation" + val testResId = 1234 + val value = "yeet_it" + val testPackageName = "foo.bar.braze" + val mockResources = mock() { + on { getIdentifier(key, "string", testPackageName) } doReturn 1234 + on { getString(testResId) } doReturn value + } + + val context: Context = mock() { + on { resources } doReturn mockResources + on { packageName } doReturn testPackageName + } + val flutterConfiguration = FlutterConfiguration(context) + assertEquals( + InAppMessageOperation.DISPLAY_NOW, + flutterConfiguration.automaticIntegrationInAppMessageOperation() + ) + } + + @Test + fun whenStringValueIsMixedCaseInResources_automaticIntegrationInAppMessageOperation_returnsValue() { + val key = "com_braze_flutter_automatic_integration_iam_operation" + val testResId = 1234 + val value = "DiSpLay_LaTeR" + val testPackageName = "foo.bar.braze" + val mockResources = mock() { + on { getIdentifier(key, "string", testPackageName) } doReturn 1234 + on { getString(testResId) } doReturn value + } + + val context: Context = mock() { + on { resources } doReturn mockResources + on { packageName } doReturn testPackageName + } + val flutterConfiguration = FlutterConfiguration(context) + assertEquals( + InAppMessageOperation.DISPLAY_LATER, + flutterConfiguration.automaticIntegrationInAppMessageOperation() + ) + } +} diff --git a/android/src/main/kotlin/com/braze/brazeplugin/BrazePlugin.kt b/android/src/main/kotlin/com/braze/brazeplugin/BrazePlugin.kt index c0419ed..9662958 100644 --- a/android/src/main/kotlin/com/braze/brazeplugin/BrazePlugin.kt +++ b/android/src/main/kotlin/com/braze/brazeplugin/BrazePlugin.kt @@ -41,7 +41,7 @@ class BrazePlugin : MethodCallHandler, FlutterPlugin, ActivityAware { private lateinit var context: Context private lateinit var channel: MethodChannel - private lateinit var flutterCachedConfiguration: FlutterCachedConfiguration + private lateinit var flutterConfiguration: FlutterConfiguration private var activity: Activity? = null //-- @@ -49,7 +49,7 @@ class BrazePlugin : MethodCallHandler, FlutterPlugin, ActivityAware { //-- private fun initPlugin(context: Context, messenger: BinaryMessenger) { - flutterCachedConfiguration = FlutterCachedConfiguration(context, false) + flutterConfiguration = FlutterConfiguration(context) val channel = MethodChannel(messenger, "braze_plugin") channel.setMethodCallHandler(this) this.context = context @@ -225,9 +225,9 @@ class BrazePlugin : MethodCallHandler, FlutterPlugin, ActivityAware { override fun onAttachedToActivity(binding: ActivityPluginBinding) { this.activity = binding.activity - if (IntegrationInitializer.isUninitialized && flutterCachedConfiguration.isAutomaticInitializationEnabled()) { + if (IntegrationInitializer.isUninitialized && flutterConfiguration.isAutomaticInitializationEnabled()) { brazelog(I) { "Running Flutter BrazePlugin automatic initialization" } - this.activity?.application?.let { IntegrationInitializer.initializePlugin(it, flutterCachedConfiguration) } + this.activity?.application?.let { IntegrationInitializer.initializePlugin(it, flutterConfiguration) } } } @@ -572,7 +572,7 @@ class BrazePlugin : MethodCallHandler, FlutterPlugin, ActivityAware { val pushToken = call.argument("pushToken") Braze.getInstance(context).registeredPushToken = pushToken } - "getInstallTrackingId" -> { + "getDeviceId" -> { result.success(Braze.getInstance(context).deviceId) } "setGoogleAdvertisingId" -> { diff --git a/android/src/main/kotlin/com/braze/brazeplugin/FlutterCachedConfiguration.kt b/android/src/main/kotlin/com/braze/brazeplugin/FlutterCachedConfiguration.kt deleted file mode 100644 index b098029..0000000 --- a/android/src/main/kotlin/com/braze/brazeplugin/FlutterCachedConfiguration.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.braze.brazeplugin - -import android.content.Context -import com.braze.configuration.CachedConfigurationProvider -import com.braze.ui.inappmessage.InAppMessageOperation - -class FlutterCachedConfiguration(context: Context, useCache: Boolean) : CachedConfigurationProvider(context, useCache) { - companion object { - private const val ENABLE_AUTOMATIC_INTEGRATION_INITIALIZER = "com_braze_flutter_enable_automatic_integration_initializer" - private const val AUTOMATIC_INTEGRATION_IAM_OPERATION = "com_braze_flutter_automatic_integration_iam_operation" - private val IAM_OPERATION_ENUM_MAP = InAppMessageOperation.values().associateBy { it.name } - } - - fun isAutomaticInitializationEnabled(): Boolean = getBooleanValue(ENABLE_AUTOMATIC_INTEGRATION_INITIALIZER, true) - - fun automaticIntegrationInAppMessageOperation(): InAppMessageOperation { - val value = getStringValue(AUTOMATIC_INTEGRATION_IAM_OPERATION, "")?.uppercase() - return IAM_OPERATION_ENUM_MAP[value] ?: InAppMessageOperation.DISPLAY_NOW - } -} diff --git a/android/src/main/kotlin/com/braze/brazeplugin/FlutterConfiguration.kt b/android/src/main/kotlin/com/braze/brazeplugin/FlutterConfiguration.kt new file mode 100644 index 0000000..942e2ed --- /dev/null +++ b/android/src/main/kotlin/com/braze/brazeplugin/FlutterConfiguration.kt @@ -0,0 +1,46 @@ +package com.braze.brazeplugin + +import android.annotation.SuppressLint +import android.content.Context +import com.braze.ui.inappmessage.InAppMessageOperation + +class FlutterConfiguration(private val context: Context) { + companion object { + private const val ENABLE_AUTOMATIC_INTEGRATION_INITIALIZER = + "com_braze_flutter_enable_automatic_integration_initializer" + private const val AUTOMATIC_INTEGRATION_IAM_OPERATION = "com_braze_flutter_automatic_integration_iam_operation" + private val IAM_OPERATION_ENUM_MAP = InAppMessageOperation.values().associateBy { it.name } + private const val MISSING_RESOURCE_IDENTIFIER = 0 + } + + @SuppressLint("DiscouragedApi") + fun isAutomaticInitializationEnabled(): Boolean { + val defaultValue = true + val resId = context.resources.getIdentifier(ENABLE_AUTOMATIC_INTEGRATION_INITIALIZER, "bool", context.packageName) + if (resId == MISSING_RESOURCE_IDENTIFIER) { + return defaultValue + } + + return try { + context.resources.getBoolean(resId) + } catch (e: Exception) { + defaultValue + } + } + + @SuppressLint("DiscouragedApi") + fun automaticIntegrationInAppMessageOperation(): InAppMessageOperation { + val defaultValue = InAppMessageOperation.DISPLAY_NOW + val resId = context.resources.getIdentifier(AUTOMATIC_INTEGRATION_IAM_OPERATION, "string", context.packageName) + if (resId == MISSING_RESOURCE_IDENTIFIER) { + return defaultValue + } + + return try { + val value = context.resources.getString(resId).uppercase() + IAM_OPERATION_ENUM_MAP[value] ?: defaultValue + } catch (e: Exception) { + defaultValue + } + } +} diff --git a/android/src/main/kotlin/com/braze/brazeplugin/IntegrationInitializer.kt b/android/src/main/kotlin/com/braze/brazeplugin/IntegrationInitializer.kt index f111231..edd68e2 100644 --- a/android/src/main/kotlin/com/braze/brazeplugin/IntegrationInitializer.kt +++ b/android/src/main/kotlin/com/braze/brazeplugin/IntegrationInitializer.kt @@ -20,7 +20,7 @@ object IntegrationInitializer { private var featureFlagsUpdatedSubscriber: IEventSubscriber? = null private var pushNotificationsUpdatedSubscriber: IEventSubscriber? = null - internal fun initializePlugin(application: Application, config: FlutterCachedConfiguration) { + internal fun initializePlugin(application: Application, config: FlutterConfiguration) { application.registerActivityLifecycleCallbacks(BrazeActivityLifecycleCallbackListener()) val ctx = application.applicationContext subscribeToContentCardsUpdatedEvent(ctx) diff --git a/example/android/app/src/main/kotlin/braze/com/brazepluginexample/MainActivity.kt b/example/android/app/src/main/kotlin/braze/com/brazepluginexample/MainActivity.kt index 547461c..ab78ec0 100644 --- a/example/android/app/src/main/kotlin/braze/com/brazepluginexample/MainActivity.kt +++ b/example/android/app/src/main/kotlin/braze/com/brazepluginexample/MainActivity.kt @@ -2,11 +2,14 @@ package braze.com.brazepluginexample import android.content.Intent import android.os.Bundle +import android.os.StrictMode +import android.os.StrictMode.ThreadPolicy import com.braze.Braze import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine -import io.flutter.plugins.GeneratedPluginRegistrant import io.flutter.plugin.common.MethodChannel +import io.flutter.plugins.GeneratedPluginRegistrant + class MainActivity : FlutterActivity() { override fun configureFlutterEngine(flutterEngine: FlutterEngine) { @@ -15,6 +18,15 @@ class MainActivity : FlutterActivity() { } override fun onCreate(savedInstanceState: Bundle?) { + StrictMode.setThreadPolicy( + ThreadPolicy.Builder() + .detectDiskReads() + .detectDiskWrites() + .detectNetwork() // or .detectAll() for all detectable problems + .penaltyLog() + .build() + ) + super.onCreate(savedInstanceState) handleDeepLink(intent) } diff --git a/example/android/app/src/main/res/values/braze.xml b/example/android/app/src/main/res/values/braze.xml index e923246..feb21a5 100644 --- a/example/android/app/src/main/res/values/braze.xml +++ b/example/android/app/src/main/res/values/braze.xml @@ -4,6 +4,8 @@ 0fc32ae3-88b4-48b8-91f4-a0e2003b08ec STAGING + + true 901477453852 diff --git a/example/integration_test/braze_plugin_integration_test.dart b/example/integration_test/braze_plugin_integration_test.dart index a83fafb..f050a11 100644 --- a/example/integration_test/braze_plugin_integration_test.dart +++ b/example/integration_test/braze_plugin_integration_test.dart @@ -7,8 +7,8 @@ void main() { testWidgets('Can initialize plugin', (WidgetTester tester) async { BrazePlugin plugin = BrazePlugin(); - Future installTrackingId = plugin.getInstallTrackingId(); + Future getDeviceId = plugin.getDeviceId(); expect(plugin, isNotNull); - expect(installTrackingId, isNotNull); + expect(getDeviceId, isNotNull); }); } diff --git a/example/lib/main.dart b/example/lib/main.dart index 6a47093..e8f914a 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -119,7 +119,7 @@ class BrazeFunctionsState extends State { if (_enabled == "") { // This is a hack to determine the enabled state of the Braze API // Not recommended for use in production - _braze.getInstallTrackingId().then((result) { + _braze.getDeviceId().then((result) { if (result == "") { this.setState(() { _enabled = "DISABLED"; @@ -564,7 +564,17 @@ class BrazeFunctionsState extends State { }, ), TextButton( - child: const Text('GET INSTALL TRACKING ID'), + child: const Text('GET DEVICE ID'), + onPressed: () { + _braze.getDeviceId().then((result) { + ScaffoldMessenger.of(context).showSnackBar(new SnackBar( + content: new Text("Device ID: " + result), + )); + }); + }, + ), + TextButton( + child: const Text('GET INSTALL TRACKING ID(deprecated)'), onPressed: () { _braze.getInstallTrackingId().then((result) { ScaffoldMessenger.of(context).showSnackBar(new SnackBar( diff --git a/ios/Classes/BrazePlugin.swift b/ios/Classes/BrazePlugin.swift index 5198ada..dca9505 100644 --- a/ios/Classes/BrazePlugin.swift +++ b/ios/Classes/BrazePlugin.swift @@ -50,7 +50,7 @@ public class BrazePlugin: NSObject, FlutterPlugin, BrazeSDKAuthDelegate { case "setSdkAuthenticationDelegate": BrazePlugin.braze?.sdkAuthDelegate = self - case "getInstallTrackingId": + case "getDeviceId": if let deviceId = BrazePlugin.braze?.deviceId { result(deviceId) } diff --git a/ios/braze_plugin.podspec b/ios/braze_plugin.podspec index 4f6c72a..66bd848 100644 --- a/ios/braze_plugin.podspec +++ b/ios/braze_plugin.podspec @@ -20,9 +20,9 @@ Pod::Spec.new do |s| s.static_framework = true s.dependency 'Flutter' - s.dependency 'BrazeKit', '~> 8.4.0' - s.dependency 'BrazeLocation', '~> 8.4.0' - s.dependency 'BrazeUI', '~> 8.4.0' + s.dependency 'BrazeKit', '~> 9.0.0' + s.dependency 'BrazeLocation', '~> 9.0.0' + s.dependency 'BrazeUI', '~> 9.0.0' s.ios.deployment_target = '12.0' end diff --git a/lib/braze_plugin.dart b/lib/braze_plugin.dart index 9291cb2..9158022 100644 --- a/lib/braze_plugin.dart +++ b/lib/braze_plugin.dart @@ -538,10 +538,18 @@ class BrazePlugin { _channel.invokeMethod('removeFromSubscriptionGroup', params); } - /// Gets the install tracking id. - Future getInstallTrackingId() { + /// Gets the device id. + Future getDeviceId() { return _channel - .invokeMethod('getInstallTrackingId') + .invokeMethod('getDeviceId') + .then((dynamic result) => result); + } + + /// Gets the install tracking id. + @Deprecated('Use getDeviceId instead.') + Future getInstallTrackingId() { + return _channel + .invokeMethod('getDeviceId') .then((dynamic result) => result); } @@ -559,7 +567,8 @@ class BrazePlugin { /// Sets ad tracking configuration for the current user. /// /// - `googleAdvertisingId` is required on Android. - void setAdTrackingEnabled(bool adTrackingEnabled, String? googleAdvertisingId) { + void setAdTrackingEnabled( + bool adTrackingEnabled, String? googleAdvertisingId) { final Map params = { "adTrackingEnabled": adTrackingEnabled }; diff --git a/pubspec.yaml b/pubspec.yaml index 54d8278..89c96ec 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: braze_plugin description: This is the Braze plugin for Flutter. Effective marketing automation is an essential part of successfully scaling and managing your business. -version: 9.0.0 +version: 10.0.0 homepage: https://www.braze.com/ repository: https://github.com/braze-inc/braze-flutter-sdk diff --git a/test/braze_plugin_test.dart b/test/braze_plugin_test.dart index efaad34..a816b10 100644 --- a/test/braze_plugin_test.dart +++ b/test/braze_plugin_test.dart @@ -9,7 +9,7 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); final List log = []; - final String mockInstallTrackingId = '_test_install_tracking_id_'; + final String mockDeviceId = '_test_device_id_'; final String mockFeatureFlagJson = "{\"id\":\"test\",\"enabled\":true,\"properties\":{\"stringkey\":{\"type\":\"string\",\"value\":\"stringValue\"},\"booleankey\":{\"type\":\"boolean\",\"value\": true },\"number1key\":{\"type\":\"number\",\"value\": 4 },\"number2key\":{\"type\":\"number\",\"value\": 5.1}}}"; @@ -26,8 +26,9 @@ void main() { log.add(methodCall); // If needed to mock return values: switch (methodCall.method) { + case 'getDeviceId': case 'getInstallTrackingId': - return mockInstallTrackingId; + return mockDeviceId; case 'getAllFeatureFlags': return List.generate(1, (index) => mockFeatureFlagJson); case 'getFeatureFlagByID': @@ -210,16 +211,28 @@ void main() { ]); }); + test('should call getDeviceId', () async { + BrazePlugin _braze = new BrazePlugin(); + final result = await _braze.getDeviceId(); + expect(log, [ + isMethodCall( + 'getDeviceId', + arguments: null, + ) + ]); + expect(result, mockDeviceId); + }); + test('should call getInstallTrackingId', () async { BrazePlugin _braze = new BrazePlugin(); final result = await _braze.getInstallTrackingId(); expect(log, [ isMethodCall( - 'getInstallTrackingId', + 'getDeviceId', arguments: null, ) ]); - expect(result, mockInstallTrackingId); + expect(result, mockDeviceId); }); test('should call addAlias', () {