Skip to content

Commit

Permalink
Release Flutter SDK version 4.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
hokstuff committed Mar 14, 2023
1 parent b054a75 commit 3fea51f
Show file tree
Hide file tree
Showing 14 changed files with 72 additions and 102 deletions.
24 changes: 23 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion android/.idea/.name

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
2 changes: 1 addition & 1 deletion example/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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'
2 changes: 1 addition & 1 deletion example/ios/Flutter/AppFrameworkInfo.plist
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>9.0</string>
<string>11.0</string>
</dict>
</plist>
4 changes: 3 additions & 1 deletion example/ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objectVersion = 54;
objects = {

/* Begin PBXBuildFile section */
Expand Down Expand Up @@ -215,6 +215,7 @@
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
Expand All @@ -229,6 +230,7 @@
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
Expand Down
4 changes: 1 addition & 3 deletions example/ios/Runner/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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?

Expand All @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions example/ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,7 @@
<false/>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
</plist>
37 changes: 6 additions & 31 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ class BrazeFunctionsState extends State<BrazeFunctions> {
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});

Expand Down Expand Up @@ -239,20 +243,6 @@ class BrazeFunctionsState extends State<BrazeFunctions> {
},
),
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: () {
Expand Down Expand Up @@ -283,20 +273,6 @@ class BrazeFunctionsState extends State<BrazeFunctions> {
_braze.launchContentCards();
},
),
TextButton(
child: const Text('SET CONTENT CARDS CALLBACK'),
onPressed: () {
// ignore: deprecated_member_use
_braze.setBrazeContentCardsCallback(
(List<BrazeContentCard> 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: () {
Expand Down Expand Up @@ -439,8 +415,7 @@ class BrazeFunctionsState extends State<BrazeFunctions> {
);
}

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:
Expand All @@ -460,7 +435,7 @@ class BrazeFunctionsState extends State<BrazeFunctions> {
}

void _contentCardsReceived(List<BrazeContentCard> 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."),
Expand Down
13 changes: 0 additions & 13 deletions ios/Classes/BrazePlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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)")
Expand All @@ -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)")
Expand Down
6 changes: 3 additions & 3 deletions ios/braze_plugin.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -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
68 changes: 24 additions & 44 deletions lib/braze_plugin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,8 @@ class BrazePlugin {
Map<String, bool>? _brazeCustomConfigs;
Function(BrazeSdkAuthenticationError)? _brazeSdkAuthenticationErrorHandler;

Function(BrazeInAppMessage)? _brazeInAppMessageHandler;
// To be used alongside `replayCallbacksConfigKey`
final List<BrazeInAppMessage> _queuedInAppMessages = [];

Function(List<BrazeContentCard>)? _brazeContentCardHandler;
final List<BrazeContentCard> _queuedContentCards = [];

/// Broadcast stream to listen for in-app messages.
Expand All @@ -24,15 +22,26 @@ class BrazePlugin {
StreamController<List<BrazeContentCard>> contentCardsStreamController =
StreamController<List<BrazeContentCard>>.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<BrazeContentCard>)? contentCardsHandler,
Map<String, bool>? 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);
Expand Down Expand Up @@ -70,39 +79,13 @@ class BrazePlugin {
return subscription;
}

/// Sets a callback to receive in-app message data from Braze.
@Deprecated(
'Use subscribeToInAppMessages(void onEvent(List<BrazeContentCard> 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) {
_channel.invokeMethod('setSdkAuthenticationDelegate');
_brazeSdkAuthenticationErrorHandler = callback;
}

/// Sets a callback to receive Content Card data from Braze.
@Deprecated(
'Use subscribeToContentCards(void onEvent(List<BrazeContentCard> contentCard)) instead.')
void setBrazeContentCardsCallback(Function(List<BrazeContentCard>) 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.
///
Expand Down Expand Up @@ -515,15 +498,14 @@ class BrazePlugin {
return Future<void>.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<void>.value();

case "handleBrazeContentCards":
Expand All @@ -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<void>.value();

case "handleSdkAuthenticationError":
Expand Down
7 changes: 6 additions & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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
1 change: 0 additions & 1 deletion test/braze_plugin_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down

0 comments on commit 3fea51f

Please sign in to comment.