Open igorjacauna opened 2 years ago
Thanks for reaching out, @igorjacauna. To make sure that we're on the same page, could you provide a minimal repro or code snippet to see how all the 3 messages appear in your app? Also, is the issue reproducible using the latest version?
Hi @rizafran we discovery that the problem is with any type of message. If we only mark it as read, the next message does not shows up, only if we mark as clicked or dismissed.
Just for comparison of behavior, on Android the flow has no problem, the messages from stack show up when we trigger the event screen_event
I have configured 3 messages that has the event screen_event
bind to each one:
On screen we hava a button that fire the event screen_event
and when we shows a Card message, we shows a button that mark it as clicked
We click on button that fire the screen_event
and the expected behavior is the messages shows up in order. But when Card shows up the flow stuck on it. And the 3rd message only shows if we mark the Card message as clicked.
screen_event
screen_event
screen_event
screen_event
Every time a message shows up we try to mark it as read. No error shows up on Console
Thanks for sharing the steps, @igorjacauna. As mentioned, is it possible for you to provide a minimal repro that I can run locally or a code snippet on how you display the 3 types of messages? Also, is it reproducible using the latest SDK version?
Hi @rizafran, we tried with the latest SDK version and the problem is present there too.
In our code we have two classes:
InAppMessageDisplay
: Receives the message from FirebaseInAppMessageManager
: Handle which data and fire event to our ReactNative layer to shows the messageTo clarify, we use this with ReactNative using Native Modules. And every time we receive a message we send it to ReactNative and when it is rendered on it we call markAsImpressionDetected
and if we fire the event to get next message without call markAsClicked
or markAsDismissed
nothing is coming from Firebase. Only if we call markAsClicked
or markAsDismissed
. On Android this not happen, it works if we call only markAsImpressionDetected
AppDelegate.m
we set our custom Display classInAppMessageDisplay *display = [[InAppMessageDisplay alloc] init];
[FIRInAppMessaging inAppMessaging].messageDisplayComponent = display;
InAppMessageDisplay
#import <Foundation/Foundation.h>
#import <Firebase.h>
#import "InAppMessageDisplay.h"
#import "InAppMessageManager.h"
NSString *const kFIRAppReady = @"FIRAppReadyToConfigureSDKNotification";
@implementation InAppMessageDisplay : NSObject
+ (void)load {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(didReceiveConfigureSDKNotification:)
name:kFIRAppReady
object:nil];
}
+ (void)didReceiveConfigureSDKNotification:(NSNotification *)notification {
InAppMessageDisplay *display = [[InAppMessageDisplay alloc] init];
[FIRInAppMessaging inAppMessaging].messageDisplayComponent = display;
}
- (void)displayMessage:(FIRInAppMessagingDisplayMessage *)messageForDisplay
displayDelegate:(id<FIRInAppMessagingDisplayDelegate>)displayDelegate {
if ([messageForDisplay isKindOfClass:[FIRInAppMessagingModalDisplay class]]) {
InAppMessageManager *emitter = [InAppMessageManager allocWithZone: nil];
[emitter FIAMReceivedModal:messageForDisplay displayDelegate:displayDelegate];
} else if ([messageForDisplay isKindOfClass:[FIRInAppMessagingBannerDisplay class]]) {
InAppMessageManager *emitter = [InAppMessageManager allocWithZone: nil];
[emitter FIAMReceivedBanner:messageForDisplay displayDelegate:displayDelegate];
} else if ([messageForDisplay isKindOfClass:[FIRInAppMessagingImageOnlyDisplay class]]) {
InAppMessageManager *emitter = [InAppMessageManager allocWithZone: nil];
[emitter FIAMReceivedImageOnly:messageForDisplay displayDelegate:displayDelegate];
} else if ([messageForDisplay isKindOfClass:[FIRInAppMessagingCardDisplay class]]) {
InAppMessageManager *emitter = [InAppMessageManager allocWithZone: nil];
[emitter FIAMReceivedCard:messageForDisplay displayDelegate:displayDelegate];
}
}
@end
InAppMessageManager
#import <Foundation/Foundation.h>
#import <React/RCTLog.h>
#import "InAppMessageDisplay.h"
#import "InAppMessageManager.h"
@implementation InAppMessageManager
RCT_EXPORT_MODULE();
- (nullable FIRInAppMessagingDisplayMessage *)inAppMessage {
return nil;
}
- (NSMutableDictionary *) displayDelegateDict {
if (!_displayDelegateDict) {
_displayDelegateDict = [NSMutableDictionary new];
}
return _displayDelegateDict;
}
- (NSMutableDictionary *) inAppMessageDict {
if (!_inAppMessageDict) {
_inAppMessageDict = [NSMutableDictionary new];
}
return _inAppMessageDict;
}
+ (id)allocWithZone:(NSZone *)zone {
static InAppMessageManager *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [super allocWithZone:zone];
});
return sharedInstance;
}
- (NSArray<NSString *> *)supportedEvents {
return @[@"OnDisplayInAppMessage"];
}
RCT_EXPORT_METHOD(markAsImpressionDetected:(NSString *)messageId){
if ([self.displayDelegateDict objectForKey:messageId]) {
[[self.displayDelegateDict objectForKey:messageId] impressionDetectedForMessage:[self.inAppMessageDict objectForKey:messageId]];
}
}
RCT_EXPORT_METHOD(markAsClicked:(NSString *)messageId){
NSString *actionURL = @"";
if ([[self.inAppMessageDict objectForKey:messageId] isKindOfClass:[FIRInAppMessagingModalDisplay class]]) {
FIRInAppMessagingModalDisplay *message = [self.inAppMessageDict objectForKey:messageId];
if (message.actionURL.absoluteString) {
actionURL = message.actionURL.absoluteString;
}
} else if ([[self.inAppMessageDict objectForKey:messageId] isKindOfClass:[FIRInAppMessagingBannerDisplay class]]) {
FIRInAppMessagingBannerDisplay *message = [self.inAppMessageDict objectForKey:messageId];
if (message.actionURL.absoluteString) {
actionURL = message.actionURL.absoluteString;
}
} else if ([[self.inAppMessageDict objectForKey:messageId] isKindOfClass:[FIRInAppMessagingImageOnlyDisplay class]]) {
FIRInAppMessagingImageOnlyDisplay *message = [self.inAppMessageDict objectForKey:messageId];
if (message.actionURL.absoluteString) {
actionURL = message.actionURL.absoluteString;
}
} else if ([[self.inAppMessageDict objectForKey:messageId] isKindOfClass:[FIRInAppMessagingCardDisplay class]]) {
FIRInAppMessagingCardDisplay *message = [self.inAppMessageDict objectForKey:messageId];
if (message.primaryActionURL.absoluteString) {
actionURL = message.primaryActionURL.absoluteString;
}
}
if ([self.displayDelegateDict objectForKey:messageId]) {
NSURL *url = [NSURL URLWithString:actionURL];
FIRInAppMessagingAction *action =
[[FIRInAppMessagingAction alloc] initWithActionText:nil
actionURL:url];
[[self.displayDelegateDict objectForKey:messageId] messageClicked:[self.inAppMessageDict objectForKey:messageId] withAction: action];
}
}
RCT_EXPORT_METHOD(markAsDismissed:(NSString *)messageId){
if ([self.displayDelegateDict objectForKey:messageId]) {
[[self.displayDelegateDict objectForKey:messageId] messageDismissed:[self.inAppMessageDict objectForKey:messageId] dismissType:FIRInAppMessagingDismissTypeAuto];
}
}
- (void)FIAMReceivedModal: (FIRInAppMessagingModalDisplay *)inAppMessage
displayDelegate:(id<FIRInAppMessagingDisplayDelegate>)displayDelegate {
[self sendEventWithName:@"OnDisplayInAppMessage" body:@{
@"type":@"Modal"
}];
self.displayDelegate = displayDelegate;
[self.displayDelegateDict setObject:displayDelegate forKey:inAppMessage.campaignInfo.messageID];
[self.inAppMessageDict setObject:inAppMessage forKey:inAppMessage.campaignInfo.messageID];
}
- (void)FIAMReceivedBanner: (FIRInAppMessagingBannerDisplay *)inAppMessage
displayDelegate:(id<FIRInAppMessagingDisplayDelegate>)displayDelegate {
[self sendEventWithName:@"OnDisplayInAppMessage" body:@{
@"type":@"Banner"
}];
self.displayDelegate = displayDelegate;
[self.displayDelegateDict setObject:displayDelegate forKey:inAppMessage.campaignInfo.messageID];
[self.inAppMessageDict setObject:inAppMessage forKey:inAppMessage.campaignInfo.messageID];
}
- (void)FIAMReceivedImageOnly: (FIRInAppMessagingImageOnlyDisplay *)inAppMessage
displayDelegate:(id<FIRInAppMessagingDisplayDelegate>)displayDelegate {
[self sendEventWithName:@"OnDisplayInAppMessage" body:@{
@"type":@"ImageOnly"
}];
self.displayDelegate = displayDelegate;
[self.displayDelegateDict setObject:displayDelegate forKey:inAppMessage.campaignInfo.messageID];
[self.inAppMessageDict setObject:inAppMessage forKey:inAppMessage.campaignInfo.messageID];
}
- (void)FIAMReceivedCard: (FIRInAppMessagingCardDisplay *)inAppMessage
displayDelegate:(id<FIRInAppMessagingDisplayDelegate>)displayDelegate {
[self sendEventWithName:@"OnDisplayInAppMessage" body:@{
@"type":@"Card"
}];
self.displayDelegate = displayDelegate;
[self.displayDelegateDict setObject:displayDelegate forKey:inAppMessage.campaignInfo.messageID];
[self.inAppMessageDict setObject:inAppMessage forKey:inAppMessage.campaignInfo.messageID];
}
@end
Hi @igorjacauna, unfortunately, I'm unable to run the app because it looks for InAppMessageManager
which I encountered multiple errors. If you could share the InAppMessageManager
or if you can create another runnable app that can replicate the issue, that will be great. Thanks.
Hi @rizafran , to help you to reproduce the issue we create a React Native project that has exact architecture of our project and also has the reproducible issue.
To be more specific, the iOS code is on ios
directory of the project
We put instructions on README but I will mention it here:
GoogleService-Info.plist
on ios directoryThe iOS project and code are on ios
directory
yarn install
cd ios
pod install
cd ..
yarn ios
If have any error on build, open the
ios
directory on XCode and build it on XCode. After build try runyarn ios
on root dir of project
Every time we have to try receive again the messages we must uninstall the app before run yarn ios
again
On file App.js
we have the logic about receive and mark as read or clicked the message.
If we click on button on screen, we receive a message. If we click again no one message are received.
To workaround we have to uncomment on line 42 of App.js
. Remember to uninstall the app and run yarn ios
again to start over to receive the messages
Thanks for the sample app, @igorjacauna. Unfortunately, I'm unable to run the app as I'm not familiar with React Native. However, I tried to create a simple app that uses native iOS SDK, and did the following:
What happened is that my InAppMessagingDisplay
protocol was being called only once. Could you confirm if the behavior is the same as yours?
Hi @rizafran , I'm working on the same project with @igorjacauna , I have tried to run the project without the custom FIAM class, indeed the problem doesn’t seem to happen in this condition, however for the porpoises of the project we're working on we need to use a custom FIAM class, considering this problem doesn’t occur without the custom class we realized that it may be a problem on our implementation of this class so we are doing some investigations, but just to make sure we're in the same page, this is the problematic behavior from the perspective of our custom class: In our custom class we created the method displayMessage
we expect this method to be called when an event linked to a message is triggered, however for some reason when we have two or more messages linked to the same event the method is only called once no matter how much times we trigger the event linked to the messages unless we call the method messageClicked
, once we call messageClicked
to mark the first message as clicked and trigger the event again the method displayMessage
will be called bringing a new message, So in summary looks like once the first message is shown the rest of the messages are being ignored unless we mark the first message as clicked, is it really what should be happening?
Thanks for clarifying, @Lucasfrota. It seems like we're encountering the same behavior. I'll inform the engineer about this to see if it's a bug or if something's missing in the code implementation.
Sorry for the delay in response. I just got an update from the engineer and it seems that the code you shared is working as expected. When the displayMessage
method is called, FIAM considers the message as shown to the user until one of displayDelegate
's messageDismissed
, messageClicked
, and displayError
is called. Before this, FIAM refuses to show any more messages.
I'll be closing this ticket for now, but feel free to comment if you have any other questions.
Hello @rizafran I'm the product manager working with @igorjacauna and @Lucasfrota at the in app messing implementation. We felt extremelly surprised with your last comment in this thread about the behavior of iOS SDK, given the fact that at Android SDK seems to have the behavior which satisfied our expection about marking the messaging as delivered once it is displayed. Should the behavior of the same point beeing different on Android and iOS?
As I said before we based this expectation on Android but also on firebase documentation {compose a campaign -> Scheduling your message}:
By default, a campaign is not shown after it has been viewed by (that is, impressed on) the user once. Or, you can set the frequency of messages in days (Maximum 1 time per day)
We see some risks about assuming that on iOS SDK the user needs to "dismiss" or "click to interact":
We made tests and once a user has a message received and closes the app without interacting with it the queue of messaging don´t goes to next messaging as expectated, if I have others campaign aafter that they won't be shown as planned during the user journey;
If the user put the app in background after viewing the message if he return to the App he will view the same messaging breaking major rule of seeing one message at most once a day.
He need to understand if it is the behavior we should expect for iOS SDK because it creates a risk we didn´t mapped before based on Firebase In-app documentation and seems to be a no-go issue because of right risk of spamming our iOS users and ineffectiveness of our campaigns calendar.
It's high important to considerer that in-app messaging is one of the most important peaces of our strategy to growth the engagement of 10 million active users on our app and the partneship with the biggest retail ecommerces in Brazil.
Could you check the topics I broght in this comment and give us a feedback.
@Nsouza31 Thanks for the clarification. The behavior difference between Android and iOS is something that we've had in the backlog to address. We're still working out the plan and will update here when it's determined.
Hi @Nsouza31 ,
We had an internal discussion regarding the issue with our product managers and the outcome is that the iOS SDK is working as expected and for the Android SDK, it is a bug which we have added to our roadmap for fixing. In the mean time, we will consider this issue as a feature request.
Step 1: Describe your environment
CocoaPods
iOS
Step 2: Describe the problem
We are implementing
FIRInAppMessagingDisplay
to create custom UI forInAppMessage
.We found a problem with
Card
message.When we have a stack of messages, we stuck when a
Card
message arrives. And after showsCard
message no messages shows upSteps to reproduce:
Have one event called
screen_event
and 3 messages bind to it, message A of typeImageOnly
, message B of typeCard
and message C of typeBanner
.screen_event
when screen get focused. The message A of typeImageOnly
is showed and we callimpressionDetectedForMessage
for it. After that user dismissed or clicked on message.screen_event
again and the B message is showed and we callimpressionDetectedForMessage
for it. Our custom component for message of typeCard
are showed embed to layout, i.e., there is no dismiss button. The user do not interact with the message, once is embeded on layout he scroll the screen for example.screen_event
, but the message C is not showed.The problem is that after message B of type
Card
shows up, next message are not showed. But if user interact with message B of typeCard
and we callmessageClicked
everything works. And if we trigger the eventscreen_event
again the message C of typeBanner
shows up.Seems like
impressionDetectedForMessage
not working with typeCard
. The flow of messages only works when callmessageClicked
for message of typeCard
for others typesimpressionDetectedForMessage
works fine