diff --git a/CHANGELOG.md b/CHANGELOG.md
index f9dd059..d89c0ed 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,25 @@
+## 4.0.0
+
+> Starting with this release, this SDK will use [Semantic Versioning](https://semver.org/).
+
+##### Breaking
+- Fixes the behavior in the iOS bridge introduced in version `3.0.0` when logging clicks for in-app messages and content cards. Calling `logClick` now only sends a click event for metrics, instead of both sending a click event as well as redirecting to the associated `url` field.
+ - For instance, to log a content card click and redirect to a URL, you will need two commands:
+ ```
+ braze.logContentCardClicked(contentCard);
+
+ // Your own custom implementation
+ Linking.openUrl(contentCard.url);
+ ```
+ - This brings the iOS behavior to match version `2.x` and bring parity with Android's behavior.
+- Removes `setBrazeInAppMessageCallback()` and `setBrazeContentCardsCallback()` in favor of subscribing via streams.
+ - Reference our [sample app](https://github.com/braze-inc/braze-flutter-sdk/blob/master/example/lib/main.dart) for an example on how to use [`subscribeToInAppMessages()`](https://www.braze.com/docs/developer_guide/platform_integration_guides/flutter/inapp_messages/#receiving-in-app-message-data) or [`subscribeToContentCards()`](https://www.braze.com/docs/developer_guide/platform_integration_guides/flutter/content_cards/#receiving-content-card-data).
+
+##### Changed
+- The native Android bridge uses [Braze Android SDK 24.3.0](https://github.com/braze-inc/braze-android-sdk/blob/master/CHANGELOG.md#2430).
+- The native iOS bridge uses [Braze iOS SDK 5.11.2](https://github.com/braze-inc/braze-swift-sdk/blob/main/CHANGELOG.md#5112).
+- Improves behavior when using `replayCallbacksConfigKey` alongside having subscriptions to in-app messages or content cards via streams.
+
## 3.1.0
##### Breaking
@@ -57,7 +79,7 @@
##### Changed
- Updates the iOS layer to use Swift. `BrazePlugin.h` and `BrazePlugin.m` are now consolidated to `BrazePlugin.swift`.
-- Deprecates `setBrazeInAppMessageCallback()` and `setBrazeContentCardsCallback()` in favor of the subscribing via streams.
+- Deprecates `setBrazeInAppMessageCallback()` and `setBrazeContentCardsCallback()` in favor of subscribing via streams.
## 2.5.0
diff --git a/android/.idea/.name b/android/.idea/.name
index 7316a8e..58432f7 100644
--- a/android/.idea/.name
+++ b/android/.idea/.name
@@ -1 +1 @@
-_android
\ No newline at end of file
+braze_plugin
\ No newline at end of file
diff --git a/android/build.gradle b/android/build.gradle
index e12bbb3..92683c8 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -52,5 +52,5 @@ android {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
- implementation "com.appboy:android-sdk-ui:24.2.0"
+ implementation "com.appboy:android-sdk-ui:24.3.0"
}
diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle
index 2daf368..3556f09 100644
--- a/example/android/app/build.gradle
+++ b/example/android/app/build.gradle
@@ -80,7 +80,7 @@ dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'androidx.multidex:multidex:2.0.0'
- implementation "com.appboy:android-sdk-ui:24.2.0"
+ implementation "com.appboy:android-sdk-ui:24.3.0"
implementation "com.google.firebase:firebase-messaging:+"
}
apply plugin: 'com.google.gms.google-services'
diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist
index 8d4492f..9625e10 100644
--- a/example/ios/Flutter/AppFrameworkInfo.plist
+++ b/example/ios/Flutter/AppFrameworkInfo.plist
@@ -21,6 +21,6 @@
CFBundleVersion
1.0
MinimumOSVersion
- 9.0
+ 11.0
diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj
index b991291..8e02440 100644
--- a/example/ios/Runner.xcodeproj/project.pbxproj
+++ b/example/ios/Runner.xcodeproj/project.pbxproj
@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
- objectVersion = 46;
+ objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
@@ -215,6 +215,7 @@
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
+ alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
@@ -229,6 +230,7 @@
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
+ alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
diff --git a/example/ios/Runner/AppDelegate.swift b/example/ios/Runner/AppDelegate.swift
index 20c2d2c..3a8e47e 100644
--- a/example/ios/Runner/AppDelegate.swift
+++ b/example/ios/Runner/AppDelegate.swift
@@ -12,8 +12,6 @@ let brazeEndpoint = "sondheim.appboy.com"
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate, BrazeInAppMessageUIDelegate {
- static var braze: Braze? = nil
-
// The subscription needs to be retained to be active
var contentCardsSubscription: Braze.Cancellable?
@@ -28,7 +26,7 @@ let brazeEndpoint = "sondheim.appboy.com"
configuration.sessionTimeout = 1
configuration.triggerMinimumTimeInterval = 0
configuration.location.automaticLocationCollection = true
- configuration.location.brazeLocation = BrazeLocation()
+ configuration.location.brazeLocationProvider = BrazeLocationProvider()
configuration.logger.level = .debug
let braze = BrazePlugin.initBraze(configuration)
diff --git a/example/ios/Runner/Info.plist b/example/ios/Runner/Info.plist
index dd3751e..9ca9d23 100644
--- a/example/ios/Runner/Info.plist
+++ b/example/ios/Runner/Info.plist
@@ -50,5 +50,7 @@
CADisableMinimumFrameDurationOnPhone
+ UIApplicationSupportsIndirectInputEvents
+
diff --git a/example/lib/main.dart b/example/lib/main.dart
index 7faf1c4..373300f 100644
--- a/example/lib/main.dart
+++ b/example/lib/main.dart
@@ -35,6 +35,10 @@ class BrazeFunctionsState extends State {
StreamSubscription inAppMessageStreamSubscription;
StreamSubscription contentCardsStreamSubscription;
+ // Change to `true` to automatically log clicks, button clicks,
+ // and impressions for in-app messages and content cards.
+ final automaticallyInteract = false;
+
void initState() {
_braze = new BrazePlugin(customConfigs: {replayCallbacksConfigKey: true});
@@ -239,20 +243,6 @@ class BrazeFunctionsState extends State {
},
),
SectionHeader("In-app Messages"),
- TextButton(
- child: const Text('SET IN-APP MESSAGE CALLBACK'),
- onPressed: () {
- // ignore: deprecated_member_use
- _braze.setBrazeInAppMessageCallback(
- (BrazeInAppMessage inAppMessage) {
- _inAppMessageReceived(inAppMessage, prefix: "CALLBACK");
- });
- ScaffoldMessenger.of(context).showSnackBar(new SnackBar(
- content: new Text("In-app message callback set. "
- "In-app message data will appear in snackbars."),
- ));
- },
- ),
TextButton(
child: const Text('SUBSCRIBE VIA IN-APP MESSAGE STREAM'),
onPressed: () {
@@ -283,20 +273,6 @@ class BrazeFunctionsState extends State {
_braze.launchContentCards();
},
),
- TextButton(
- child: const Text('SET CONTENT CARDS CALLBACK'),
- onPressed: () {
- // ignore: deprecated_member_use
- _braze.setBrazeContentCardsCallback(
- (List contentCards) {
- _contentCardsReceived(contentCards, prefix: "CALLBACK");
- });
- ScaffoldMessenger.of(context).showSnackBar(new SnackBar(
- content: new Text("Content Cards Callback set. "
- "Content Card data will appear in snackbars."),
- ));
- },
- ),
TextButton(
child: const Text('SUBSCRIBE VIA CONTENT CARDS STREAM'),
onPressed: () {
@@ -439,8 +415,7 @@ class BrazeFunctionsState extends State {
);
}
- void _inAppMessageReceived(BrazeInAppMessage inAppMessage,
- {String prefix, bool automaticallyInteract = false}) {
+ void _inAppMessageReceived(BrazeInAppMessage inAppMessage, {String prefix}) {
print("[$prefix] Received message: ${inAppMessage.toString()}");
ScaffoldMessenger.of(context).showSnackBar(new SnackBar(
content:
@@ -460,7 +435,7 @@ class BrazeFunctionsState extends State {
}
void _contentCardsReceived(List contentCards,
- {String prefix, bool automaticallyInteract = false}) {
+ {String prefix}) {
if (contentCards.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(new SnackBar(
content: new Text("Empty Content Cards update received."),
diff --git a/ios/Classes/BrazePlugin.swift b/ios/Classes/BrazePlugin.swift
index 8287ef9..7f328b1 100644
--- a/ios/Classes/BrazePlugin.swift
+++ b/ios/Classes/BrazePlugin.swift
@@ -9,9 +9,6 @@ public class BrazePlugin: NSObject, FlutterPlugin, BrazeDelegate {
public static var braze: Braze? = nil
- private static var inAppMessageIdsToContexts: [String: Braze.InAppMessage.Context] = [:]
- private static var contentCardIdsToContexts: [String: Braze.ContentCard.Context] = [:]
-
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "braze_plugin", binaryMessenger: registrar.messenger())
let instance = BrazePlugin()
@@ -481,11 +478,6 @@ public class BrazePlugin: NSObject, FlutterPlugin, BrazeDelegate {
do {
var inAppMessage: Braze.InAppMessage = try Braze.InAppMessage.init(inAppMessageRaw)
-
- // TODO: New context is being allocated each time, so can log duplicate impressions
- let context = Braze.InAppMessage.Context(message: inAppMessage, using: braze)
- inAppMessage.context = context
-
return inAppMessage
} catch {
print("Error parsing in-app message from jsonString: \(jsonString), error: \(error)")
@@ -499,11 +491,6 @@ public class BrazePlugin: NSObject, FlutterPlugin, BrazeDelegate {
do {
var contentCard: Braze.ContentCard = try Braze.ContentCard.init(contentCardRaw)
-
- // TODO: New context is being allocated each time, so can log duplicate impressions
- let context = Braze.ContentCard.Context(card: contentCard, using: braze)
- contentCard.context = context
-
return contentCard
} catch {
print("Error parsing Content Card from jsonString: \(jsonString), error: \(error)")
diff --git a/ios/braze_plugin.podspec b/ios/braze_plugin.podspec
index e39796e..149085b 100644
--- a/ios/braze_plugin.podspec
+++ b/ios/braze_plugin.podspec
@@ -14,9 +14,9 @@ Pod::Spec.new do |s|
s.static_framework = true
s.dependency 'Flutter'
- s.dependency 'BrazeKit', '~> 5.9.0'
- s.dependency 'BrazeLocation', '~> 5.9.0'
- s.dependency 'BrazeUI', '~> 5.9.0'
+ s.dependency 'BrazeKit', '~> 5.11.2'
+ s.dependency 'BrazeLocation', '~> 5.11.2'
+ s.dependency 'BrazeUI', '~> 5.11.2'
s.ios.deployment_target = '11.0'
end
diff --git a/lib/braze_plugin.dart b/lib/braze_plugin.dart
index 0939b0b..f02b2d8 100644
--- a/lib/braze_plugin.dart
+++ b/lib/braze_plugin.dart
@@ -10,10 +10,8 @@ class BrazePlugin {
Map? _brazeCustomConfigs;
Function(BrazeSdkAuthenticationError)? _brazeSdkAuthenticationErrorHandler;
- Function(BrazeInAppMessage)? _brazeInAppMessageHandler;
+ // To be used alongside `replayCallbacksConfigKey`
final List _queuedInAppMessages = [];
-
- Function(List)? _brazeContentCardHandler;
final List _queuedContentCards = [];
/// Broadcast stream to listen for in-app messages.
@@ -24,15 +22,26 @@ class BrazePlugin {
StreamController> contentCardsStreamController =
StreamController>.broadcast();
+ /// The plugin used to interface with all Braze APIs with optional parameters
+ /// specific customization.
+ ///
+ /// The [inAppMessageHandler] and [contentCardsHandler] can subscribe to
+ /// their respective streams at plugin initialization. These can also be
+ /// subscribed at a later time after initialization
BrazePlugin(
{Function(BrazeInAppMessage)? inAppMessageHandler,
Function(BrazeSdkAuthenticationError)? brazeSdkAuthenticationErrorHandler,
Function(List)? contentCardsHandler,
Map? customConfigs}) {
- _brazeInAppMessageHandler = inAppMessageHandler;
- _brazeSdkAuthenticationErrorHandler = brazeSdkAuthenticationErrorHandler;
- _brazeContentCardHandler = contentCardsHandler;
_brazeCustomConfigs = customConfigs;
+ _brazeSdkAuthenticationErrorHandler = brazeSdkAuthenticationErrorHandler;
+
+ if (inAppMessageHandler != null) {
+ subscribeToInAppMessages(inAppMessageHandler);
+ }
+ if (contentCardsHandler != null) {
+ subscribeToContentCards(contentCardsHandler);
+ }
// Called after setting up plugin settings
_channel.setMethodCallHandler(_handleBrazeData);
@@ -70,19 +79,6 @@ class BrazePlugin {
return subscription;
}
- /// Sets a callback to receive in-app message data from Braze.
- @Deprecated(
- 'Use subscribeToInAppMessages(void onEvent(List contentCard)) instead.')
- void setBrazeInAppMessageCallback(Function(BrazeInAppMessage) callback) {
- _brazeInAppMessageHandler = callback;
-
- if (_replayCallbacksConfigEnabled() && _queuedInAppMessages.isNotEmpty) {
- print("Replaying callback on previously queued Braze in-app messages.");
- _queuedInAppMessages.forEach((message) => callback(message));
- _queuedInAppMessages.clear();
- }
- }
-
/// Sets a callback to receive in-app message data from Braze.
void setBrazeSdkAuthenticationErrorCallback(
Function(BrazeSdkAuthenticationError) callback) {
@@ -90,19 +86,6 @@ class BrazePlugin {
_brazeSdkAuthenticationErrorHandler = callback;
}
- /// Sets a callback to receive Content Card data from Braze.
- @Deprecated(
- 'Use subscribeToContentCards(void onEvent(List contentCard)) instead.')
- void setBrazeContentCardsCallback(Function(List) callback) {
- _brazeContentCardHandler = callback;
-
- if (_replayCallbacksConfigEnabled() && _queuedContentCards.isNotEmpty) {
- print("Replaying callback on previously queued Braze content cards.");
- callback(_queuedContentCards);
- _queuedContentCards.clear();
- }
- }
-
/// Changes the current Braze userId.
/// If [sdkAuthSignature] is present, passes that token to the native layer.
///
@@ -515,15 +498,14 @@ class BrazePlugin {
return Future.value();
}
final inAppMessage = BrazeInAppMessage(inAppMessageString);
- if (_brazeInAppMessageHandler != null) {
- _brazeInAppMessageHandler!(inAppMessage);
- } else if (_replayCallbacksConfigEnabled()) {
- print("Braze in-app message callback not present. Adding to queue.");
+ if (inAppMessageStreamController.hasListener) {
+ inAppMessageStreamController.add(inAppMessage);
+ } else {
+ print(
+ "Braze in-app message subscription not present. Adding to queue.");
_queuedInAppMessages.add(inAppMessage);
}
- // Add valid in-app message to the stream.
- inAppMessageStreamController.add(inAppMessage);
return Future.value();
case "handleBrazeContentCards":
@@ -533,17 +515,15 @@ class BrazePlugin {
brazeCards.add(BrazeContentCard(card));
}
- if (_brazeContentCardHandler != null) {
- _brazeContentCardHandler!(brazeCards);
- } else if (_replayCallbacksConfigEnabled()) {
+ if (contentCardsStreamController.hasListener) {
+ contentCardsStreamController.add(brazeCards);
+ } else {
print(
- "Braze content card callback not present. Removing any queued cards and adding only the recent refresh.");
+ "Braze content card subscription not present. Removing any queued cards and adding only the recent refresh.");
_queuedContentCards.clear();
_queuedContentCards.addAll(brazeCards);
}
- // Add valid list of content cards to the stream.
- contentCardsStreamController.add(brazeCards);
return Future.value();
case "handleSdkAuthenticationError":
diff --git a/pubspec.yaml b/pubspec.yaml
index 84f6d50..0658ea5 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: 3.1.0
+version: 4.0.0
homepage: https://www.braze.com/
repository: https://github.com/braze-inc/braze-flutter-sdk
@@ -24,3 +24,8 @@ flutter:
pluginClass: BrazePlugin
ios:
pluginClass: BrazePlugin
+
+# Ignore warnings in the example app during package upload
+false_secrets:
+ - /example/android/app/google-services.json
+ - /example/ios/Runner/GoogleService-Info.plist
\ No newline at end of file
diff --git a/test/braze_plugin_test.dart b/test/braze_plugin_test.dart
index 176507e..f25f240 100644
--- a/test/braze_plugin_test.dart
+++ b/test/braze_plugin_test.dart
@@ -100,7 +100,6 @@ void main() {
});
test('should include isControl field', () {
- BrazePlugin _braze = new BrazePlugin();
String _data = '{"tp":"control"}';
BrazeContentCard _contentCard = new BrazeContentCard(_data);
expect(_contentCard.isControl, equals(true));