braze-inc / braze-ios-sdk

Public repo for the Braze iOS SDK (ObjC) for Swift Package Manager
https://www.braze.com
Other
10 stars 4 forks source link

is it safe to defer braze initialization until app launch process finish? #12

Closed dwirandytlvk closed 2 years ago

dwirandytlvk commented 2 years ago

Hi Braze Team

I try to decrease my app launch time by defer braze setup, i create a array of closure that hold all method that is called during launch time, such as init app boy, track event etc

is it safe to defer braze initialization until app launch process finish by using this approach

@import TVLFoundation;
@import Appboy_iOS_SDK;

...

typedef void (^BrazeCompletionBlock)(void);

@interface ThirdPartyBrazeIntegrationWrapper: ThirdPartyBrazeIntegration
@property (strong, nonatomic) NSMutableArray<BrazeCompletionBlock> *eventQueue;
@property (assign, nonatomic) BOOL *hasInitiated;
@end

@implementation ThirdPartyBrazeIntegrationWrapper

- (instancetype)initwithConfigType: (ThirdPartyTrackingConfig)configType {
    self.eventQueue = [[NSMutableArray alloc] init];
    self.hasInitiated = NO;

    [self enqueue:^{
        [super init];
    }];

    [self setupQueueExecutor];

    return self;
}

- (void)applicationDidLaunch:(NSDictionary *)launchOptions {
    [self enqueue:^{
        [super applicationDidLaunch:launchOptions];

        self.hasInitiated = YES;
    }];
}

- (void)setUserID:(NSString *)userID {
    [self enqueue:^{
        [super setUserID:userID];
    }];
}

- (void)identity:(ThirdPartyTrackPayload *)payload {
    [self enqueue:^{
        [super identity:payload];
    }];
}

- (void)track:(ThirdPartyTrackPayload *)payload {
    [self enqueue:^{
        [super track:payload];
    }];
}

- (void)registeredForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    [self enqueue:^{
        [super registeredForRemoteNotificationsWithDeviceToken:deviceToken];
    }];
}

#pragma mark - Private Methods

/// After app launch is finish
/// Call all method called during app launch based on the queue
- (void)setupQueueExecutor {
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            if (!self.hasInitiated) {
                for (BrazeCompletionBlock command in self.eventQueue) {
                    command();
                }
            }

            self.eventQueue = nil;
        });
    });
}

/// Enqueue block that called during launch time
/// The queue block will be executed after app launch process finish
/// @param block bloc of code that called during app launch
- (void)enqueue:(BrazeCompletionBlock)block {
    if (self.hasInitiated) {
        block();
    } else {
        [self.eventQueue addObject:block];
    }
}

@end

cc: @hokstuff @lowip

Bucimis commented 2 years ago

@dwirandytlvk You can defer Braze init safely, however, there is a big caveat - for push, the Braze delegate methods you need to implement in your UserNotifications framework delegates require a valid Braze instance to work (the stuff in https://www.braze.com/docs/developer_guide/platform_integration_guides/ios/push_notifications/integration/#step-5-enable-push-handling). You will need to ensure that your strategy synchronously creates a Braze instance before you call any Braze push delegates