braze-flutter-sdk
braze-flutter-sdk copied to clipboard
[Bug]: Content Cards fetching and dismissing doesn't work consistently on iOS
Which Platforms?
iOS
Which Flutter Version?
3.24.3
Which Braze Flutter SDK version?
13.0.0
Repro Rate
100
Steps To Reproduce
Reproduction is very simple; I followed the steps in the documentation for implementing Content Cards.
In main.dart, I initialize Braze and set the User ID (braze.changeUser).
Then on the next screen, I subscribe to the Content Cards Stream and refresh them to get the latest content cards.
main.dart
final brazePlugin =
BrazePlugin(customConfigs: {replayCallbacksConfigKey: true});
...
braze.changeUser(userId);
...
Expected Behavior
The expected behavior is: 1- It should work exactly the same on Android and iOS, as it is not an OS-specific feature.
2- The Content Cards subscription, if updated, should return all active Content Cards, not just the new ones.
3- The Content Cards Dismiss should be applied to both Cached and Server cards.
Actual Incorrect Behavior
On Android, the Content Cards are displayed (old ones that are still active and new ones), while on iOS, only the new ones are displayed, and the old ones that are active are not.
Temporarily, to fix this, I merge the cached content cards and the "new" ones.
Meanwhile, the dismiss functionality also doesn't work consistently on iOS. Apparently, after dismissing a Content Card, it isn't marked as dismissed in the cached Content Cards.
To fix this problem, I simply store a list of the Content Card IDs that the user dismissed.
The strange thing about all this is that on Android everything works perfectly without having to do any workaround.
Verbose Logs
The only log that may worth sharing is the following, maybe it's related to this issue:
flutter: Braze content card subscription not present. Removing any queued cards and adding only the recent refresh.
This is only showing when running the App in iOS.
Additional Information
No response
Hi @julianfalcionelli, thanks for raising these concerns. To confirm, is the behavior you're seeing strictly related to the model-based subscriptions and dismissal methods (i.e. you are using those to build your own custom UI), or are you using the default out-of-the-box UI provided by Braze?
Hi @jerielng, this is happening for the subscription and dismissal methods. I am rendering my own custom UI.
Thanks for sharing! I'll raise your point on dismissals with the team to discuss between iOS and Android. For context, that behavior you are describing matches what we have written here about the underlying Swift SDK. We'll keep you updated on this note.
However, I'm not clear on what you mean with this point:
On Android, the Content Cards are displayed (old ones that are still active and new ones), while on iOS, only the new ones are displayed, and the old ones that are active are not.
Could you clarify the reproduction steps you are observing, perhaps describing a sample list of cards going through a before and after state of the subscriber trigger? When a refresh occurs and the subscriber is triggered, we expect the list returned to be the source of truth (with the latest states merged from both the local and server).
Hi @jerielng ,
It's really easy to reproduce it, like I just tried the following:
1- Braze: Trigger Content Card A 2- Braze: Trigger Content Card B 3- Open iOS App: Content Card A and B showing 4- Dismiss Content Card B 5- Close iOS App 6- Re-open iOS App 7- Non-Content Cards are shown -> Wrong
Doing the same in Android and step 7 results in only Content Card A showing -> Correct
Then in the iOS App, after a few "refresh content cards" calls the Card A appears, but initially it doesn't.
Then on iOS, I dimiss this pending Content Card A, and when I refreshed (make "refresh content cards") while in the app, Content Card A was displayed again. This didn't happen on Android ✅ .
Could it be related to the "ChangeUser" not being synchronous and on iOS taking a long time and causing something undesirable in terms of which Cards are shown to the User? I don't think so because I even added delays to make sure all this Content Card subscriptions happen after the ChangeUser.
As I said before, I achieved the desired behavior by merging the cached content cards and keeping an in-memory list of the dismissed content cards to prevent them from being displayed (on iOS).
Thanks for the clarification @julianfalcionelli - as mentioned, we'll raise some of those dismissal concerns with the team for further discussion on platform alignment. This may not be a trivial change, so it may take some time to solution, though it sounds like you have a workaround in the meantime.
As for the refreshing, the behavior you described sounds like something that was recently fixed in the 12.0.0 version of the underlying Swift SDK:
- Fixes an issue where Braze.ContentCards.subscribeToUpdates(_:) would not call the update closure whenever a sync occurred without any changes in the Content Cards data.
- Previously, the update closure would only be called when the sync resulted in a change.
We're hoping to push that version to this Flutter SDK shortly and will keep you updated when it has gone out.
Great, thanks @jerielng !
Hey @julianfalcionelli, the 14.0.0 version of the Flutter SDK has been released with the fix to the Swift subscribe method mentioned above if you are able to test it to see if it resolves your concerns.
As for the dismissal behavior, it is still on our radar but will take a longer time horizon to solution, but we will keep you posted with any updates as we have them!
Great, thanks for the update @jerielng .
It still seems like the behavior differs between Android and iOS.
brazePlugin.contentCardsStreamController.stream
On iOS the stream does not emit anything upon first subscription, whereas on Android it does.
EDIT: Actually, the stream doesn't emit anything ever. Even after requested refresh when I know there is a new content card lined up. Just to be clear, everything works just fine on Android.
I have the same issue of not receving the cards in iOs, or it was receiving only the first time, but not immediately, and sometimes, and then it disappear. Android works very well instead. @andreasmpet have you found the reason of the issue?
Yeah! I was able to solve this by adding the following code to my Swift code.
contentCardsSubscription = braze.contentCards.subscribeToUpdates { contentCards in
BrazePlugin.processContentCards(contentCards)
}