mirror of
https://github.com/firebase/firebase-ios-sdk
synced 2026-11-10 22:45:59 +05:45
450 lines
22 KiB
Objective-C
450 lines
22 KiB
Objective-C
/*
|
|
* 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 || TARGET_OS_VISION
|
|
|
|
#import <GoogleUtilities/GULUserDefaults.h>
|
|
|
|
#import "FirebaseCore/Extension/FirebaseCoreInternal.h"
|
|
|
|
#import "FirebaseInAppMessaging/Sources/Analytics/FIRIAMAnalyticsEventLoggerImpl.h"
|
|
#import "FirebaseInAppMessaging/Sources/Analytics/FIRIAMClearcutHttpRequestSender.h"
|
|
#import "FirebaseInAppMessaging/Sources/Analytics/FIRIAMClearcutLogStorage.h"
|
|
#import "FirebaseInAppMessaging/Sources/FIRCore+InAppMessaging.h"
|
|
#import "FirebaseInAppMessaging/Sources/FIRInAppMessagingPrivate.h"
|
|
#import "FirebaseInAppMessaging/Sources/Flows/FIRIAMDisplayCheckOnFetchDoneNotificationFlow.h"
|
|
#import "FirebaseInAppMessaging/Sources/Private/Analytics/FIRIAMClearcutLogger.h"
|
|
#import "FirebaseInAppMessaging/Sources/Private/Analytics/FIRIAMClearcutUploader.h"
|
|
#import "FirebaseInAppMessaging/Sources/Private/Analytics/FIRIAMClientInfoFetcher.h"
|
|
#import "FirebaseInAppMessaging/Sources/Private/Data/FIRIAMFetchResponseParser.h"
|
|
#import "FirebaseInAppMessaging/Sources/Private/Flows/FIRIAMActivityLogger.h"
|
|
#import "FirebaseInAppMessaging/Sources/Private/Flows/FIRIAMBookKeeper.h"
|
|
#import "FirebaseInAppMessaging/Sources/Private/Flows/FIRIAMDisplayCheckOnAnalyticEventsFlow.h"
|
|
#import "FirebaseInAppMessaging/Sources/Private/Flows/FIRIAMDisplayCheckOnAppForegroundFlow.h"
|
|
#import "FirebaseInAppMessaging/Sources/Private/Flows/FIRIAMDisplayExecutor.h"
|
|
#import "FirebaseInAppMessaging/Sources/Private/Flows/FIRIAMFetchOnAppForegroundFlow.h"
|
|
#import "FirebaseInAppMessaging/Sources/Private/Flows/FIRIAMMessageClientCache.h"
|
|
#import "FirebaseInAppMessaging/Sources/Private/Flows/FIRIAMMsgFetcherUsingRestful.h"
|
|
#import "FirebaseInAppMessaging/Sources/Private/Runtime/FIRIAMRuntimeManager.h"
|
|
#import "FirebaseInAppMessaging/Sources/Private/Runtime/FIRIAMSDKModeManager.h"
|
|
#import "FirebaseInAppMessaging/Sources/Public/FirebaseInAppMessaging/FIRInAppMessaging.h"
|
|
|
|
// A enum indicating 3 different possibilities of a setting about auto data collection.
|
|
typedef NS_ENUM(NSInteger, FIRIAMAutoDataCollectionSetting) {
|
|
// This indicates that the config is not explicitly set.
|
|
FIRIAMAutoDataCollectionSettingNone = 0,
|
|
|
|
// This indicates that the setting explicitly enables the auto data collection.
|
|
FIRIAMAutoDataCollectionSettingEnabled = 1,
|
|
|
|
// This indicates that the setting explicitly disables the auto data collection.
|
|
FIRIAMAutoDataCollectionSettingDisabled = 2,
|
|
};
|
|
|
|
@interface FIRIAMRuntimeManager () <FIRIAMTestingModeListener>
|
|
@property(nonatomic, nonnull) FIRIAMMsgFetcherUsingRestful *restfulFetcher;
|
|
@property(nonatomic, nonnull) FIRIAMDisplayCheckOnAppForegroundFlow *displayOnAppForegroundFlow;
|
|
@property(nonatomic, nonnull) FIRIAMDisplayCheckOnFetchDoneNotificationFlow *displayOnFetchDoneFlow;
|
|
@property(nonatomic, nonnull)
|
|
FIRIAMDisplayCheckOnAnalyticEventsFlow *displayOnFIRAnalyticEventsFlow;
|
|
|
|
@property(nonatomic, nonnull) FIRIAMFetchOnAppForegroundFlow *fetchOnAppForegroundFlow;
|
|
@property(nonatomic, nonnull) FIRIAMClientInfoFetcher *clientInfoFetcher;
|
|
@property(nonatomic, nonnull) FIRIAMFetchResponseParser *responseParser;
|
|
@end
|
|
|
|
static NSString *const _userDefaultsKeyForFIAMProgrammaticAutoDataCollectionSetting =
|
|
@"firebase-iam-sdk-auto-data-collection";
|
|
|
|
@implementation FIRIAMRuntimeManager {
|
|
// since we allow the SDK feature to be disabled/enabled at runtime, we need a field to track
|
|
// its state on this
|
|
BOOL _running;
|
|
}
|
|
+ (FIRIAMRuntimeManager *)getSDKRuntimeInstance {
|
|
static FIRIAMRuntimeManager *managerInstance = nil;
|
|
static dispatch_once_t onceToken;
|
|
|
|
dispatch_once(&onceToken, ^{
|
|
managerInstance = [[FIRIAMRuntimeManager alloc] init];
|
|
});
|
|
|
|
return managerInstance;
|
|
}
|
|
|
|
// For protocol FIRIAMTestingModeListener.
|
|
- (void)testingModeSwitchedOn {
|
|
FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM180015",
|
|
@"Dynamically switch to the display flow for testing mode instance.");
|
|
|
|
[self.displayOnAppForegroundFlow stop];
|
|
[self.displayOnFetchDoneFlow start];
|
|
}
|
|
|
|
- (FIRIAMAutoDataCollectionSetting)FIAMProgrammaticAutoDataCollectionSetting {
|
|
id settingEntry = [[GULUserDefaults standardUserDefaults]
|
|
objectForKey:_userDefaultsKeyForFIAMProgrammaticAutoDataCollectionSetting];
|
|
|
|
if (![settingEntry isKindOfClass:[NSNumber class]]) {
|
|
FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM180014",
|
|
@"No auto data collection enable setting entry detected."
|
|
"So no FIAM programmatic setting from the app.");
|
|
return FIRIAMAutoDataCollectionSettingNone;
|
|
} else {
|
|
if ([(NSNumber *)settingEntry boolValue]) {
|
|
return FIRIAMAutoDataCollectionSettingEnabled;
|
|
} else {
|
|
return FIRIAMAutoDataCollectionSettingDisabled;
|
|
}
|
|
}
|
|
}
|
|
|
|
// the key for the plist entry to suppress auto start
|
|
static NSString *const kFirebaseInAppMessagingAutoDataCollectionKey =
|
|
@"FirebaseInAppMessagingAutomaticDataCollectionEnabled";
|
|
|
|
- (FIRIAMAutoDataCollectionSetting)FIAMPlistAutoDataCollectionSetting {
|
|
id fiamAutoDataCollectionPlistEntry = [[NSBundle mainBundle]
|
|
objectForInfoDictionaryKey:kFirebaseInAppMessagingAutoDataCollectionKey];
|
|
|
|
if ([fiamAutoDataCollectionPlistEntry isKindOfClass:[NSNumber class]]) {
|
|
BOOL fiamDataCollectionEnabledPlistSetting =
|
|
[(NSNumber *)fiamAutoDataCollectionPlistEntry boolValue];
|
|
|
|
if (fiamDataCollectionEnabledPlistSetting) {
|
|
FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM180011",
|
|
@"Auto data collection is explicitly enabled in FIAM plist entry.");
|
|
return FIRIAMAutoDataCollectionSettingEnabled;
|
|
} else {
|
|
FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM180012",
|
|
@"Auto data collection is explicitly disabled in FIAM plist entry.");
|
|
return FIRIAMAutoDataCollectionSettingDisabled;
|
|
}
|
|
} else {
|
|
return FIRIAMAutoDataCollectionSettingNone;
|
|
}
|
|
}
|
|
|
|
// Whether data collection is enabled by FIAM programmatic flag.
|
|
- (BOOL)automaticDataCollectionEnabled {
|
|
return
|
|
[self FIAMProgrammaticAutoDataCollectionSetting] != FIRIAMAutoDataCollectionSettingDisabled;
|
|
}
|
|
|
|
// Sets FIAM's programmatic flag for auto data collection.
|
|
- (void)setAutomaticDataCollectionEnabled:(BOOL)automaticDataCollectionEnabled {
|
|
if (automaticDataCollectionEnabled) {
|
|
[self resume];
|
|
} else {
|
|
[self pause];
|
|
}
|
|
}
|
|
|
|
- (BOOL)shouldRunSDKFlowsOnStartup {
|
|
// This can be controlled at 3 different levels in descending priority. If a higher-priority
|
|
// setting exists, the lower level settings are ignored.
|
|
// 1. Setting made by the app by setting FIAM SDK's automaticDataCollectionEnabled flag.
|
|
// 2. FIAM specific data collection setting in plist file.
|
|
// 3. Global Firebase auto data collecting setting (carried over by currentSetting property).
|
|
|
|
FIRIAMAutoDataCollectionSetting programmaticSetting =
|
|
[self FIAMProgrammaticAutoDataCollectionSetting];
|
|
|
|
if (programmaticSetting == FIRIAMAutoDataCollectionSettingEnabled) {
|
|
FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM180010",
|
|
@"FIAM auto data-collection is explicitly enabled, start SDK flows.");
|
|
return true;
|
|
} else if (programmaticSetting == FIRIAMAutoDataCollectionSettingDisabled) {
|
|
FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM180013",
|
|
@"FIAM auto data-collection is explicitly disabled, do not start SDK flows.");
|
|
return false;
|
|
} else {
|
|
// No explicit setting from fiam's programmatic setting. Checking next level down.
|
|
FIRIAMAutoDataCollectionSetting fiamPlistDataCollectionSetting =
|
|
[self FIAMPlistAutoDataCollectionSetting];
|
|
|
|
if (fiamPlistDataCollectionSetting == FIRIAMAutoDataCollectionSettingNone) {
|
|
FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM180018",
|
|
@"No programmatic or plist setting at FIAM level. Fallback to global Firebase "
|
|
"level setting.");
|
|
return self.currentSetting.isFirebaseAutoDataCollectionEnabled;
|
|
} else {
|
|
return fiamPlistDataCollectionSetting == FIRIAMAutoDataCollectionSettingEnabled;
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)resume {
|
|
// persist the setting
|
|
[[GULUserDefaults standardUserDefaults]
|
|
setObject:@(YES)
|
|
forKey:_userDefaultsKeyForFIAMProgrammaticAutoDataCollectionSetting];
|
|
|
|
@synchronized(self) {
|
|
if (!_running) {
|
|
[self.fetchOnAppForegroundFlow start];
|
|
[self.displayOnAppForegroundFlow start];
|
|
[self.displayOnFIRAnalyticEventsFlow start];
|
|
FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM180019",
|
|
@"Start Firebase In-App Messaging flows from inactive.");
|
|
_running = YES;
|
|
} else {
|
|
FIRLogWarning(kFIRLoggerInAppMessaging, @"I-IAM180004",
|
|
@"Runtime is already active, resume is just a no-op");
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)pause {
|
|
// persist the setting
|
|
[[GULUserDefaults standardUserDefaults]
|
|
setObject:@(NO)
|
|
forKey:_userDefaultsKeyForFIAMProgrammaticAutoDataCollectionSetting];
|
|
|
|
@synchronized(self) {
|
|
if (_running) {
|
|
[self.fetchOnAppForegroundFlow stop];
|
|
[self.displayOnAppForegroundFlow stop];
|
|
[self.displayOnFIRAnalyticEventsFlow stop];
|
|
FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM180006",
|
|
@"Shutdown Firebase In-App Messaging flows.");
|
|
_running = NO;
|
|
} else {
|
|
FIRLogWarning(kFIRLoggerInAppMessaging, @"I-IAM180005",
|
|
@"No runtime active yet, pause is just a no-op");
|
|
}
|
|
}
|
|
}
|
|
|
|
- (void)setShouldSuppressMessageDisplay:(BOOL)shouldSuppress {
|
|
FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM180003", @"Message display suppress set to %@",
|
|
@(shouldSuppress));
|
|
self.displayExecutor.suppressMessageDisplay = shouldSuppress;
|
|
}
|
|
|
|
- (void)startRuntimeWithSDKSettings:(FIRIAMSDKSettings *)settings {
|
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0ul), ^{
|
|
[self internalStartRuntimeWithSDKSettings:settings];
|
|
});
|
|
}
|
|
|
|
- (void)internalStartRuntimeWithSDKSettings:(FIRIAMSDKSettings *)settings {
|
|
if (_running) {
|
|
// Runtime has been started previously. Stop all the flows first.
|
|
[self.fetchOnAppForegroundFlow stop];
|
|
[self.displayOnAppForegroundFlow stop];
|
|
[self.displayOnFIRAnalyticEventsFlow stop];
|
|
}
|
|
|
|
self.currentSetting = settings;
|
|
|
|
FIRIAMTimerWithNSDate *timeFetcher = [[FIRIAMTimerWithNSDate alloc] init];
|
|
NSTimeInterval start = [timeFetcher currentTimestampInSeconds];
|
|
|
|
self.activityLogger =
|
|
[[FIRIAMActivityLogger alloc] initWithMaxCountBeforeReduce:settings.loggerMaxCountBeforeReduce
|
|
withSizeAfterReduce:settings.loggerSizeAfterReduce
|
|
verboseMode:settings.loggerInVerboseMode
|
|
loadFromCache:YES];
|
|
|
|
self.responseParser = [[FIRIAMFetchResponseParser alloc] initWithTimeFetcher:timeFetcher];
|
|
|
|
self.bookKeeper = [[FIRIAMBookKeeperViaUserDefaults alloc]
|
|
initWithUserDefaults:[GULUserDefaults standardUserDefaults]];
|
|
|
|
self.messageCache = [[FIRIAMMessageClientCache alloc] initWithBookkeeper:self.bookKeeper
|
|
usingResponseParser:self.responseParser];
|
|
self.fetchResultStorage = [[FIRIAMServerMsgFetchStorage alloc] init];
|
|
|
|
self.clientInfoFetcher = [[FIRIAMClientInfoFetcher alloc]
|
|
initWithFirebaseInstallations:[FIRInAppMessaging inAppMessaging].installations];
|
|
|
|
self.restfulFetcher =
|
|
[[FIRIAMMsgFetcherUsingRestful alloc] initWithHost:settings.apiServerHost
|
|
HTTPProtocol:settings.apiHttpProtocol
|
|
project:settings.firebaseProjectNumber
|
|
firebaseApp:settings.firebaseAppId
|
|
APIKey:settings.apiKey
|
|
fetchStorage:self.fetchResultStorage
|
|
instanceIDFetcher:self.clientInfoFetcher
|
|
usingURLSession:nil
|
|
responseParser:self.responseParser];
|
|
|
|
// start fetch on app foreground flow
|
|
FIRIAMFetchSetting *fetchSetting = [[FIRIAMFetchSetting alloc] init];
|
|
fetchSetting.fetchMinIntervalInMinutes = settings.fetchMinIntervalInMinutes;
|
|
|
|
// start render on app foreground flow
|
|
FIRIAMDisplaySetting *appForegroundDisplaysetting = [[FIRIAMDisplaySetting alloc] init];
|
|
appForegroundDisplaysetting.displayMinIntervalInMinutes =
|
|
settings.appFGRenderMinIntervalInMinutes;
|
|
|
|
// clearcut log expires after 14 days: give up on attempting to deliver them any more
|
|
NSInteger ctLogExpiresInSeconds = 14 * 24 * 60 * 60;
|
|
|
|
FIRIAMClearcutLogStorage *ctLogStorage =
|
|
[[FIRIAMClearcutLogStorage alloc] initWithExpireAfterInSeconds:ctLogExpiresInSeconds
|
|
withTimeFetcher:timeFetcher];
|
|
|
|
FIRIAMClearcutHttpRequestSender *clearcutRequestSender = [[FIRIAMClearcutHttpRequestSender alloc]
|
|
initWithClearcutHost:settings.clearcutServerHost
|
|
usingTimeFetcher:timeFetcher
|
|
withOSMajorVersion:[self.clientInfoFetcher getOSMajorVersion]];
|
|
|
|
FIRIAMClearcutUploader *ctUploader =
|
|
[[FIRIAMClearcutUploader alloc] initWithRequestSender:clearcutRequestSender
|
|
timeFetcher:timeFetcher
|
|
logStorage:ctLogStorage
|
|
usingStrategy:settings.clearcutStrategy
|
|
usingUserDefaults:nil];
|
|
|
|
FIRIAMClearcutLogger *clearcutLogger =
|
|
[[FIRIAMClearcutLogger alloc] initWithFBProjectNumber:settings.firebaseProjectNumber
|
|
fbAppId:settings.firebaseAppId
|
|
clientInfoFetcher:self.clientInfoFetcher
|
|
usingTimeFetcher:timeFetcher
|
|
usingUploader:ctUploader];
|
|
|
|
FIRIAMAnalyticsEventLoggerImpl *analyticsEventLogger = [[FIRIAMAnalyticsEventLoggerImpl alloc]
|
|
initWithClearcutLogger:clearcutLogger
|
|
usingTimeFetcher:timeFetcher
|
|
usingUserDefaults:nil
|
|
analytics:[FIRInAppMessaging inAppMessaging].analytics];
|
|
|
|
FIRIAMSDKModeManager *sdkModeManager =
|
|
[[FIRIAMSDKModeManager alloc] initWithUserDefaults:GULUserDefaults.standardUserDefaults
|
|
testingModeListener:self];
|
|
|
|
FIRIAMActionURLFollower *actionFollower = [FIRIAMActionURLFollower actionURLFollower];
|
|
|
|
self.displayExecutor =
|
|
[[FIRIAMDisplayExecutor alloc] initWithInAppMessaging:[FIRInAppMessaging inAppMessaging]
|
|
setting:appForegroundDisplaysetting
|
|
messageCache:self.messageCache
|
|
timeFetcher:timeFetcher
|
|
bookKeeper:self.bookKeeper
|
|
actionURLFollower:actionFollower
|
|
activityLogger:self.activityLogger
|
|
analyticsEventLogger:analyticsEventLogger];
|
|
|
|
self.fetchOnAppForegroundFlow =
|
|
[[FIRIAMFetchOnAppForegroundFlow alloc] initWithSetting:fetchSetting
|
|
messageCache:self.messageCache
|
|
messageFetcher:self.restfulFetcher
|
|
timeFetcher:timeFetcher
|
|
bookKeeper:self.bookKeeper
|
|
activityLogger:self.activityLogger
|
|
analyticsEventLogger:analyticsEventLogger
|
|
FIRIAMSDKModeManager:sdkModeManager
|
|
displayExecutor:self.displayExecutor];
|
|
|
|
// Setting the message display component and suppression. It's needed in case
|
|
// headless SDK is initialized after the these properties are already set on FIRInAppMessaging.
|
|
self.displayExecutor.messageDisplayComponent =
|
|
FIRInAppMessaging.inAppMessaging.messageDisplayComponent;
|
|
self.displayExecutor.suppressMessageDisplay =
|
|
FIRInAppMessaging.inAppMessaging.messageDisplaySuppressed;
|
|
|
|
// Both display flows are created on startup. But they would only be turned on (started) based on
|
|
// the sdk mode for the current instance
|
|
self.displayOnFetchDoneFlow = [[FIRIAMDisplayCheckOnFetchDoneNotificationFlow alloc]
|
|
initWithDisplayFlow:self.displayExecutor];
|
|
self.displayOnAppForegroundFlow =
|
|
[[FIRIAMDisplayCheckOnAppForegroundFlow alloc] initWithDisplayFlow:self.displayExecutor];
|
|
|
|
self.displayOnFIRAnalyticEventsFlow =
|
|
[[FIRIAMDisplayCheckOnAnalyticEventsFlow alloc] initWithDisplayFlow:self.displayExecutor];
|
|
|
|
self.messageCache.analyticsEventDisplayCheckFlow = self.displayOnFIRAnalyticEventsFlow;
|
|
[self.messageCache
|
|
loadMessageDataFromServerFetchStorage:self.fetchResultStorage
|
|
withCompletion:^(BOOL success) {
|
|
// start flows regardless whether we can load messages from fetch
|
|
// storage successfully
|
|
FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM180001",
|
|
@"Message loading from fetch storage was done.");
|
|
|
|
if ([self shouldRunSDKFlowsOnStartup]) {
|
|
FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM180008",
|
|
@"Start SDK runtime components.");
|
|
|
|
[self.clientInfoFetcher
|
|
fetchFirebaseInstallationDataWithProjectNumber:
|
|
self.currentSetting.firebaseProjectNumber
|
|
withCompletion:^(
|
|
NSString *_Nullable FID,
|
|
NSString
|
|
*_Nullable FISToken,
|
|
NSError *_Nullable error) {
|
|
// Always dump the
|
|
// installation ID into log
|
|
// on startup to help
|
|
// developers to find it for
|
|
// their app instance.
|
|
FIRLogDebug(
|
|
kFIRLoggerInAppMessaging,
|
|
@"I-IAM180017",
|
|
@"Starting "
|
|
@"InAppMessaging "
|
|
@"runtime "
|
|
@"with "
|
|
"Firebase Installation "
|
|
"ID %@",
|
|
FID);
|
|
}];
|
|
|
|
[self.fetchOnAppForegroundFlow start];
|
|
[self.displayOnFIRAnalyticEventsFlow start];
|
|
|
|
self->_running = YES;
|
|
|
|
if (sdkModeManager.currentMode == FIRIAMSDKModeTesting) {
|
|
FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM180007",
|
|
@"InAppMessaging testing mode enabled. App "
|
|
"foreground messages will be displayed following "
|
|
"fetch");
|
|
[self.displayOnFetchDoneFlow start];
|
|
} else {
|
|
FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM180020",
|
|
@"Start regular display flow for non-testing "
|
|
"instance mode");
|
|
[self.displayOnAppForegroundFlow start];
|
|
|
|
// Simulate app going into foreground on startup
|
|
[self.displayExecutor checkAndDisplayNextAppForegroundMessage];
|
|
}
|
|
|
|
// One-time triggering of checks for both fetch flow
|
|
// upon SDK/app startup.
|
|
[self.fetchOnAppForegroundFlow
|
|
checkAndFetchForInitialAppLaunch:YES];
|
|
} else {
|
|
FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM180009",
|
|
@"No FIAM SDK startup due to settings.");
|
|
}
|
|
}];
|
|
|
|
FIRLogDebug(kFIRLoggerInAppMessaging, @"I-IAM180002",
|
|
@"Firebase In-App Messaging SDK version %@ finished startup in %lf seconds "
|
|
"with these settings: %@",
|
|
[self.clientInfoFetcher getIAMSDKVersion],
|
|
(double)([timeFetcher currentTimestampInSeconds] - start), settings);
|
|
}
|
|
@end
|
|
|
|
#endif // TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_VISION
|