AutorÃa | Ultima modificación | Ver Log |
/** Copyright 2017 Google** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/#import <TargetConditionals.h>#if TARGET_OS_IOS || TARGET_OS_TV#import <UIKit/UIKit.h>#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"#import "FirebaseInAppMessaging/Sources/FIRCore+InAppMessaging.h"#import "FirebaseInAppMessaging/Sources/Private/Data/FIRIAMMessageContentData.h"#import "FirebaseInAppMessaging/Sources/Private/Data/FIRIAMMessageDefinition.h"#import "FirebaseInAppMessaging/Sources/Private/Flows/FIRIAMActivityLogger.h"#import "FirebaseInAppMessaging/Sources/Private/Flows/FIRIAMDisplayExecutor.h"#import "FirebaseInAppMessaging/Sources/Public/FirebaseInAppMessaging/FIRInAppMessaging.h"#import "FirebaseInAppMessaging/Sources/RenderingObjects/FIRInAppMessagingRenderingPrivate.h"#import "FirebaseInAppMessaging/Sources/Runtime/FIRIAMSDKRuntimeErrorCodes.h"#import "FirebaseABTesting/Sources/Private/FirebaseABTestingInternal.h"@implementation FIRIAMDisplaySetting@end@interface FIRIAMDisplayExecutor () <FIRInAppMessagingDisplayDelegate>@property(nonatomic) id<FIRIAMTimeFetcher> timeFetcher;// YES if a message is being rendered at this time@property(nonatomic) BOOL isMsgBeingDisplayed;@property(nonatomic) NSTimeInterval lastDisplayTime;@property(nonatomic, nonnull, readonly) FIRInAppMessaging *inAppMessaging;@property(nonatomic, nonnull, readonly) FIRIAMDisplaySetting *setting;@property(nonatomic, nonnull, readonly) FIRIAMMessageClientCache *messageCache;@property(nonatomic, nonnull, readonly) id<FIRIAMBookKeeper> displayBookKeeper;@property(nonatomic) BOOL impressionRecorded;@property(nonatomic, nonnull, readonly) id<FIRIAMAnalyticsEventLogger> analyticsEventLogger;@property(nonatomic, nonnull, readonly) FIRIAMActionURLFollower *actionURLFollower;// Used for displaying the test on device message error alert.@property(nonatomic, strong) UIWindow *alertWindow;@end@implementation FIRIAMDisplayExecutor {FIRIAMMessageDefinition *_currentMsgBeingDisplayed;}+ (NSString *)logStringForNilMessageDisplayComponent {#if TARGET_OS_IOSreturn @"Message display component is not present yet. No display should happen.";#else // TARGET_OS_TVreturn @"There is no default UI for tvOS. You must implement a messageDisplayComponent and set "@"it on the InAppMessaging singleton. See "@"https://firebase.google.com/docs/in-app-messaging/"@"customize-messages#create_your_own_message_display_library.";#endif}#pragma mark - FIRInAppMessagingDisplayDelegate methods- (void)messageClicked:(FIRInAppMessagingDisplayMessage *)inAppMessagewithAction:(FIRInAppMessagingAction *)action {// Call through to app-side delegate.__weak id<FIRInAppMessagingDisplayDelegate> appSideDelegate = self.inAppMessaging.delegate;if ([appSideDelegate respondsToSelector:@selector(messageClicked:withAction:)]) {[appSideDelegate messageClicked:inAppMessage withAction:action];}self.isMsgBeingDisplayed = NO;if (!_currentMsgBeingDisplayed.renderData.messageID) {FIRLogWarning(kFIRLoggerInAppMessaging, @"I-IAM400030",@"messageClicked called but ""there is no current message ID.");return;}if (_currentMsgBeingDisplayed.isTestMessage) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400031",@"A test message clicked. Do test event impression/click analytics logging");[self.analyticsEventLoggerlogAnalyticsEventForType:FIRIAMAnalyticsEventTestMessageImpressionforCampaignID:_currentMsgBeingDisplayed.renderData.messageIDwithCampaignName:_currentMsgBeingDisplayed.renderData.nameeventTimeInMs:nilcompletion:^(BOOL success) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400036",@"Logging analytics event for url following %@",success ? @"succeeded" : @"failed");}];[self.analyticsEventLoggerlogAnalyticsEventForType:FIRIAMAnalyticsEventTestMessageClickforCampaignID:_currentMsgBeingDisplayed.renderData.messageIDwithCampaignName:_currentMsgBeingDisplayed.renderData.nameeventTimeInMs:nilcompletion:^(BOOL success) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400039",@"Logging analytics event for url following %@",success ? @"succeeded" : @"failed");}];} else {// Logging the impression[self recordValidImpression:_currentMsgBeingDisplayed.renderData.messageIDwithMessageName:_currentMsgBeingDisplayed.renderData.name];if (action.actionURL) {[self.analyticsEventLoggerlogAnalyticsEventForType:FIRIAMAnalyticsEventActionURLFollowforCampaignID:_currentMsgBeingDisplayed.renderData.messageIDwithCampaignName:_currentMsgBeingDisplayed.renderData.nameeventTimeInMs:nilcompletion:^(BOOL success) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400032",@"Logging analytics event for url following %@",success ? @"succeeded" : @"failed");}];// Also start tracking conversions.[self.analyticsEventLoggerlogConversionTrackingEventForCampaignID:_currentMsgBeingDisplayed.renderData.messageID];}}NSURL *actionURL = action.actionURL;if (!actionURL) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400033",@"messageClicked called but ""there is no action url specified in the message data.");// it's equivalent to closing the message with no further actionreturn;} else {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400037", @"Following action url %@",actionURL.absoluteString);@try {[self.actionURLFollowerfollowActionURL:actionURLwithCompletionBlock:^(BOOL success) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400034",@"Seeing %@ from following action URL", success ? @"success" : @"error");}];} @catch (NSException *e) {FIRLogWarning(kFIRLoggerInAppMessaging, @"I-IAM400035",@"Exception encountered in following ""action url (%@): %@ ",actionURL, e.description);@throw;}}}- (void)messageDismissed:(FIRInAppMessagingDisplayMessage *)inAppMessagedismissType:(FIRInAppMessagingDismissType)dismissType {// Call through to app-side delegate.__weak id<FIRInAppMessagingDisplayDelegate> appSideDelegate = self.inAppMessaging.delegate;if ([appSideDelegate respondsToSelector:@selector(messageDismissed:dismissType:)]) {[appSideDelegate messageDismissed:inAppMessage dismissType:dismissType];}self.isMsgBeingDisplayed = NO;if (!_currentMsgBeingDisplayed.renderData.messageID) {FIRLogWarning(kFIRLoggerInAppMessaging, @"I-IAM400014",@"messageDismissedWithType called but ""there is no current message ID.");return;}if (_currentMsgBeingDisplayed.isTestMessage) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400020",@"A test message dismissed. Record the impression event.");[self.analyticsEventLoggerlogAnalyticsEventForType:FIRIAMAnalyticsEventTestMessageImpressionforCampaignID:_currentMsgBeingDisplayed.renderData.messageIDwithCampaignName:_currentMsgBeingDisplayed.renderData.nameeventTimeInMs:nilcompletion:^(BOOL success) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400038",@"Logging analytics event for url following %@",success ? @"succeeded" : @"failed");}];return;}// Logging the impression[self recordValidImpression:_currentMsgBeingDisplayed.renderData.messageIDwithMessageName:_currentMsgBeingDisplayed.renderData.name];FIRIAMAnalyticsLogEventType logEventType = dismissType == FIRInAppMessagingDismissTypeAuto? FIRIAMAnalyticsEventMessageDismissAuto: FIRIAMAnalyticsEventMessageDismissClick;[self.analyticsEventLoggerlogAnalyticsEventForType:logEventTypeforCampaignID:_currentMsgBeingDisplayed.renderData.messageIDwithCampaignName:_currentMsgBeingDisplayed.renderData.nameeventTimeInMs:nilcompletion:^(BOOL success) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400004",@"Logging analytics event for message dismiss %@",success ? @"succeeded" : @"failed");}];}- (void)impressionDetectedForMessage:(FIRInAppMessagingDisplayMessage *)inAppMessage {__weak id<FIRInAppMessagingDisplayDelegate> appSideDelegate = self.inAppMessaging.delegate;if ([appSideDelegate respondsToSelector:@selector(impressionDetectedForMessage:)]) {[appSideDelegate impressionDetectedForMessage:inAppMessage];}if (!_currentMsgBeingDisplayed.renderData.messageID) {FIRLogWarning(kFIRLoggerInAppMessaging, @"I-IAM400022",@"impressionDetected called but ""there is no current message ID.");return;}// If this is an experimental FIAM, activate the experiment.if (inAppMessage.campaignInfo.experimentPayload) {[[FIRExperimentController sharedInstance]activateExperiment:inAppMessage.campaignInfo.experimentPayloadforServiceOrigin:@"fiam"];}if (!_currentMsgBeingDisplayed.isTestMessage) {// Displayed long enough to be a valid impression.[self recordValidImpression:_currentMsgBeingDisplayed.renderData.messageIDwithMessageName:_currentMsgBeingDisplayed.renderData.name];if ([self shouldTrackConversionsOnImpressionForCurrentInAppMessage:_currentMsgBeingDisplayed]) {[self.analyticsEventLoggerlogConversionTrackingEventForCampaignID:_currentMsgBeingDisplayed.renderData.messageID];}} else {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400011",@"A test message. Record the test message impression event.");return;}}- (BOOL)shouldTrackConversionsOnImpressionForCurrentInAppMessage:(FIRIAMMessageDefinition *)inAppMessage {// If the message has no action URL, an impression is enough to start tracking conversions.id<FIRIAMMessageContentData> contentData = inAppMessage.renderData.contentData;return contentData.actionURL == nil && contentData.secondaryActionURL == nil;}- (void)displayErrorForMessage:(FIRInAppMessagingDisplayMessage *)inAppMessageerror:(NSError *)error {__weak id<FIRInAppMessagingDisplayDelegate> appSideDelegate = self.inAppMessaging.delegate;if ([appSideDelegate respondsToSelector:@selector(displayErrorForMessage:error:)]) {[appSideDelegate displayErrorForMessage:inAppMessage error:error];}self.isMsgBeingDisplayed = NO;if (!_currentMsgBeingDisplayed.renderData.messageID) {FIRLogWarning(kFIRLoggerInAppMessaging, @"I-IAM400017",@"displayErrorEncountered called but ""there is no current message ID.");return;}NSString *messageID = _currentMsgBeingDisplayed.renderData.messageID;FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400009",@"Display ran into error for message %@: %@", messageID, error);if (_currentMsgBeingDisplayed.isTestMessage) {[self displayMessageLoadError:error];FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400012",@"A test message. No analytics tracking ""from image data loading failure");return;}// we remove the message from the client side cache so that it won't be retried until next time// it's fetched again from server.[self.messageCache removeMessageWithId:messageID];NSString *messageName = _currentMsgBeingDisplayed.renderData.name;if ([error.domain isEqualToString:NSURLErrorDomain]) {[self.analyticsEventLoggerlogAnalyticsEventForType:FIRIAMAnalyticsEventImageFetchErrorforCampaignID:messageIDwithCampaignName:messageNameeventTimeInMs:nilcompletion:^(BOOL success) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400010",@"Logging analytics event for image fetch error %@",success ? @"succeeded" : @"failed");}];} else if (error.code == FIRIAMSDKRuntimeErrorNonImageMimetypeFromImageURL) {[self.analyticsEventLoggerlogAnalyticsEventForType:FIRIAMAnalyticsEventImageFormatUnsupportedforCampaignID:messageIDwithCampaignName:messageNameeventTimeInMs:nilcompletion:^(BOOL success) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400013",@"Logging analytics event for image format error %@",success ? @"succeeded" : @"failed");}];}}- (void)recordValidImpression:(NSString *)messageID withMessageName:(NSString *)messageName {if (!self.impressionRecorded) {[self.displayBookKeeperrecordNewImpressionForMessage:messageIDwithStartTimestampInSeconds:[self.timeFetcher currentTimestampInSeconds]];self.impressionRecorded = YES;[self.messageCache removeMessageWithId:messageID];// Log an impression analytics event as well.[self.analyticsEventLoggerlogAnalyticsEventForType:FIRIAMAnalyticsEventMessageImpressionforCampaignID:messageIDwithCampaignName:messageNameeventTimeInMs:nilcompletion:^(BOOL success) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400007",@"Logging analytics event for impression %@",success ? @"succeeded" : @"failed");}];}}- (void)displayMessageLoadError:(NSError *)error {NSString *errorMsg = error.userInfo[NSLocalizedDescriptionKey]? error.userInfo[NSLocalizedDescriptionKey]: NSLocalizedString(@"Message loading failed", nil);UIAlertController *alert = [UIAlertControlleralertControllerWithTitle:@"Firebase InAppMessaging fail to load a test message"message:errorMsgpreferredStyle:UIAlertControllerStyleAlert];UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil)style:UIAlertActionStyleDefaulthandler:^(UIAlertAction *action) {self.alertWindow.hidden = NO;self.alertWindow = nil;}];[alert addAction:defaultAction];dispatch_async(dispatch_get_main_queue(), ^{#if defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000if (@available(iOS 13.0, tvOS 13.0, *)) {UIWindowScene *foregroundedScene = nil;for (UIWindowScene *connectedScene in [UIApplication sharedApplication].connectedScenes) {if (connectedScene.activationState == UISceneActivationStateForegroundActive) {foregroundedScene = connectedScene;break;}}if (foregroundedScene == nil) {return;}self.alertWindow = [[UIWindow alloc] initWithWindowScene:foregroundedScene];}#else // defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000self.alertWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];#endifUIViewController *alertViewController = [[UIViewController alloc] init];self.alertWindow.rootViewController = alertViewController;self.alertWindow.hidden = NO;[alertViewController presentViewController:alert animated:YES completion:nil];});}- (instancetype)initWithInAppMessaging:(FIRInAppMessaging *)inAppMessagingsetting:(FIRIAMDisplaySetting *)settingmessageCache:(FIRIAMMessageClientCache *)cachetimeFetcher:(id<FIRIAMTimeFetcher>)timeFetcherbookKeeper:(id<FIRIAMBookKeeper>)displayBookKeeperactionURLFollower:(FIRIAMActionURLFollower *)actionURLFolloweractivityLogger:(FIRIAMActivityLogger *)activityLoggeranalyticsEventLogger:(id<FIRIAMAnalyticsEventLogger>)analyticsEventLogger {if (self = [super init]) {_inAppMessaging = inAppMessaging;_timeFetcher = timeFetcher;_lastDisplayTime = displayBookKeeper.lastDisplayTime;_setting = setting;_messageCache = cache;_displayBookKeeper = displayBookKeeper;_isMsgBeingDisplayed = NO;_analyticsEventLogger = analyticsEventLogger;_actionURLFollower = actionURLFollower;_suppressMessageDisplay = NO; // always allow message display on startup}return self;}- (void)checkAndDisplayNextContextualMessageForAnalyticsEvent:(NSString *)eventName {// synchronizing on self so that we won't potentially enter the render flow from two// threads: example like showing analytics triggered message and a regular app open// triggered message@synchronized(self) {if (self.suppressMessageDisplay) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400015",@"Message display is being suppressed. No contextual message rendering.");return;}if (!self.messageDisplayComponent) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400026", @"%@",[[self class] logStringForNilMessageDisplayComponent]);return;}if (self.isMsgBeingDisplayed) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400008",@"An in-app message display is in progress, do not check analytics event ""based message for now.");return;}// Pop up next analytics event based message to be displayedFIRIAMMessageDefinition *nextAnalyticsBasedMessage =[self.messageCache nextOnFirebaseAnalyticEventDisplayMsg:eventName];if (nextAnalyticsBasedMessage) {[self displayForMessage:nextAnalyticsBasedMessagetriggerType:FIRInAppMessagingDisplayTriggerTypeOnAnalyticsEvent];}}}- (FIRInAppMessagingCardDisplay *)cardDisplayMessageWithMessageDefinition:(FIRIAMMessageDefinition *)definitionportraitImageData:(FIRInAppMessagingImageData *)portraitImageDatalandscapeImageData:(nullable FIRInAppMessagingImageData *)landscapeImageDatatriggerType:(FIRInAppMessagingDisplayTriggerType)triggerType {// For easier reference in this method.FIRIAMMessageRenderData *renderData = definition.renderData;NSString *title = renderData.contentData.titleText;NSString *body = renderData.contentData.bodyText;// Action button data is never nil for a card message.#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wdeprecated-declarations"FIRInAppMessagingActionButton *primaryActionButton = [[FIRInAppMessagingActionButton alloc]initWithButtonText:renderData.contentData.actionButtonTextbuttonTextColor:renderData.renderingEffectSettings.btnTextColorbackgroundColor:renderData.renderingEffectSettings.btnBGColor];#pragma clang diagnostic popFIRInAppMessagingActionButton *secondaryActionButton = nil;if (definition.renderData.contentData.secondaryActionButtonText) {#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wdeprecated-declarations"secondaryActionButton = [[FIRInAppMessagingActionButton alloc]initWithButtonText:renderData.contentData.secondaryActionButtonTextbuttonTextColor:renderData.renderingEffectSettings.secondaryActionBtnTextColorbackgroundColor:renderData.renderingEffectSettings.btnBGColor];#pragma clang diagnostic pop}FIRInAppMessagingCardDisplay *cardMessage = [[FIRInAppMessagingCardDisplay alloc]initWithMessageID:renderData.messageIDcampaignName:renderData.nameexperimentPayload:definition.experimentPayloadrenderAsTestMessage:definition.isTestMessagetriggerType:triggerTypetitleText:titlebodyText:bodytextColor:renderData.renderingEffectSettings.textColorportraitImageData:portraitImageDatalandscapeImageData:landscapeImageDatabackgroundColor:renderData.renderingEffectSettings.displayBGColorprimaryActionButton:primaryActionButtonsecondaryActionButton:secondaryActionButtonprimaryActionURL:definition.renderData.contentData.actionURLsecondaryActionURL:definition.renderData.contentData.secondaryActionURLappData:definition.appData];return cardMessage;}- (FIRInAppMessagingBannerDisplay *)bannerDisplayMessageWithMessageDefinition:(FIRIAMMessageDefinition *)definitionimageData:(FIRInAppMessagingImageData *)imageDatatriggerType:(FIRInAppMessagingDisplayTriggerType)triggerType {NSString *title = definition.renderData.contentData.titleText;NSString *body = definition.renderData.contentData.bodyText;#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wdeprecated-declarations"FIRInAppMessagingBannerDisplay *bannerMessage = [[FIRInAppMessagingBannerDisplay alloc]initWithMessageID:definition.renderData.messageIDcampaignName:definition.renderData.nameexperimentPayload:definition.experimentPayloadrenderAsTestMessage:definition.isTestMessagetriggerType:triggerTypetitleText:titlebodyText:bodytextColor:definition.renderData.renderingEffectSettings.textColorbackgroundColor:definition.renderData.renderingEffectSettings.displayBGColorimageData:imageDataactionURL:definition.renderData.contentData.actionURLappData:definition.appData];#pragma clang diagnostic popreturn bannerMessage;}- (FIRInAppMessagingImageOnlyDisplay *)imageOnlyDisplayMessageWithMessageDefinition:(FIRIAMMessageDefinition *)definitionimageData:(FIRInAppMessagingImageData *)imageDatatriggerType:(FIRInAppMessagingDisplayTriggerType)triggerType {#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wdeprecated-declarations"FIRInAppMessagingImageOnlyDisplay *imageOnlyMessage = [[FIRInAppMessagingImageOnlyDisplay alloc]initWithMessageID:definition.renderData.messageIDcampaignName:definition.renderData.nameexperimentPayload:definition.experimentPayloadrenderAsTestMessage:definition.isTestMessagetriggerType:triggerTypeimageData:imageDataactionURL:definition.renderData.contentData.actionURLappData:definition.appData];#pragma clang diagnostic popreturn imageOnlyMessage;}- (FIRInAppMessagingModalDisplay *)modalDisplayMessageWithMessageDefinition:(FIRIAMMessageDefinition *)definitionimageData:(FIRInAppMessagingImageData *)imageDatatriggerType:(FIRInAppMessagingDisplayTriggerType)triggerType {// For easier reference in this method.FIRIAMMessageRenderData *renderData = definition.renderData;NSString *title = renderData.contentData.titleText;NSString *body = renderData.contentData.bodyText;FIRInAppMessagingActionButton *actionButton = nil;if (definition.renderData.contentData.actionButtonText) {#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wdeprecated-declarations"actionButton = [[FIRInAppMessagingActionButton alloc]initWithButtonText:renderData.contentData.actionButtonTextbuttonTextColor:renderData.renderingEffectSettings.btnTextColorbackgroundColor:renderData.renderingEffectSettings.btnBGColor];#pragma clang diagnostic pop}#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wdeprecated-declarations"FIRInAppMessagingModalDisplay *modalViewMessage = [[FIRInAppMessagingModalDisplay alloc]initWithMessageID:definition.renderData.messageIDcampaignName:definition.renderData.nameexperimentPayload:definition.experimentPayloadrenderAsTestMessage:definition.isTestMessagetriggerType:triggerTypetitleText:titlebodyText:bodytextColor:renderData.renderingEffectSettings.textColorbackgroundColor:renderData.renderingEffectSettings.displayBGColorimageData:imageDataactionButton:actionButtonactionURL:definition.renderData.contentData.actionURLappData:definition.appData];#pragma clang diagnostic popreturn modalViewMessage;}- (FIRInAppMessagingDisplayMessage *)displayMessageWithMessageDefinition:(FIRIAMMessageDefinition *)definitionimageData:(FIRInAppMessagingImageData *)imageDatalandscapeImageData:(nullable FIRInAppMessagingImageData *)landscapeImageDatatriggerType:(FIRInAppMessagingDisplayTriggerType)triggerType {switch (definition.renderData.renderingEffectSettings.viewMode) {case FIRIAMRenderAsCardView:if (imageData == nil) {// Image data should never nil for a valid card message.return nil;}return [self cardDisplayMessageWithMessageDefinition:definitionportraitImageData:imageDatalandscapeImageData:landscapeImageDatatriggerType:triggerType];case FIRIAMRenderAsBannerView:return [self bannerDisplayMessageWithMessageDefinition:definitionimageData:imageDatatriggerType:triggerType];case FIRIAMRenderAsModalView:return [self modalDisplayMessageWithMessageDefinition:definitionimageData:imageDatatriggerType:triggerType];case FIRIAMRenderAsImageOnlyView:return [self imageOnlyDisplayMessageWithMessageDefinition:definitionimageData:imageDatatriggerType:triggerType];default:return nil;}}- (void)displayForMessage:(FIRIAMMessageDefinition *)messagetriggerType:(FIRInAppMessagingDisplayTriggerType)triggerType {_currentMsgBeingDisplayed = message;self.isMsgBeingDisplayed = YES;[message.renderData.contentDataloadImageDataWithBlock:^(NSData *_Nullable standardImageRawData,NSData *_Nullable landscapeImageRawData, NSError *_Nullable error) {FIRInAppMessagingImageData *imageData = nil;FIRInAppMessagingImageData *landscapeImageData = nil;if (error) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400019",@"Error in loading image data for the message.");FIRInAppMessagingDisplayMessage *erroredMessage =[self displayMessageWithMessageDefinition:messageimageData:imageDatalandscapeImageData:landscapeImageDatatriggerType:triggerType];// short-circuit to display error handling[self displayErrorForMessage:erroredMessage error:error];self.isMsgBeingDisplayed = NO;return;} else {if (standardImageRawData) {#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wdeprecated-declarations"imageData = [[FIRInAppMessagingImageData alloc]initWithImageURL:message.renderData.contentData.imageURL.absoluteStringimageData:standardImageRawData];#pragma clang diagnostic pop}if (landscapeImageRawData) {#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wdeprecated-declarations"landscapeImageData = [[FIRInAppMessagingImageData alloc]initWithImageURL:message.renderData.contentData.landscapeImageURL.absoluteStringimageData:landscapeImageRawData];#pragma clang diagnostic pop}}// On slow networks, image loading may take significant time,// in which the value of `suppressMessageDisplay` could change.if (self.suppressMessageDisplay) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400042",@"Message display suppressed by developer at message display time.");self.isMsgBeingDisplayed = NO;return;}self.impressionRecorded = NO;FIRInAppMessagingDisplayMessage *displayMessage =[self displayMessageWithMessageDefinition:messageimageData:imageDatalandscapeImageData:landscapeImageDatatriggerType:triggerType];// A final `nil`-check, performed to avoid crashing the client app.if (!displayMessage) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400043",@"Failed to construct a non-nil display message.");return;}[self.messageDisplayComponent displayMessage:displayMessage displayDelegate:self];}];}- (BOOL)enoughIntervalFromLastDisplay {NSTimeInterval intervalFromLastDisplayInSeconds =[self.timeFetcher currentTimestampInSeconds] - self.lastDisplayTime;FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400005",@"Interval time from last display is %lf seconds", intervalFromLastDisplayInSeconds);return intervalFromLastDisplayInSeconds >= self.setting.displayMinIntervalInMinutes * 60.0;}- (void)checkAndDisplayNextAppLaunchMessage {// synchronizing on self so that we won't potentially enter the render flow from two// threads.@synchronized(self) {if (!self.messageDisplayComponent) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400028", @"%@",[[self class] logStringForNilMessageDisplayComponent]);return;}if (self.suppressMessageDisplay) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400029",@"Message display is being suppressed. No regular message rendering.");return;}if (self.isMsgBeingDisplayed) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400030",@"An in-app message display is in progress, do not over-display on top of it.");return;}if ([self.messageCache hasTestMessage] || [self enoughIntervalFromLastDisplay]) {// We can display test messages anytime or display regular messages when// the display time interval has been reachedFIRIAMMessageDefinition *nextAppLaunchMessage = [self.messageCache nextOnAppLaunchDisplayMsg];if (nextAppLaunchMessage) {[self displayForMessage:nextAppLaunchMessagetriggerType:FIRInAppMessagingDisplayTriggerTypeOnAnalyticsEvent];self.lastDisplayTime = [self.timeFetcher currentTimestampInSeconds];} else {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400040",@"No appropriate in-app message detected for display.");}} else {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400041",@"Minimal display interval of %lf seconds has not been reached yet.",self.setting.displayMinIntervalInMinutes * 60.0);}}}- (void)checkAndDisplayNextAppForegroundMessage {// synchronizing on self so that we won't potentially enter the render flow from two// threads: example like showing analytics triggered message and a regular app open// triggered message concurrently@synchronized(self) {if (!self.messageDisplayComponent) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400027", @"%@",[[self class] logStringForNilMessageDisplayComponent]);return;}if (self.suppressMessageDisplay) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400016",@"Message display is being suppressed. No regular message rendering.");return;}if (self.isMsgBeingDisplayed) {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400002",@"An in-app message display is in progress, do not over-display on top of it.");return;}if ([self.messageCache hasTestMessage] || [self enoughIntervalFromLastDisplay]) {// We can display test messages anytime or display regular messages when// the display time interval has been reachedFIRIAMMessageDefinition *nextForegroundMessage = [self.messageCache nextOnAppOpenDisplayMsg];if (nextForegroundMessage) {[self displayForMessage:nextForegroundMessagetriggerType:FIRInAppMessagingDisplayTriggerTypeOnAppForeground];self.lastDisplayTime = [self.timeFetcher currentTimestampInSeconds];} else {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400001",@"No appropriate in-app message detected for display.");}} else {FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM400003",@"Minimal display interval of %lf seconds has not been reached yet.",self.setting.displayMinIntervalInMinutes * 60.0);}}}@end#endif // TARGET_OS_IOS || TARGET_OS_TV