diff --git a/src/ios/dependencies/Branch-SDK/BNCConfig.m b/src/ios/dependencies/Branch-SDK/BNCConfig.m index 12b7b8c7..cc428b18 100644 --- a/src/ios/dependencies/Branch-SDK/BNCConfig.m +++ b/src/ios/dependencies/Branch-SDK/BNCConfig.m @@ -8,9 +8,12 @@ #include "BNCConfig.h" +#if defined(BNCTesting) +NSString * const BNC_API_BASE_URL = @"https://auhong.api.beta.branch.io"; +#else NSString * const BNC_API_BASE_URL = @"https://api.branch.io"; -//NSString * const BNC_API_BASE_URL = @"https://ahmed.api.beta.branch.io"; +#endif NSString * const BNC_API_VERSION = @"v1"; NSString * const BNC_LINK_URL = @"https://bnc.lt"; -NSString * const BNC_SDK_VERSION = @"0.12.27"; +NSString * const BNC_SDK_VERSION = @"0.13.5"; diff --git a/src/ios/dependencies/Branch-SDK/BNCDeviceInfo.h b/src/ios/dependencies/Branch-SDK/BNCDeviceInfo.h index f4953287..7b2dc119 100644 --- a/src/ios/dependencies/Branch-SDK/BNCDeviceInfo.h +++ b/src/ios/dependencies/Branch-SDK/BNCDeviceInfo.h @@ -35,5 +35,7 @@ //----------Methods----------------// + (BNCDeviceInfo *)getInstance; ++ (NSString*) userAgentString; // Warning: Has an implied lock on main thread on first call. ++ (NSString*) systemBuildVersion; @end diff --git a/src/ios/dependencies/Branch-SDK/BNCDeviceInfo.m b/src/ios/dependencies/Branch-SDK/BNCDeviceInfo.m index 9858179e..1572b7fe 100644 --- a/src/ios/dependencies/Branch-SDK/BNCDeviceInfo.m +++ b/src/ios/dependencies/Branch-SDK/BNCDeviceInfo.m @@ -9,6 +9,7 @@ #import #import +#import #import "BNCDeviceInfo.h" #import "BNCPreferenceHelper.h" #import "BNCSystemObserver.h" @@ -83,27 +84,107 @@ - (id)init { } + self.browserUserAgent = [self.class userAgentString]; + return self; +} + ++ (NSString*) systemBuildVersion { + int mib[2] = { CTL_KERN, KERN_OSVERSION }; + u_int namelen = sizeof(mib) / sizeof(mib[0]); + + // Get the size for the buffer -- + + size_t bufferSize = 0; + sysctl(mib, namelen, NULL, &bufferSize, NULL, 0); + if (bufferSize <= 0) return nil; + + u_char buildBuffer[bufferSize]; + int result = sysctl(mib, namelen, buildBuffer, &bufferSize, NULL, 0); + + NSString *version = nil; + if (result >= 0) { + version = [[NSString alloc] + initWithBytes:buildBuffer + length:bufferSize-1 + encoding:NSUTF8StringEncoding]; + } + return version; +} + + ++ (NSString*) userAgentString { + static NSString* browserUserAgentString = nil; + void (^setBrowserUserAgent)() = ^() { + if (!browserUserAgentString) { + browserUserAgentString = + [[[UIWebView alloc] + initWithFrame:CGRectZero] + stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"]; + BNCPreferenceHelper *preferences = [BNCPreferenceHelper preferenceHelper]; + preferences.browserUserAgentString = browserUserAgentString; + preferences.lastSystemBuildVersion = self.systemBuildVersion; + //NSLog(@"[Branch] userAgentString: '%@'.", browserUserAgentString); + } + }; + + // We only get the string once per app run: + + if (browserUserAgentString) + return browserUserAgentString; + + // Did we cache it? + + BNCPreferenceHelper *preferences = [BNCPreferenceHelper preferenceHelper]; + if (preferences.browserUserAgentString && + preferences.lastSystemBuildVersion && + [preferences.lastSystemBuildVersion isEqualToString:self.systemBuildVersion]) { + browserUserAgentString = [preferences.browserUserAgentString copy]; + return browserUserAgentString; + } - void (^setUpBrowserUserAgent)() = ^() { - browserUserAgentString = - [[[UIWebView alloc] - initWithFrame:CGRectZero] - stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"]; - self.browserUserAgent = browserUserAgentString; - }; - - @synchronized (self.class) { - if (browserUserAgentString) { - self.browserUserAgent = browserUserAgentString; - } else if (NSThread.isMainThread) { - setUpBrowserUserAgent(); - } else { - dispatch_sync(dispatch_get_main_queue(), setUpBrowserUserAgent); - } + // Make sure this executes on the main thread. + // Uses an implied lock through dispatch_queues: This can deadlock if mis-used! + + if (NSThread.isMainThread) { + setBrowserUserAgent(); + return browserUserAgentString; + } + + // Different case for iOS 7.0: + if ([UIDevice currentDevice].systemVersion.floatValue < 8.0) { + dispatch_sync(dispatch_get_main_queue(), ^ { + setBrowserUserAgent(); + }); + return browserUserAgentString; } - return self; + // Wait and yield to prevent deadlock: + + int retries = 10; + int64_t timeoutDelta = (dispatch_time_t)((long double)NSEC_PER_SEC * (long double)0.100); + while (!browserUserAgentString && retries > 0) { + + dispatch_block_t agentBlock = dispatch_block_create_with_qos_class( + DISPATCH_BLOCK_DETACHED | DISPATCH_BLOCK_ENFORCE_QOS_CLASS, + QOS_CLASS_USER_INTERACTIVE, + 0, ^ { + //NSLog(@"Will userAgent."); + setBrowserUserAgent(); + //NSLog(@"Did userAgent."); + }); + dispatch_async(dispatch_get_main_queue(), agentBlock); + + dispatch_time_t timeoutTime = dispatch_time(DISPATCH_TIME_NOW, timeoutDelta); + #if defined(BNCTesting) + long result = dispatch_block_wait(agentBlock, timeoutTime); + NSLog(@"Wait result: %ld.", result); + #else + dispatch_block_wait(agentBlock, timeoutTime); + #endif + retries--; + } + return browserUserAgentString; } @end diff --git a/src/ios/dependencies/Branch-SDK/BNCLinkCache.m b/src/ios/dependencies/Branch-SDK/BNCLinkCache.m index d0a0f1fb..e09cf7db 100644 --- a/src/ios/dependencies/Branch-SDK/BNCLinkCache.m +++ b/src/ios/dependencies/Branch-SDK/BNCLinkCache.m @@ -6,30 +6,34 @@ // Copyright (c) 2015 Branch Metrics. All rights reserved. // + #import "BNCLinkCache.h" -@interface BNCLinkCache () +@interface BNCLinkCache () @property (nonatomic, strong) NSMutableDictionary *cache; - @end + @implementation BNCLinkCache - (id)init { if (self = [super init]) { self.cache = [[NSMutableDictionary alloc] init]; } - return self; } - (void)setObject:(NSString *)anObject forKey:(BNCLinkData *)aKey { - self.cache[@([aKey hash])] = anObject; + @synchronized (self) { + self.cache[@([aKey hash])] = anObject; + } } - (NSString *)objectForKey:(BNCLinkData *)aKey { - return self.cache[@([aKey hash])]; + @synchronized (self) { + return self.cache[@([aKey hash])]; + } } @end diff --git a/src/ios/dependencies/Branch-SDK/BNCPreferenceHelper.h b/src/ios/dependencies/Branch-SDK/BNCPreferenceHelper.h index be3a7bf9..21b1c9d5 100644 --- a/src/ios/dependencies/Branch-SDK/BNCPreferenceHelper.h +++ b/src/ios/dependencies/Branch-SDK/BNCPreferenceHelper.h @@ -15,7 +15,7 @@ @property (strong, nonatomic) NSString *branchKey; @property (strong, nonatomic) NSString *lastRunBranchKey; -@property (strong, nonatomic) NSDate *lastStrongMatchDate; +@property (strong, nonatomic) NSDate *lastStrongMatchDate; @property (strong, nonatomic) NSString *appVersion; @property (strong, nonatomic) NSString *deviceFingerprintID; @property (strong, nonatomic) NSString *sessionID; @@ -39,6 +39,9 @@ @property (strong, nonatomic) NSMutableDictionary *savedAnalyticsData; @property (assign, nonatomic) NSInteger installRequestDelay; @property (strong, nonatomic) NSDictionary *appleSearchAdDetails; +@property (strong, nonatomic) NSString *lastSystemBuildVersion; +@property (strong, nonatomic) NSString *browserUserAgentString; +@property (strong) NSString *branchAPIURL; + (BNCPreferenceHelper *)preferenceHelper; + (NSURL*) URLForBranchDirectory; @@ -79,4 +82,7 @@ - (NSMutableDictionary *)getBranchAnalyticsData; - (NSDictionary *)getContentAnalyticsManifest; - (void)saveContentAnalyticsManifest:(NSDictionary *)cdManifest; + +- (void) save; // Flushes preference queue to persistence. + @end diff --git a/src/ios/dependencies/Branch-SDK/BNCPreferenceHelper.m b/src/ios/dependencies/Branch-SDK/BNCPreferenceHelper.m index 1f1c81d3..134758f0 100644 --- a/src/ios/dependencies/Branch-SDK/BNCPreferenceHelper.m +++ b/src/ios/dependencies/Branch-SDK/BNCPreferenceHelper.m @@ -47,7 +47,12 @@ // The name of this key was specified in the account-creation API integration static NSString * const BNC_BRANCH_FABRIC_APP_KEY_KEY = @"branch_key"; -@interface BNCPreferenceHelper () +@interface BNCPreferenceHelper () { + NSOperationQueue *_persistPrefsQueue; + NSString *_lastSystemBuildVersion; + NSString *_browserUserAgentString; + NSString *_branchAPIURL; +} @property (strong, nonatomic) NSMutableDictionary *persistenceDict; @property (strong, nonatomic) NSMutableDictionary *creditsDictionary; @@ -121,6 +126,11 @@ + (BNCPreferenceHelper *)getInstance { return preferenceHelper; } + +/* + + This creates one global queue. Not so desirable. + - (NSOperationQueue *)persistPrefsQueue { static NSOperationQueue *persistPrefsQueue; static dispatch_once_t persistOnceToken; @@ -132,6 +142,26 @@ - (NSOperationQueue *)persistPrefsQueue { return persistPrefsQueue; } +*/ + +- (NSOperationQueue *)persistPrefsQueue { + @synchronized (self) { + if (_persistPrefsQueue) + return _persistPrefsQueue; + _persistPrefsQueue = [[NSOperationQueue alloc] init]; + _persistPrefsQueue.maxConcurrentOperationCount = 1; + return _persistPrefsQueue; + } +} + +- (void) save { + // Flushes preference queue to persistence. + [_persistPrefsQueue waitUntilAllOperationsAreFinished]; +} + +- (void) dealloc { + [self save]; +} #pragma mark - Debug methods @@ -151,8 +181,25 @@ - (void)logWarning:(NSString *)message { } } +- (void) setBranchAPIURL:(NSString*)branchAPIURL_ { + @synchronized (self) { + _branchAPIURL = [branchAPIURL_ copy]; + } +} + +- (NSString*) branchAPIURL { + @synchronized (self) { + if (!_branchAPIURL) { + _branchAPIURL = [BNC_API_BASE_URL copy]; + } + return _branchAPIURL; + } +} + - (NSString *)getAPIBaseURL { - return [NSString stringWithFormat:@"%@/%@/", BNC_API_BASE_URL, BNC_API_VERSION]; + @synchronized (self) { + return [NSString stringWithFormat:@"%@/%@/", self.branchAPIURL, BNC_API_VERSION]; + } } - (NSString *)getAPIURL:(NSString *) endpoint { @@ -160,9 +207,14 @@ - (NSString *)getAPIURL:(NSString *) endpoint { } - (NSString *)getEndpointFromURL:(NSString *)url { - NSUInteger index = BNC_API_BASE_URL.length; - return [url substringFromIndex:index]; + NSString *APIBase = self.branchAPIURL; + if ([url hasPrefix:APIBase]) { + NSUInteger index = APIBase.length; + return [url substringFromIndex:index]; + } + return @""; } + #pragma mark - Preference Storage - (NSString *)getBranchKey:(BOOL)isLive { @@ -434,6 +486,34 @@ - (NSDictionary*) appleSearchAdDetails { return [_appleSearchAdDetails isKindOfClass:[NSDictionary class]] ? _appleSearchAdDetails : nil; } +- (NSString*) lastSystemBuildVersion { + if (!_lastSystemBuildVersion) { + _lastSystemBuildVersion = [self readStringFromDefaults:@"_lastSystemBuildVersion"]; + } + return _lastSystemBuildVersion; +} + +- (void) setLastSystemBuildVersion:(NSString *)lastSystemBuildVersion { + if (![_lastSystemBuildVersion isEqualToString:lastSystemBuildVersion]) { + _lastSystemBuildVersion = lastSystemBuildVersion; + [self writeObjectToDefaults:@"_lastSystemBuildVersion" value:_lastSystemBuildVersion]; + } +} + +- (NSString*) browserUserAgentString { + if (!_browserUserAgentString) { + _browserUserAgentString = [self readStringFromDefaults:@"_browserUserAgentString"]; + } + return _browserUserAgentString; +} + +- (void) setBrowserUserAgentString:(NSString *)browserUserAgentString { + if (![_browserUserAgentString isEqualToString:browserUserAgentString]) { + _browserUserAgentString = browserUserAgentString; + [self writeObjectToDefaults:@"_browserUserAgentString" value:_browserUserAgentString]; + } +} + - (NSString *)userUrl { if (!_userUrl) { _userUrl = [self readStringFromDefaults:BRANCH_PREFS_KEY_USER_URL]; @@ -672,10 +752,10 @@ - (void)persistPrefsToDisk { [self logWarning:@"Can't create preferences data."]; return; } + NSURL *prefsURL = self.class.URLForPrefsFile; NSBlockOperation *newPersistOp = [NSBlockOperation blockOperationWithBlock:^ { NSError *error = nil; - [data writeToURL:self.class.URLForPrefsFile - options:NSDataWritingAtomic error:&error]; + [data writeToURL:prefsURL options:NSDataWritingAtomic error:&error]; if (error) { [self logWarning: [NSString stringWithFormat: @@ -810,7 +890,8 @@ + (NSURL* _Nonnull) URLForPrefsFile { } + (void) moveOldPrefsFile { - NSURL *oldURL = [NSURL fileURLWithPath:self.prefsFile_deprecated]; + NSString* oldPath = self.prefsFile_deprecated; + NSURL *oldURL = (oldPath) ? [NSURL fileURLWithPath:self.prefsFile_deprecated] : nil; NSURL *newURL = [self URLForPrefsFile]; if (!oldURL || !newURL) { return; } diff --git a/src/ios/dependencies/Branch-SDK/BNCServerInterface.m b/src/ios/dependencies/Branch-SDK/BNCServerInterface.m index 960e4539..771f6376 100644 --- a/src/ios/dependencies/Branch-SDK/BNCServerInterface.m +++ b/src/ios/dependencies/Branch-SDK/BNCServerInterface.m @@ -139,10 +139,9 @@ - (void)genericHTTPRequest:(NSURLRequest *)request retryNumber:(NSInteger)retryN } } - dispatch_async(dispatch_get_main_queue(), ^{ - if (callback) - callback(serverResponse, error); - }); + // Don't call on the main queue since it might be blocked. + if (callback) + callback(serverResponse, error); }; NSURLConnectionCompletionHandler connectionHandler = ^void(NSURLResponse *response, NSData *responseData, NSError *error) { @@ -294,11 +293,15 @@ - (void) collectInstrumentationMetrics { } - (void)updateDeviceInfoToMutableDictionary:(NSMutableDictionary *)dict { BNCDeviceInfo *deviceInfo = [BNCDeviceInfo getInstance]; - - if (deviceInfo.hardwareId && deviceInfo.hardwareIdType) { - dict[BRANCH_REQUEST_KEY_HARDWARE_ID] = deviceInfo.hardwareId; - dict[BRANCH_REQUEST_KEY_HARDWARE_ID_TYPE] = deviceInfo.hardwareIdType; - dict[BRANCH_REQUEST_KEY_IS_HARDWARE_ID_REAL] = @(deviceInfo.isRealHardwareId); + + NSString *hardwareId = [deviceInfo.hardwareId copy]; + NSString *hardwareIdType = [deviceInfo.hardwareIdType copy]; + NSNumber *isRealHardwareId = @(deviceInfo.isRealHardwareId); + + if (hardwareId && hardwareIdType && isRealHardwareId) { + dict[BRANCH_REQUEST_KEY_HARDWARE_ID] = hardwareId; + dict[BRANCH_REQUEST_KEY_HARDWARE_ID_TYPE] = hardwareIdType; + dict[BRANCH_REQUEST_KEY_IS_HARDWARE_ID_REAL] = isRealHardwareId; } [self safeSetValue:deviceInfo.vendorId forKey:BRANCH_REQUEST_KEY_IOS_VENDOR_ID onDict:dict]; diff --git a/src/ios/dependencies/Branch-SDK/BNCServerRequestQueue.m b/src/ios/dependencies/Branch-SDK/BNCServerRequestQueue.m index b59538eb..9288fed2 100755 --- a/src/ios/dependencies/Branch-SDK/BNCServerRequestQueue.m +++ b/src/ios/dependencies/Branch-SDK/BNCServerRequestQueue.m @@ -215,11 +215,9 @@ - (void)persistToDisk { if ([req isKindOfClass:[BranchCloseRequest class]]) { continue; } - NSData *encodedReq = [NSKeyedArchiver archivedDataWithRootObject:req]; - [encodedRequests addObject:encodedReq]; + if (encodedReq) [encodedRequests addObject:encodedReq]; } - NSData *data = [NSKeyedArchiver archivedDataWithRootObject:encodedRequests]; if (!data) { [[BNCPreferenceHelper preferenceHelper] @@ -246,20 +244,27 @@ - (void)persistToDisk { - (void)retrieve { NSMutableArray *queue = [[NSMutableArray alloc] init]; - NSArray *encodedRequests; + NSArray *encodedRequests = nil; // Capture exception while loading the queue file @try { NSError *error = nil; NSData *data = [NSData dataWithContentsOfURL:self.class.URLForQueueFile options:0 error:&error]; - if (!error && data) + if ([error.domain isEqualToString:NSCocoaErrorDomain] && error.code == NSFileReadNoSuchFileError) { + encodedRequests = [NSArray new]; + } else if (!error && data) encodedRequests = [NSKeyedUnarchiver unarchiveObjectWithData:data]; + if (![encodedRequests isKindOfClass:[NSArray class]]) { + @throw [NSException exceptionWithName:NSInvalidArgumentException + reason:@"Saved server queue is invalid." userInfo:nil]; + } } @catch (NSException *exception) { NSString *warningMessage = [NSString stringWithFormat: - @"An exception occurred while attempting to load the queue file, proceeding without requests. Exception information:\n\n%@", - [self exceptionString:exception]]; + @"An exception occurred while attempting to load the queue file, " + "proceeding without requests. Exception information:\n\n%@", + [self exceptionString:exception]]; [[BNCPreferenceHelper preferenceHelper] logWarning:warningMessage]; self.queue = queue; return; @@ -273,7 +278,8 @@ - (void)retrieve { request = [NSKeyedUnarchiver unarchiveObjectWithData:encodedRequest]; } @catch (NSException *exception) { - [[BNCPreferenceHelper preferenceHelper] logWarning:@"An exception occurred while attempting to parse a queued request, discarding."]; + [[BNCPreferenceHelper preferenceHelper] + logWarning:@"An exception occurred while attempting to parse a queued request, discarding."]; continue; } diff --git a/src/ios/dependencies/Branch-SDK/BNCStrongMatchHelper.m b/src/ios/dependencies/Branch-SDK/BNCStrongMatchHelper.m index 5dc27219..499d235b 100644 --- a/src/ios/dependencies/Branch-SDK/BNCStrongMatchHelper.m +++ b/src/ios/dependencies/Branch-SDK/BNCStrongMatchHelper.m @@ -302,7 +302,7 @@ - (BOOL) willLoadViewControllerWithURL:(NSURL*)matchURL { objc_registerClassPair(BNCMatchViewControllerSubclass); } - NSLog(@"Safari initializing."); // eDebug + //NSLog(@"Safari initializing."); // eDebug self.primaryWindow = [self keyWindow]; self.matchViewController = [[BNCMatchViewControllerSubclass alloc] initWithURL:matchURL]; @@ -327,7 +327,7 @@ - (BOOL) willLoadViewControllerWithURL:(NSURL*)matchURL { } - (void) unloadViewController { - NSLog(@"Safari unloadViewController"); // eDebug + //NSLog(@"Safari unloadViewController"); // eDebug [self.matchViewController willMoveToParentViewController:nil]; [self.matchViewController.view removeFromSuperview]; @@ -347,7 +347,7 @@ - (void) unloadViewController { - (void)safariViewController:(SFSafariViewController *)controller didCompleteInitialLoad:(BOOL)didLoadSuccessfully { - NSLog(@"Safari Did load. Success: %d.", didLoadSuccessfully); // eDebug + //NSLog(@"Safari Did load. Success: %d.", didLoadSuccessfully); // eDebug [self unloadViewController]; } diff --git a/src/ios/dependencies/Branch-SDK/Branch.h b/src/ios/dependencies/Branch-SDK/Branch.h index a0924e88..0ddac3e9 100644 --- a/src/ios/dependencies/Branch-SDK/Branch.h +++ b/src/ios/dependencies/Branch-SDK/Branch.h @@ -520,6 +520,13 @@ typedef NS_ENUM(NSUInteger, BranchCreditHistoryOrder) { */ - (NSDictionary *)getLatestReferringParams; +/** + Returns the most recent referral parameters for this user. An empty object can be returned. + This call blocks the calling thread until the latest results are available. + @warning This call blocks the calling thread. + */ +- (NSDictionary*) getLatestReferringParamsSynchronous; + /** Tells Branch to act as though initSession hadn't been called. Will require another open call (this is done automatically, internally). */ diff --git a/src/ios/dependencies/Branch-SDK/Branch.m b/src/ios/dependencies/Branch-SDK/Branch.m index 0bbe3e88..19f361a4 100644 --- a/src/ios/dependencies/Branch-SDK/Branch.m +++ b/src/ios/dependencies/Branch-SDK/Branch.m @@ -86,7 +86,6 @@ @interface Branch() @property (strong, nonatomic) BNCServerInterface *bServerInterface; @property (strong, nonatomic) BNCServerRequestQueue *requestQueue; -@property (strong, nonatomic) NSTimer *sessionTimer; @property (strong, nonatomic) dispatch_semaphore_t processing_sema; @property (copy, nonatomic) callbackWithParams sessionInitWithParamsCallback; @property (copy, nonatomic) callbackWithBranchUniversalObject sessionInitWithBranchUniversalObjectCallback; @@ -180,7 +179,9 @@ - (id)initWithInterface:(BNCServerInterface *)interface queue:(BNCServerRequestQ _deepLinkControllers = [[NSMutableDictionary alloc] init]; _whiteListedSchemeList = [[NSMutableArray alloc] init]; _useCookieBasedMatching = YES; - + + [BranchOpenRequest setWaitNeededForOpenResponseLock]; + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; [notificationCenter addObserver:self selector:@selector(applicationWillResignActive) name:UIApplicationWillResignActiveNotification object:nil]; [notificationCenter addObserver:self selector:@selector(applicationDidBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil]; @@ -564,7 +565,7 @@ - (BOOL)checkAppleSearchAdsAttribution { NSMutableDictionary *testDetails = [[NSMutableDictionary alloc] init]; [testDetails setObject:[NSNumber numberWithBool:YES] forKey:@"iad-attribution"]; [testDetails setObject:[NSNumber numberWithInteger:1234567890] forKey:@"iad-campaign-id"]; - [testDetails setObject:@"CampaignName" forKey:@"iad-campaign-name"]; + [testDetails setObject:@"DebugAppleSearchAdsCampaignName" forKey:@"iad-campaign-name"]; [testDetails setObject:@"2016-09-09T01:33:17Z" forKey:@"iad-click-date"]; [testDetails setObject:@"2016-09-09T01:33:17Z" forKey:@"iad-conversion-date"]; [testDetails setObject:[NSNumber numberWithInteger:1234567890] forKey:@"iad-creative-id"]; @@ -856,6 +857,13 @@ - (NSDictionary *)getLatestReferringParams { return origSessionParams; } +- (NSDictionary*) getLatestReferringParamsSynchronous { + [BranchOpenRequest waitForOpenResponseLock]; + NSDictionary *result = [self getLatestReferringParams]; + [BranchOpenRequest releaseOpenResponseLock]; + return result; +} + - (BranchUniversalObject *)getLatestReferringBranchUniversalObject { NSDictionary *params = [self getLatestReferringParams]; if ([[params objectForKey:BRANCH_INIT_KEY_CLICKED_BRANCH_LINK] isEqual:@1]) { @@ -1131,17 +1139,50 @@ - (void)generateShortUrl:(NSArray *)tags andAlias:(NSString *)alias andType:(Bra [self processNextQueueItem]; } -- (NSString *)generateShortUrl:(NSArray *)tags andAlias:(NSString *)alias andType:(BranchLinkType)type andMatchDuration:(NSUInteger)duration andChannel:(NSString *)channel andFeature:(NSString *)feature andStage:(NSString *)stage andCampaign:(NSString *)campaign andParams:(NSDictionary *)params ignoreUAString:(NSString *)ignoreUAString forceLinkCreation:(BOOL)forceLinkCreation { +- (NSString *)generateShortUrl:(NSArray *)tags + andAlias:(NSString *)alias + andType:(BranchLinkType)type + andMatchDuration:(NSUInteger)duration + andChannel:(NSString *)channel + andFeature:(NSString *)feature + andStage:(NSString *)stage + andCampaign:(NSString *)campaign + andParams:(NSDictionary *)params + ignoreUAString:(NSString *)ignoreUAString + forceLinkCreation:(BOOL)forceLinkCreation { + NSString *shortURL = nil; - BNCLinkData *linkData = [self prepareLinkDataFor:tags andAlias:alias andType:type andMatchDuration:duration andChannel:channel andFeature:feature andStage:stage andCampaign:campaign andParams:params ignoreUAString:ignoreUAString]; + BNCLinkData *linkData = + [self prepareLinkDataFor:tags + andAlias:alias + andType:type + andMatchDuration:duration + andChannel:channel + andFeature:feature + andStage:stage + andCampaign:campaign + andParams:params + ignoreUAString:ignoreUAString]; - // If an ignore UA string is present, we always get a new url. Otherwise, if we've already seen this request, use the cached version + // If an ignore UA string is present, we always get a new url. + // Otherwise, if we've already seen this request, use the cached version. if (!ignoreUAString && [self.linkCache objectForKey:linkData]) { shortURL = [self.linkCache objectForKey:linkData]; - } - else { - BranchShortUrlSyncRequest *req = [[BranchShortUrlSyncRequest alloc] initWithTags:tags alias:alias type:type matchDuration:duration channel:channel feature:feature stage:stage campaign:campaign params:params linkData:linkData linkCache:self.linkCache]; + } else { + BranchShortUrlSyncRequest *req = + [[BranchShortUrlSyncRequest alloc] + initWithTags:tags + alias:alias + type:type + matchDuration:duration + channel:channel + feature:feature + stage:stage + campaign:campaign + params:params + linkData:linkData + linkCache:self.linkCache]; if (self.isInitialized) { [self.preferenceHelper log:FILE_NAME line:LINE_NUM message:@"Created custom url synchronously"]; @@ -1152,11 +1193,12 @@ - (NSString *)generateShortUrl:(NSArray *)tags andAlias:(NSString *)alias andTyp if (shortURL) { [self.linkCache setObject:shortURL forKey:linkData]; } - } - else { + } else { if (forceLinkCreation) { if (self.branchKey) { - return [BranchShortUrlSyncRequest createLinkFromBranchKey:self.branchKey tags:tags alias:alias type:type matchDuration:duration channel:channel feature:feature stage:stage params:params]; + return [BranchShortUrlSyncRequest createLinkFromBranchKey:self.branchKey + tags:tags alias:alias type:type matchDuration:duration + channel:channel feature:feature stage:stage params:params]; } } NSLog(@"Branch SDK Error: making request before init succeeded!"); @@ -1166,13 +1208,29 @@ - (NSString *)generateShortUrl:(NSArray *)tags andAlias:(NSString *)alias andTyp return shortURL; } -- (NSString *)generateLongURLWithParams:(NSDictionary *)params andChannel:(NSString *)channel andTags:(NSArray *)tags andFeature:(NSString *)feature andStage:(NSString *)stage andAlias:(NSString *)alias { +- (NSString *)generateLongURLWithParams:(NSDictionary *)params + andChannel:(NSString *)channel + andTags:(NSArray *)tags + andFeature:(NSString *)feature + andStage:(NSString *)stage + andAlias:(NSString *)alias { + NSString *baseLongUrl = [NSString stringWithFormat:@"%@/a/%@", BNC_LINK_URL, self.branchKey]; - return [self longUrlWithBaseUrl:baseLongUrl params:params tags:tags feature:feature channel:nil stage:stage alias:alias duration:0 type:BranchLinkTypeUnlimitedUse]; + return [self longUrlWithBaseUrl:baseLongUrl params:params tags:tags feature:feature + channel:nil stage:stage alias:alias duration:0 type:BranchLinkTypeUnlimitedUse]; } -- (NSString *)longUrlWithBaseUrl:(NSString *)baseUrl params:(NSDictionary *)params tags:(NSArray *)tags feature:(NSString *)feature channel:(NSString *)channel stage:(NSString *)stage alias:(NSString *)alias duration:(NSUInteger)duration type:(BranchLinkType)type { +- (NSString *)longUrlWithBaseUrl:(NSString *)baseUrl + params:(NSDictionary *)params + tags:(NSArray *)tags + feature:(NSString *)feature + channel:(NSString *)channel + stage:(NSString *)stage + alias:(NSString *)alias + duration:(NSUInteger)duration + type:(BranchLinkType)type { + NSMutableString *longUrl = [[NSMutableString alloc] initWithFormat:@"%@?", baseUrl]; for (NSString *tag in tags) { @@ -1208,7 +1266,17 @@ - (NSString *)longUrlWithBaseUrl:(NSString *)baseUrl params:(NSDictionary *)para return longUrl; } -- (BNCLinkData *)prepareLinkDataFor:(NSArray *)tags andAlias:(NSString *)alias andType:(BranchLinkType)type andMatchDuration:(NSUInteger)duration andChannel:(NSString *)channel andFeature:(NSString *)feature andStage:(NSString *)stage andCampaign:(NSString *)campaign andParams:(NSDictionary *)params ignoreUAString:(NSString *)ignoreUAString { +- (BNCLinkData *)prepareLinkDataFor:(NSArray *)tags + andAlias:(NSString *)alias + andType:(BranchLinkType)type + andMatchDuration:(NSUInteger)duration + andChannel:(NSString *)channel + andFeature:(NSString *)feature + andStage:(NSString *)stage + andCampaign:(NSString *)campaign + andParams:(NSDictionary *)params + ignoreUAString:(NSString *)ignoreUAString { + BNCLinkData *post = [[BNCLinkData alloc] init]; [post setupType:type]; @@ -1241,16 +1309,15 @@ - (void)registerViewWithParams:(NSDictionary *)params andCallback:(callbackWithP #pragma mark - Application State Change methods - (void)applicationDidBecomeActive { - [self clearTimer]; if (!self.isInitialized && !self.preferenceHelper.shouldWaitForInit && ![self.requestQueue containsInstallOrOpen]) { [self initUserSessionAndCallCallback:YES]; } } - (void)applicationWillResignActive { - [self clearTimer]; - self.sessionTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(callClose) userInfo:nil repeats:NO]; + [self callClose]; [self.requestQueue persistImmediately]; + [BranchOpenRequest setWaitNeededForOpenResponseLock]; } - (void)callClose { @@ -1259,7 +1326,7 @@ - (void)callClose { BranchContentDiscoverer *contentDiscoverer = [BranchContentDiscoverer getInstance]; if (contentDiscoverer) { - [contentDiscoverer stopContentDiscoveryTask]; + [contentDiscoverer stopDiscoveryTask]; } if (self.preferenceHelper.sessionID && ![self.requestQueue containsClose]) { @@ -1271,9 +1338,6 @@ - (void)callClose { } } -- (void)clearTimer { - [self.sessionTimer invalidate]; -} #pragma mark - Queue management @@ -1286,72 +1350,93 @@ - (void)insertRequestAtFront:(BNCServerRequest *)req { } } +void BNCPerformBlockOnMainThreadSync(dispatch_block_t block) { + if ([NSThread isMainThread]) { + block(); + } else { + dispatch_sync(dispatch_get_main_queue(), block); + } +} + +void BNCPerformBlockOnMainThread(dispatch_block_t block) { + dispatch_async(dispatch_get_main_queue(), block); +} + +- (void) processRequest:(BNCServerRequest*)req response:(BNCServerResponse*)response error:(NSError*)error { + // If the request was successful, or was a bad user request, continue processing. + if (!error || error.code == BNCBadRequestError || error.code == BNCDuplicateResourceError) { + + BNCPerformBlockOnMainThreadSync(^{ [req processResponse:response error:error]; }); + + [self.requestQueue dequeue]; + self.networkCount = 0; + [self processNextQueueItem]; + } + // On network problems, or Branch down, call the other callbacks and stop processing. + else { + // First, gather all the requests to fail + NSMutableArray *requestsToFail = [[NSMutableArray alloc] init]; + for (int i = 0; i < self.requestQueue.size; i++) { + BNCServerRequest *request = [self.requestQueue peekAt:i]; + if (request) { + [requestsToFail addObject:request]; + } + } + + // Next, remove all the requests that should not be replayed. Note, we do this before + // calling callbacks, in case any of the callbacks try to kick off another request, which + // could potentially start another request (and call these callbacks again) + for (BNCServerRequest *request in requestsToFail) { + if (![request isKindOfClass:[BranchUserCompletedActionRequest class]] && + ![request isKindOfClass:[BranchSetIdentityRequest class]]) { + [self.requestQueue remove:request]; + } + } + + // Then, set the network count to zero, indicating that requests can be started again + self.networkCount = 0; + + // Finally, call all the requests callbacks with the error + for (BNCServerRequest *request in requestsToFail) { + BNCPerformBlockOnMainThreadSync(^ { [request processResponse:nil error:error]; }); + } + } +} + - (void)processNextQueueItem { dispatch_semaphore_wait(self.processing_sema, DISPATCH_TIME_FOREVER); if (self.networkCount == 0 && self.requestQueue.size > 0 && !self.preferenceHelper.shouldWaitForInit) { self.networkCount = 1; dispatch_semaphore_signal(self.processing_sema); - BNCServerRequest *req = [self.requestQueue peek]; if (req) { - BNCServerCallback callback = ^(BNCServerResponse *response, NSError *error) { - // If the request was successful, or was a bad user request, continue processing. - if (!error || error.code == BNCBadRequestError || error.code == BNCDuplicateResourceError) { - [req processResponse:response error:error]; - - [self.requestQueue dequeue]; - self.networkCount = 0; - [self processNextQueueItem]; - } - // On network problems, or Branch down, call the other callbacks and stop processing. - else { - // First, gather all the requests to fail - NSMutableArray *requestsToFail = [[NSMutableArray alloc] init]; - for (int i = 0; i < self.requestQueue.size; i++) { - BNCServerRequest *request = [self.requestQueue peekAt:i]; - if (request) { - [requestsToFail addObject:request]; - } - } - - // Next, remove all the requests that should not be replayed. Note, we do this before calling callbacks, in case any - // of the callbacks try to kick off another request, which could potentially start another request (and call these callbacks again) - for (BNCServerRequest *request in requestsToFail) { - if (![request isKindOfClass:[BranchUserCompletedActionRequest class]] && ![request isKindOfClass:[BranchSetIdentityRequest class]]) { - [self.requestQueue remove:request]; - } - } - - // Then, set the network count to zero, indicating that requests can be started again - self.networkCount = 0; - - // Finally, call all the requests callbacks with the error - for (BNCServerRequest *request in requestsToFail) { - [request processResponse:nil error:error]; - } - } - }; - + if (![req isKindOfClass:[BranchInstallRequest class]] && !self.preferenceHelper.identityID) { NSLog(@"[Branch Error] User session has not been initialized!"); - [req processResponse:nil error:[NSError errorWithDomain:BNCErrorDomain code:BNCInitError userInfo:@{ NSLocalizedDescriptionKey: @"Branch User Session has not been initialized" }]]; + BNCPerformBlockOnMainThreadSync(^{ + [req processResponse:nil error:[NSError errorWithDomain:BNCErrorDomain code:BNCInitError + userInfo:@{ NSLocalizedDescriptionKey: @"Branch User Session has not been initialized" }]]; + }); return; } - else if (![req isKindOfClass:[BranchOpenRequest class]] && (!self.preferenceHelper.deviceFingerprintID || !self.preferenceHelper.sessionID)) { + else if (![req isKindOfClass:[BranchOpenRequest class]] && + (!self.preferenceHelper.deviceFingerprintID || !self.preferenceHelper.sessionID)) { NSLog(@"[Branch Error] Missing session items!"); - [req processResponse:nil error:[NSError errorWithDomain:BNCErrorDomain code:BNCInitError userInfo:@{ NSLocalizedDescriptionKey: @"Branch User Session has not been initialized" }]]; + BNCPerformBlockOnMainThreadSync(^{ + [req processResponse:nil error:[NSError errorWithDomain:BNCErrorDomain code:BNCInitError + userInfo:@{ NSLocalizedDescriptionKey: @"Branch User Session has not been initialized" }]]; + }); return; } - if (![req isKindOfClass:[BranchCloseRequest class]]) { - [self clearTimer]; - } - dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); dispatch_async(queue, ^ { - [req makeRequest:self.bServerInterface key:self.branchKey callback:callback]; + [req makeRequest:self.bServerInterface key:self.branchKey callback: + ^(BNCServerResponse* response, NSError* error) { + [self processRequest:req response:response error:error]; + }]; }); } } @@ -1363,6 +1448,7 @@ - (void)processNextQueueItem { #pragma mark - Session Initialization + - (void)initSessionIfNeededAndNotInProgress { if (!self.isInitialized && !self.preferenceHelper.shouldWaitForInit && ![self.requestQueue containsInstallOrOpen]) { [self initUserSessionAndCallCallback:NO]; @@ -1382,7 +1468,11 @@ - (void)initUserSessionAndCallCallback:(BOOL)callCallback { self.sessionInitWithParamsCallback([self getLatestReferringParams], nil); } else if (self.sessionInitWithBranchUniversalObjectCallback) { - self.sessionInitWithBranchUniversalObjectCallback([self getLatestReferringBranchUniversalObject], [self getLatestReferringBranchLinkProperties], nil); + self.sessionInitWithBranchUniversalObjectCallback( + [self getLatestReferringBranchUniversalObject], + [self getLatestReferringBranchLinkProperties], + nil + ); } } } @@ -1396,45 +1486,49 @@ - (void)initializeSession { [self.preferenceHelper logWarning:@"You are using your test app's Branch Key. Remember to change it to live Branch Key for deployment."]; } - if (!self.preferenceHelper.identityID) { - [self registerInstallOrOpen:[BranchInstallRequest class]]; - } - else { - [self registerInstallOrOpen:[BranchOpenRequest class]]; - } -} + Class clazz = [BranchInstallRequest class]; + if (self.preferenceHelper.identityID) { + clazz = [BranchOpenRequest class]; + } -- (void)registerInstallOrOpen:(Class)clazz { callbackWithStatus initSessionCallback = ^(BOOL success, NSError *error) { - if (error) { - [self handleInitFailure:error]; - } - else { - [self handleInitSuccess]; - } + dispatch_async(dispatch_get_main_queue(), ^ { + if (error) { + [self handleInitFailure:error]; + } else { + [self handleInitSuccess]; + } + }); }; - + if ([BNCSystemObserver getOSVersion].integerValue >= 9 && self.useCookieBasedMatching) { [[BNCStrongMatchHelper strongMatchHelper] createStrongMatchWithBranchKey:self.branchKey]; } - if ([self.requestQueue removeInstallOrOpen]) - self.networkCount = 0; - BranchOpenRequest *req = [[clazz alloc] initWithCallback:initSessionCallback]; - [self insertRequestAtFront:req]; - [self processNextQueueItem]; + @synchronized (self) { + if ([self.requestQueue removeInstallOrOpen]) + self.networkCount = 0; + [BranchOpenRequest setWaitNeededForOpenResponseLock]; + BranchOpenRequest *req = [[clazz alloc] initWithCallback:initSessionCallback]; + [self insertRequestAtFront:req]; + [self processNextQueueItem]; + } } - (void)handleInitSuccess { + self.isInitialized = YES; - NSDictionary *latestReferringParams = [self getLatestReferringParams]; if (self.shouldCallSessionInitCallback) { if (self.sessionInitWithParamsCallback) { self.sessionInitWithParamsCallback(latestReferringParams, nil); } else if (self.sessionInitWithBranchUniversalObjectCallback) { - self.sessionInitWithBranchUniversalObjectCallback([self getLatestReferringBranchUniversalObject], [self getLatestReferringBranchLinkProperties], nil); + self.sessionInitWithBranchUniversalObjectCallback( + [self getLatestReferringBranchUniversalObject], + [self getLatestReferringBranchLinkProperties], + nil + ); } } @@ -1454,7 +1548,8 @@ - (void)handleInitSuccess { [branchSharingController configureControlWithData:latestReferringParams]; } else { - [self.preferenceHelper log:FILE_NAME line:LINE_NUM message:@"[Branch Warning] View controller does not implement configureControlWithData:"]; + [self.preferenceHelper log:FILE_NAME line:LINE_NUM message: + @"[Branch Warning] View controller does not implement configureControlWithData:"]; } branchSharingController.deepLinkingCompletionDelegate = self; self.deepLinkPresentingController = [[[UIApplicationClass sharedApplication].delegate window] rootViewController]; @@ -1495,7 +1590,7 @@ - (void)deepLinkingControllerCompleted { [self.deepLinkPresentingController dismissViewControllerAnimated:YES completion:NULL]; } -#pragma mark FABKit methods +#pragma mark - FABKit methods + (NSString *)bundleIdentifier { return @"io.branch.sdk.ios"; diff --git a/src/ios/dependencies/Branch-SDK/BranchConstants.h b/src/ios/dependencies/Branch-SDK/BranchConstants.h index 44f4ac41..5ad1449c 100644 --- a/src/ios/dependencies/Branch-SDK/BranchConstants.h +++ b/src/ios/dependencies/Branch-SDK/BranchConstants.h @@ -88,6 +88,7 @@ extern NSString * const BRANCH_RESPONSE_KEY_DEVICE_FINGERPRINT_ID; extern NSString * const BRANCH_RESPONSE_KEY_SESSION_DATA; extern NSString * const BRANCH_RESPONSE_KEY_CLICKED_BRANCH_LINK; extern NSString * const BRANCH_RESPONSE_KEY_BRANCH_VIEW_DATA; +extern NSString * const BRANCH_RESPONSE_KEY_BRANCH_REFERRING_LINK; extern NSString * const BRANCH_LINK_DATA_KEY_OG_TITLE; extern NSString * const BRANCH_LINK_DATA_KEY_OG_DESCRIPTION; diff --git a/src/ios/dependencies/Branch-SDK/BranchConstants.m b/src/ios/dependencies/Branch-SDK/BranchConstants.m index 0477a60b..ddacc389 100644 --- a/src/ios/dependencies/Branch-SDK/BranchConstants.m +++ b/src/ios/dependencies/Branch-SDK/BranchConstants.m @@ -87,6 +87,7 @@ NSString * const BRANCH_RESPONSE_KEY_SESSION_DATA = @"data"; NSString * const BRANCH_RESPONSE_KEY_CLICKED_BRANCH_LINK = @"+clicked_branch_link"; NSString * const BRANCH_RESPONSE_KEY_BRANCH_VIEW_DATA = @"branch_view_data"; +NSString * const BRANCH_RESPONSE_KEY_BRANCH_REFERRING_LINK = @"~referring_link"; NSString * const BRANCH_LINK_DATA_KEY_OG_TITLE = @"$og_title"; NSString * const BRANCH_LINK_DATA_KEY_OG_DESCRIPTION = @"$og_description"; diff --git a/src/ios/dependencies/Branch-SDK/BranchContentDiscoverer.h b/src/ios/dependencies/Branch-SDK/BranchContentDiscoverer.h index e696e905..21071099 100644 --- a/src/ios/dependencies/Branch-SDK/BranchContentDiscoverer.h +++ b/src/ios/dependencies/Branch-SDK/BranchContentDiscoverer.h @@ -5,21 +5,19 @@ // Created by Sojan P.R. on 8/17/16. // Copyright © 2016 Branch Metrics. All rights reserved. // -#import -#import "BranchContentDiscoveryManifest.h" -#ifndef ContentDiscoverer_h -#define ContentDiscoverer_h +#import +#import "BranchContentDiscoveryManifest.h" -#endif /* ContentDiscoverer_h */ @interface BranchContentDiscoverer : NSObject //----------- Methods ----------------// -+ (BranchContentDiscoverer *)getInstance:(BranchContentDiscoveryManifest *)manifest; + (BranchContentDiscoverer *)getInstance; -- (void)startContentDiscoveryTask; -- (void)stopContentDiscoveryTask; +- (void) startDiscoveryTaskWithManifest:(BranchContentDiscoveryManifest*)manifest; +- (void) startDiscoveryTask; +- (void) stopDiscoveryTask; +@property (nonatomic, strong) BranchContentDiscoveryManifest* contentManifest; @end diff --git a/src/ios/dependencies/Branch-SDK/BranchContentDiscoverer.m b/src/ios/dependencies/Branch-SDK/BranchContentDiscoverer.m index e0445cc4..0aaae65d 100644 --- a/src/ios/dependencies/Branch-SDK/BranchContentDiscoverer.m +++ b/src/ios/dependencies/Branch-SDK/BranchContentDiscoverer.m @@ -6,6 +6,7 @@ // Copyright © 2016 Branch Metrics. All rights reserved. // + #import #import "BranchContentDiscoverer.h" #import "BranchContentDiscoveryManifest.h" @@ -16,57 +17,63 @@ #import #import "BNCEncodingUtils.h" -@interface BranchContentDiscoverer () +@interface BranchContentDiscoverer () @property (nonatomic, strong) NSString *lastViewControllerName; @property (nonatomic, strong) NSTimer *contentDiscoveryTimer; -@property (nonatomic, strong) BranchContentDiscoveryManifest *cdManifest; @property (nonatomic) NSInteger numOfViewsDiscovered; - @end @implementation BranchContentDiscoverer -static BranchContentDiscoverer *contentViewHandler; -static NSInteger const CONTENT_DISCOVERY_INTERVAL = 5; - - -+ (BranchContentDiscoverer *)getInstance:(BranchContentDiscoveryManifest *)manifest { - if (!contentViewHandler) { - contentViewHandler = [[BranchContentDiscoverer alloc] init]; ++ (BranchContentDiscoverer *)getInstance { + static BranchContentDiscoverer *sharedInstance = nil; + @synchronized (self) { + if (!sharedInstance) { + sharedInstance = [[BranchContentDiscoverer alloc] init]; + } + return sharedInstance; } - [contentViewHandler initInstance:manifest]; - return contentViewHandler; } -+ (BranchContentDiscoverer *)getInstance { - return contentViewHandler; +- (void) dealloc { + [_contentDiscoveryTimer invalidate]; } -- (void)initInstance:(BranchContentDiscoveryManifest *)manifest { +- (void) setContentManifest:(BranchContentDiscoveryManifest*)manifest { _numOfViewsDiscovered = 0; - _cdManifest = manifest; - + _contentManifest = manifest; } -- (void)startContentDiscoveryTask { - _contentDiscoveryTimer = [NSTimer scheduledTimerWithTimeInterval:CONTENT_DISCOVERY_INTERVAL - target:self - selector:@selector(readContentDataIfNeeded) - userInfo:nil - repeats:YES]; +- (void) startDiscoveryTaskWithManifest:(BranchContentDiscoveryManifest*)manifest { + self.contentManifest = manifest; + [self startDiscoveryTask]; } -- (void)stopContentDiscoveryTask { +- (void)startDiscoveryTask { + if (![NSThread isMainThread]) { + NSLog(@"Error: Should be called on main thread!"); + } + [_contentDiscoveryTimer invalidate]; + _contentDiscoveryTimer = + [NSTimer scheduledTimerWithTimeInterval:1.0 + target:self + selector:@selector(readContentDataIfNeeded) + userInfo:nil + repeats:YES]; +} + +- (void)stopDiscoveryTask { _lastViewControllerName = nil; if (_contentDiscoveryTimer) { [_contentDiscoveryTimer invalidate]; + _contentDiscoveryTimer = nil; } } - (void)readContentDataIfNeeded { - if (_numOfViewsDiscovered < _cdManifest.maxViewHistoryLength) { + if (_numOfViewsDiscovered < self.contentManifest.maxViewHistoryLength) { UIViewController *presentingViewController = [self getActiveViewController]; if (presentingViewController) { NSString *presentingViewControllerName = NSStringFromClass([presentingViewController class]); @@ -76,7 +83,7 @@ - (void)readContentDataIfNeeded { } } } else { - [self stopContentDiscoveryTask]; + [self stopDiscoveryTask]; } } @@ -88,7 +95,7 @@ - (void)readContentData:(UIViewController *)viewController { BOOL isClearText = YES; if (rootView) { - BranchContentPathProperties *pathProperties = [_cdManifest getContentPathProperties:viewController]; + BranchContentPathProperties *pathProperties = [self.contentManifest getContentPathProperties:viewController]; // Check for any existing path properties for this ViewController if (pathProperties) { isClearText = pathProperties.isClearText; @@ -101,14 +108,14 @@ - (void)readContentData:(UIViewController *)viewController { [self discoverFilteredViewContents:viewController contentData:contentDataArray contentKeys:contentKeysArray clearText:isClearText]; } } - } else if (_cdManifest.referredLink) { // else discover content if this session is started by a link click + } else if (self.contentManifest.referredLink) { // else discover content if this session is started by a link click [self discoverViewContents:rootView contentData:nil contentKeys:contentKeysArray clearText:YES ID:@""]; } if (contentKeysArray && contentKeysArray.count > 0) { NSMutableDictionary *contentEventObj = [[NSMutableDictionary alloc] init]; [contentEventObj setObject:[NSString stringWithFormat:@"%f", [[NSDate date] timeIntervalSince1970]] forKey:BRANCH_TIME_STAMP_KEY]; - if (_cdManifest.referredLink) { - [contentEventObj setObject:_cdManifest.referredLink forKey:BRANCH_REFERRAL_LINK_KEY]; + if (self.contentManifest.referredLink.length) { + [contentEventObj setObject:self.contentManifest.referredLink forKey:BRANCH_REFERRAL_LINK_KEY]; } [contentEventObj setObject:[NSString stringWithFormat:@"/%@", _lastViewControllerName] forKey:BRANCH_VIEW_KEY]; @@ -125,20 +132,27 @@ - (void)readContentData:(UIViewController *)viewController { } -- (void)discoverViewContents:(UIView *)rootView contentData:(NSMutableArray *)contentDataArray contentKeys:(NSMutableArray *)contentKeysArray clearText:(BOOL)isClearText ID:(NSString *)viewId { +- (void)discoverViewContents:(UIView *)rootView + contentData:(NSMutableArray *)contentDataArray + contentKeys:(NSMutableArray *)contentKeysArray + clearText:(BOOL)isClearText + ID:(NSString *)viewId { if ([rootView isKindOfClass:UITableView.class] || [rootView isKindOfClass:UICollectionView.class]) { NSArray *cells = [rootView performSelector:@selector(visibleCells) withObject:nil]; NSInteger cellCnt = -1; for (UIView *cell in cells) { cellCnt++; - NSString *format; - if (viewId.length > 0 ) { - format = @"-%d"; + NSString *cellViewId = nil; + if (viewId.length > 0) { + cellViewId = [viewId stringByAppendingFormat:@"-%ld", (long) cellCnt]; } else { - format = @"%d"; + cellViewId = [NSString stringWithFormat:@"%ld", (long) cellCnt]; } - NSString *cellViewId = [viewId stringByAppendingFormat:format, cellCnt]; - [self discoverViewContents:cell contentData:contentDataArray contentKeys:contentKeysArray clearText:isClearText ID:cellViewId]; + [self discoverViewContents:cell + contentData:contentDataArray + contentKeys:contentKeysArray + clearText:isClearText + ID:cellViewId]; } } else { NSString *contentData = [self getContentText:rootView]; @@ -152,15 +166,27 @@ - (void)discoverViewContents:(UIView *)rootView contentData:(NSMutableArray *)co NSArray *subViews = [rootView subviews]; NSInteger childCount = 0; for (UIView *view in subViews) { - NSString *subViewId = [viewId stringByAppendingFormat:@"-%ld", (long)childCount]; + NSString *subViewId = nil; + if (viewId.length > 0) { + subViewId = [viewId stringByAppendingFormat:@"-%ld", (long) childCount]; + } else { + subViewId = [NSString stringWithFormat:@"%ld", (long) childCount]; + } childCount++; - [self discoverViewContents:view contentData:contentDataArray contentKeys:contentKeysArray clearText:isClearText ID:subViewId]; + [self discoverViewContents:view + contentData:contentDataArray + contentKeys:contentKeysArray + clearText:isClearText + ID:subViewId]; } } } -- (void)discoverFilteredViewContents:(UIViewController *)viewController contentData:(NSMutableArray *)contentDataArray contentKeys:(NSMutableArray *)contentKeysArray clearText:(BOOL)isClearText { +- (void)discoverFilteredViewContents:(UIViewController *)viewController + contentData:(NSMutableArray *)contentDataArray + contentKeys:(NSMutableArray *)contentKeysArray + clearText:(BOOL)isClearText { for (NSString *contentKey in contentKeysArray) { NSString *contentData = [self getViewText:contentKey forController:viewController]; if (contentData == nil) { @@ -182,7 +208,8 @@ - (UIView *)getRootView:(UIViewController *)viewController { return rootView; } -- (NSString *)getViewText:(NSString *)viewId forController:(UIViewController *)viewController { +- (NSString *)getViewText:(NSString *)viewId + forController:(UIViewController *)viewController { NSString *viewTxt = @""; if (viewController) { UIView *rootView = [viewController view]; @@ -243,8 +270,8 @@ - (UIViewController *)getActiveViewController:(UIViewController *)rootViewContro - (void)addFormattedContentData:(NSMutableArray *)contentDataArray withText:(NSString *)contentData clearText:(BOOL)isClearText { - if (contentData && contentData.length > _cdManifest.maxTextLen) { - contentData = [contentData substringToIndex:_cdManifest.maxTextLen]; + if (contentData && contentData.length > self.contentManifest.maxTextLen) { + contentData = [contentData substringToIndex:self.contentManifest.maxTextLen]; } if (!isClearText) { contentData = [BNCEncodingUtils md5Encode:contentData]; diff --git a/src/ios/dependencies/Branch-SDK/BranchContentDiscoveryManifest.m b/src/ios/dependencies/Branch-SDK/BranchContentDiscoveryManifest.m index 75433bcf..7e755752 100644 --- a/src/ios/dependencies/Branch-SDK/BranchContentDiscoveryManifest.m +++ b/src/ios/dependencies/Branch-SDK/BranchContentDiscoveryManifest.m @@ -6,6 +6,7 @@ // Copyright © 2016 Branch Metrics. All rights reserved. // + #import #import "BranchContentDiscoveryManifest.h" #import "BNCPreferenceHelper.h" @@ -13,16 +14,13 @@ #import #import "BranchConstants.h" -@interface BranchContentDiscoveryManifest () +@interface BranchContentDiscoveryManifest () @property (nonatomic, strong) NSString *manifestVersion; - @end -@implementation BranchContentDiscoveryManifest - -static BranchContentDiscoveryManifest *contentDiscoveryManifest; +@implementation BranchContentDiscoveryManifest - (instancetype)init { self = [super init]; @@ -38,14 +36,15 @@ - (instancetype)init { } + (BranchContentDiscoveryManifest *)getInstance { - if (!contentDiscoveryManifest) { - contentDiscoveryManifest = [[BranchContentDiscoveryManifest alloc] init]; + @synchronized (self) { + static BranchContentDiscoveryManifest *contentDiscoveryManifest = nil; + if (!contentDiscoveryManifest) { + contentDiscoveryManifest = [[BranchContentDiscoveryManifest alloc] init]; + } + return contentDiscoveryManifest; } - return contentDiscoveryManifest; } - - - (void)onBranchInitialised:(NSDictionary *)branchInitDict withUrl:(NSString *)referredUrl { _referredLink = referredUrl; if ([branchInitDict objectForKey:BRANCH_CONTENT_DISCOVER_KEY]) { diff --git a/src/ios/dependencies/Branch-SDK/NSMutableDictionary+Branch.m b/src/ios/dependencies/Branch-SDK/NSMutableDictionary+Branch.m index e4030ecd..b78ec0a3 100644 --- a/src/ios/dependencies/Branch-SDK/NSMutableDictionary+Branch.m +++ b/src/ios/dependencies/Branch-SDK/NSMutableDictionary+Branch.m @@ -13,14 +13,18 @@ @implementation NSMutableDictionary (Branch) - (void) bnc_safeSetObject:(id)anObject forKey:(id)aKey { - if (anObject) { + if (anObject && aKey) { [self setObject:anObject forKey:aKey]; } } - (void) bnc_safeAddEntriesFromDictionary:(NSDictionary,id> *)otherDictionary { if ([otherDictionary isKindOfClass:[NSDictionary class]]) { - [self addEntriesFromDictionary:otherDictionary]; + NSDictionary *deepCopy = + [[NSDictionary alloc] + initWithDictionary:otherDictionary + copyItems:YES]; + [self addEntriesFromDictionary:deepCopy]; } } diff --git a/src/ios/dependencies/Branch-SDK/Requests/BranchInstallRequest.m b/src/ios/dependencies/Branch-SDK/Requests/BranchInstallRequest.m index 04aeb998..4ef00d47 100644 --- a/src/ios/dependencies/Branch-SDK/Requests/BranchInstallRequest.m +++ b/src/ios/dependencies/Branch-SDK/Requests/BranchInstallRequest.m @@ -57,8 +57,7 @@ - (void)makeRequest:(BNCServerInterface *)serverInterface key:(NSString *)key ca dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{ [serverInterface postRequest:params url:[preferenceHelper getAPIURL:BRANCH_REQUEST_ENDPOINT_INSTALL] key:key callback:callback]; }); - } - else { + } else { [serverInterface postRequest:params url:[preferenceHelper getAPIURL:BRANCH_REQUEST_ENDPOINT_INSTALL] key:key callback:callback]; } } diff --git a/src/ios/dependencies/Branch-SDK/Requests/BranchLogoutRequest.m b/src/ios/dependencies/Branch-SDK/Requests/BranchLogoutRequest.m index 6c2b85f1..3955644a 100644 --- a/src/ios/dependencies/Branch-SDK/Requests/BranchLogoutRequest.m +++ b/src/ios/dependencies/Branch-SDK/Requests/BranchLogoutRequest.m @@ -6,16 +6,17 @@ // Copyright (c) 2015 Branch Metrics. All rights reserved. // + #import "BranchLogoutRequest.h" #import "BNCPreferenceHelper.h" #import "BranchConstants.h" -@interface BranchLogoutRequest () +@interface BranchLogoutRequest () @property (copy) callbackWithStatus callback; - @end + @implementation BranchLogoutRequest - (id)initWithCallback:(callbackWithStatus)callback { diff --git a/src/ios/dependencies/Branch-SDK/Requests/BranchOpenRequest.h b/src/ios/dependencies/Branch-SDK/Requests/BranchOpenRequest.h index ad34052a..f76d3ead 100644 --- a/src/ios/dependencies/Branch-SDK/Requests/BranchOpenRequest.h +++ b/src/ios/dependencies/Branch-SDK/Requests/BranchOpenRequest.h @@ -13,6 +13,10 @@ @property (copy) callbackWithStatus callback; ++ (void) waitForOpenResponseLock; ++ (void) releaseOpenResponseLock; ++ (void) setWaitNeededForOpenResponseLock; + - (id)initWithCallback:(callbackWithStatus)callback; - (id)initWithCallback:(callbackWithStatus)callback isInstall:(BOOL)isInstall; diff --git a/src/ios/dependencies/Branch-SDK/Requests/BranchOpenRequest.m b/src/ios/dependencies/Branch-SDK/Requests/BranchOpenRequest.m index c24b3a83..c06f4ffe 100644 --- a/src/ios/dependencies/Branch-SDK/Requests/BranchOpenRequest.m +++ b/src/ios/dependencies/Branch-SDK/Requests/BranchOpenRequest.m @@ -6,16 +6,18 @@ // Copyright (c) 2015 Branch Metrics. All rights reserved. // + #import "BranchOpenRequest.h" #import "BNCPreferenceHelper.h" #import "BNCSystemObserver.h" +#import "BNCDeviceInfo.h" #import "BranchConstants.h" #import "BNCEncodingUtils.h" #import "BranchViewHandler.h" #import "BNCFabricAnswers.h" #import "BranchContentDiscoveryManifest.h" #import "BranchContentDiscoverer.h" - +#import "NSMutableDictionary+Branch.h" @interface BranchOpenRequest () @property (assign, nonatomic) BOOL isInstall; @@ -33,7 +35,7 @@ - (id)initWithCallback:(callbackWithStatus)callback isInstall:(BOOL)isInstall { _callback = callback; _isInstall = isInstall; } - + return self; } @@ -44,13 +46,13 @@ - (void)makeRequest:(BNCServerInterface *)serverInterface key:(NSString *)key ca if (preferenceHelper.deviceFingerprintID) { params[BRANCH_REQUEST_KEY_DEVICE_FINGERPRINT_ID] = preferenceHelper.deviceFingerprintID; } - + params[BRANCH_REQUEST_KEY_BRANCH_IDENTITY] = preferenceHelper.identityID; params[BRANCH_REQUEST_KEY_DEBUG] = @(preferenceHelper.isDebug); - + [self safeSetValue:[BNCSystemObserver getBundleID] forKey:BRANCH_REQUEST_KEY_BUNDLE_ID onDict:params]; [self safeSetValue:[BNCSystemObserver getTeamIdentifier] forKey:BRANCH_REQUEST_KEY_TEAM_ID onDict:params]; - [self safeSetValue:[BNCSystemObserver getAppVersion] forKey:BRANCH_REQUEST_KEY_APP_VERSION onDict:params]; + [self safeSetValue:[BNCSystemObserver getAppVersion] forKey:BRANCH_REQUEST_KEY_APP_VERSION onDict:params]; [self safeSetValue:[BNCSystemObserver getDefaultUriScheme] forKey:BRANCH_REQUEST_KEY_URI_SCHEME onDict:params]; [self safeSetValue:[BNCSystemObserver getUpdateState] forKey:BRANCH_REQUEST_KEY_UPDATE onDict:params]; [self safeSetValue:[NSNumber numberWithBool:preferenceHelper.checkedFacebookAppLinks] forKey:BRANCH_REQUEST_KEY_CHECKED_FACEBOOK_APPLINKS onDict:params]; @@ -59,12 +61,12 @@ - (void)makeRequest:(BNCServerInterface *)serverInterface key:(NSString *)key ca [self safeSetValue:preferenceHelper.spotlightIdentifier forKey:BRANCH_REQUEST_KEY_SPOTLIGHT_IDENTIFIER onDict:params]; [self safeSetValue:preferenceHelper.universalLinkUrl forKey:BRANCH_REQUEST_KEY_UNIVERSAL_LINK_URL onDict:params]; [self safeSetValue:preferenceHelper.externalIntentURI forKey:BRANCH_REQUEST_KEY_EXTERNAL_INTENT_URI onDict:params]; - + NSMutableDictionary *cdDict = [[NSMutableDictionary alloc] init]; BranchContentDiscoveryManifest *contentDiscoveryManifest = [BranchContentDiscoveryManifest getInstance]; - [cdDict setObject:[contentDiscoveryManifest getManifestVersion] forKey:BRANCH_MANIFEST_VERSION_KEY]; - [cdDict setObject:[BNCSystemObserver getBundleID] forKey:BRANCH_BUNDLE_IDENTIFIER]; - [self safeSetValue:cdDict forKey:BRANCH_CONTENT_DISCOVER_KEY onDict:params]; + [cdDict bnc_safeSetObject:[contentDiscoveryManifest getManifestVersion] forKey:BRANCH_MANIFEST_VERSION_KEY]; + [cdDict bnc_safeSetObject:[BNCSystemObserver getBundleID] forKey:BRANCH_BUNDLE_IDENTIFIER]; + [self safeSetValue:cdDict forKey:BRANCH_CONTENT_DISCOVER_KEY onDict:params]; if (preferenceHelper.appleSearchAdDetails) { NSString *encodedSearchData = nil; @@ -83,29 +85,30 @@ - (void)makeRequest:(BNCServerInterface *)serverInterface key:(NSString *)key ca - (void)processResponse:(BNCServerResponse *)response error:(NSError *)error { if (error) { + [BranchOpenRequest releaseOpenResponseLock]; if (self.callback) { self.callback(NO, error); } return; } - + BNCPreferenceHelper *preferenceHelper = [BNCPreferenceHelper preferenceHelper]; NSDictionary *data = response.data; - + // Handle possibly mis-parsed identity. id userIdentity = data[BRANCH_RESPONSE_KEY_DEVELOPER_IDENTITY]; if ([userIdentity isKindOfClass:[NSNumber class]]) { userIdentity = [userIdentity stringValue]; } - + preferenceHelper.deviceFingerprintID = data[BRANCH_RESPONSE_KEY_DEVICE_FINGERPRINT_ID]; preferenceHelper.userUrl = data[BRANCH_RESPONSE_KEY_USER_URL]; preferenceHelper.userIdentity = userIdentity; preferenceHelper.sessionID = data[BRANCH_RESPONSE_KEY_SESSION_ID]; [BNCSystemObserver setUpdateState]; - + NSString *sessionData = data[BRANCH_RESPONSE_KEY_SESSION_DATA]; - + // Update session params preferenceHelper.sessionParams = sessionData; @@ -119,20 +122,22 @@ - (void)processResponse:(BNCServerResponse *)response error:(NSError *)error { NSDictionary *sessionDataDict = [BNCEncodingUtils decodeJsonStringToDictionary:sessionData]; BOOL dataIsFromALinkClick = [sessionDataDict[BRANCH_RESPONSE_KEY_CLICKED_BRANCH_LINK] isEqual:@1]; BOOL storedParamsAreEmpty = YES; - + if ([preferenceHelper.installParams isKindOfClass:[NSString class]]) { storedParamsAreEmpty = !preferenceHelper.installParams.length; } - + if (dataIsFromALinkClick && (self.isInstall || storedParamsAreEmpty)) { preferenceHelper.installParams = sessionData; } - + if (dataIsFromALinkClick) { - [BNCFabricAnswers sendEventWithName:[@"Branch " stringByAppendingString:[[self getActionName] capitalizedString]] andAttributes:sessionDataDict]; + NSString * eventName = + [@"Branch " stringByAppendingString:[[self getActionName] capitalizedString]]; + [BNCFabricAnswers sendEventWithName:eventName andAttributes:sessionDataDict]; } } - + NSString *referredUrl = nil; if (preferenceHelper.universalLinkUrl) { referredUrl = preferenceHelper.universalLinkUrl; @@ -140,12 +145,18 @@ - (void)processResponse:(BNCServerResponse *)response error:(NSError *)error { else if (preferenceHelper.externalIntentURI) { referredUrl = preferenceHelper.externalIntentURI; } + else { + NSDictionary *sessionDataDict = [BNCEncodingUtils decodeJsonStringToDictionary:sessionData]; + if (sessionDataDict[BRANCH_RESPONSE_KEY_BRANCH_REFERRING_LINK]) { + referredUrl = sessionDataDict[BRANCH_RESPONSE_KEY_BRANCH_REFERRING_LINK]; + } + } BranchContentDiscoveryManifest *cdManifest = [BranchContentDiscoveryManifest getInstance]; [cdManifest onBranchInitialised:data withUrl:referredUrl]; if ([cdManifest isCDEnabled]) { - [[BranchContentDiscoverer getInstance:cdManifest] startContentDiscoveryTask]; + [[BranchContentDiscoverer getInstance] startDiscoveryTaskWithManifest:cdManifest]; } - + // Clear link identifiers so they don't get reused on the next open preferenceHelper.checkedFacebookAppLinks = NO; preferenceHelper.linkClickIdentifier = nil; @@ -153,25 +164,79 @@ - (void)processResponse:(BNCServerResponse *)response error:(NSError *)error { preferenceHelper.universalLinkUrl = nil; preferenceHelper.externalIntentURI = nil; preferenceHelper.appleSearchAdDetails = nil; - + if (data[BRANCH_RESPONSE_KEY_BRANCH_IDENTITY]) { preferenceHelper.identityID = data[BRANCH_RESPONSE_KEY_BRANCH_IDENTITY]; } - + + [BranchOpenRequest releaseOpenResponseLock]; + // Check if there is any Branch View to show NSObject *branchViewDict = data[BRANCH_RESPONSE_KEY_BRANCH_VIEW_DATA]; if ([branchViewDict isKindOfClass:[NSDictionary class]]) { - [[BranchViewHandler getInstance] showBranchView:[self getActionName] withBranchViewDictionary:(NSDictionary *)branchViewDict andWithDelegate:nil]; + [[BranchViewHandler getInstance] + showBranchView:[self getActionName] + withBranchViewDictionary:(NSDictionary *)branchViewDict + andWithDelegate:nil]; } - + if (self.callback) { self.callback(YES, nil); } - + } - (NSString *)getActionName { return @"open"; } + +#pragma - Open Response Lock Handling + + +// Instead of semaphores, the lock is handled by scheduled dispatch_queues. +// This is the 'new' way to lock and is handled better optimized for iOS. +// Also, since implied lock is handled by a scheduler and not a hard semaphore it's less error +// prone. + + +static dispatch_queue_t openRequestWaitQueue = NULL; +static BOOL openRequestWaitQueueIsSuspended = NO; + + ++ (void) initialize { + if (self != [BranchOpenRequest self]) + return; + openRequestWaitQueue = + dispatch_queue_create("io.branch.sdk.openqueue", DISPATCH_QUEUE_CONCURRENT); +} + ++ (void) setWaitNeededForOpenResponseLock { + @synchronized (self) { + if (!openRequestWaitQueueIsSuspended) { + //NSLog(@"Suspend openRequestWaitQueue."); + openRequestWaitQueueIsSuspended = YES; + dispatch_suspend(openRequestWaitQueue); + } + } +} + ++ (void) waitForOpenResponseLock { + //NSLog(@"Wait for openRequestWaitQueue."); + [BNCDeviceInfo userAgentString]; // Make sure we do this lock first to prevent a deadlock. + dispatch_sync(openRequestWaitQueue, ^ { + //NSLog(@"Finished waitForOpenResponseLock"); + }); +} + ++ (void) releaseOpenResponseLock { + @synchronized (self) { + if (openRequestWaitQueueIsSuspended) { + //NSLog(@"Resume openRequestWaitQueue."); + openRequestWaitQueueIsSuspended = NO; + dispatch_resume(openRequestWaitQueue); + } + } +} + @end diff --git a/src/ios/dependencies/Branch-SDK/Requests/BranchShortUrlRequest.m b/src/ios/dependencies/Branch-SDK/Requests/BranchShortUrlRequest.m index 07605d3c..db17abf1 100644 --- a/src/ios/dependencies/Branch-SDK/Requests/BranchShortUrlRequest.m +++ b/src/ios/dependencies/Branch-SDK/Requests/BranchShortUrlRequest.m @@ -72,10 +72,8 @@ - (void)processResponse:(BNCServerResponse *)response error:(NSError *)error { if (userUrl) { failedUrl = [self createLongUrlForUserUrl:userUrl]; } - self.callback(failedUrl, error); } - return; } @@ -85,7 +83,6 @@ - (void)processResponse:(BNCServerResponse *)response error:(NSError *)error { if (url) { [self.linkCache setObject:url forKey:self.linkData]; } - if (self.callback) { self.callback(url, nil); } @@ -153,13 +150,11 @@ - (id)initWithCoder:(NSCoder *)decoder { [self.linkData setupMatchDuration:_matchDuration]; [self.linkData setupParams:_params]; } - return self; } - (void)encodeWithCoder:(NSCoder *)coder { [super encodeWithCoder:coder]; - [coder encodeObject:self.tags forKey:@"tags"]; [coder encodeObject:self.alias forKey:@"alias"]; [coder encodeInteger:self.type forKey:@"type"]; diff --git a/src/ios/dependencies/Branch-SDK/Requests/BranchShortUrlSyncRequest.h b/src/ios/dependencies/Branch-SDK/Requests/BranchShortUrlSyncRequest.h index a0feb6d0..f6008328 100644 --- a/src/ios/dependencies/Branch-SDK/Requests/BranchShortUrlSyncRequest.h +++ b/src/ios/dependencies/Branch-SDK/Requests/BranchShortUrlSyncRequest.h @@ -11,9 +11,30 @@ @interface BranchShortUrlSyncRequest : NSObject -- (id)initWithTags:(NSArray *)tags alias:(NSString *)alias type:(BranchLinkType)type matchDuration:(NSInteger)duration channel:(NSString *)channel feature:(NSString *)feature stage:(NSString *)stage campaign:(NSString *)campaign params:(NSDictionary *)params linkData:(BNCLinkData *)linkData linkCache:(BNCLinkCache *)linkCache; +- (id)initWithTags:(NSArray *)tags + alias:(NSString *)alias + type:(BranchLinkType)type + matchDuration:(NSInteger)duration + channel:(NSString *)channel + feature:(NSString *)feature + stage:(NSString *)stage + campaign:(NSString *)campaign + params:(NSDictionary *)params + linkData:(BNCLinkData *)linkData + linkCache:(BNCLinkCache *)linkCache; + - (BNCServerResponse *)makeRequest:(BNCServerInterface *)serverInterface key:(NSString *)key; + - (NSString *)processResponse:(BNCServerResponse *)response; -+ (NSString *)createLinkFromBranchKey:(NSString *)branchKey tags:(NSArray *)tags alias:(NSString *)alias type:(BranchLinkType)type matchDuration:(NSInteger)duration channel:(NSString *)channel feature:(NSString *)feature stage:(NSString *)stage params:(NSDictionary *)params; + ++ (NSString *)createLinkFromBranchKey:(NSString *)branchKey + tags:(NSArray *)tags + alias:(NSString *)alias + type:(BranchLinkType)type + matchDuration:(NSInteger)duration + channel:(NSString *)channel + feature:(NSString *)feature + stage:(NSString *)stage + params:(NSDictionary *)params; @end diff --git a/src/ios/dependencies/Branch-SDK/Requests/BranchShortUrlSyncRequest.m b/src/ios/dependencies/Branch-SDK/Requests/BranchShortUrlSyncRequest.m index fb7e99c9..94bca133 100644 --- a/src/ios/dependencies/Branch-SDK/Requests/BranchShortUrlSyncRequest.m +++ b/src/ios/dependencies/Branch-SDK/Requests/BranchShortUrlSyncRequest.m @@ -56,7 +56,10 @@ - (BNCServerResponse *)makeRequest:(BNCServerInterface *)serverInterface key:(NS params[BRANCH_REQUEST_KEY_BRANCH_IDENTITY] = preferenceHelper.identityID; params[BRANCH_REQUEST_KEY_SESSION_ID] = preferenceHelper.sessionID; - return [serverInterface postRequest:params url:[preferenceHelper getAPIURL:BRANCH_REQUEST_ENDPOINT_GET_SHORT_URL] key:key log:YES]; + return [serverInterface postRequest:params + url:[preferenceHelper getAPIURL:BRANCH_REQUEST_ENDPOINT_GET_SHORT_URL] + key:key + log:YES]; } - (NSString *)processResponse:(BNCServerResponse *)response { diff --git a/src/ios/dependencies/Branch.framework/Versions/A/Branch b/src/ios/dependencies/Branch.framework/Versions/A/Branch index 00c698ef..d8f306d3 100644 Binary files a/src/ios/dependencies/Branch.framework/Versions/A/Branch and b/src/ios/dependencies/Branch.framework/Versions/A/Branch differ diff --git a/src/ios/dependencies/Branch.framework/Versions/A/Headers/BNCPreferenceHelper.h b/src/ios/dependencies/Branch.framework/Versions/A/Headers/BNCPreferenceHelper.h index be3a7bf9..21b1c9d5 100644 --- a/src/ios/dependencies/Branch.framework/Versions/A/Headers/BNCPreferenceHelper.h +++ b/src/ios/dependencies/Branch.framework/Versions/A/Headers/BNCPreferenceHelper.h @@ -15,7 +15,7 @@ @property (strong, nonatomic) NSString *branchKey; @property (strong, nonatomic) NSString *lastRunBranchKey; -@property (strong, nonatomic) NSDate *lastStrongMatchDate; +@property (strong, nonatomic) NSDate *lastStrongMatchDate; @property (strong, nonatomic) NSString *appVersion; @property (strong, nonatomic) NSString *deviceFingerprintID; @property (strong, nonatomic) NSString *sessionID; @@ -39,6 +39,9 @@ @property (strong, nonatomic) NSMutableDictionary *savedAnalyticsData; @property (assign, nonatomic) NSInteger installRequestDelay; @property (strong, nonatomic) NSDictionary *appleSearchAdDetails; +@property (strong, nonatomic) NSString *lastSystemBuildVersion; +@property (strong, nonatomic) NSString *browserUserAgentString; +@property (strong) NSString *branchAPIURL; + (BNCPreferenceHelper *)preferenceHelper; + (NSURL*) URLForBranchDirectory; @@ -79,4 +82,7 @@ - (NSMutableDictionary *)getBranchAnalyticsData; - (NSDictionary *)getContentAnalyticsManifest; - (void)saveContentAnalyticsManifest:(NSDictionary *)cdManifest; + +- (void) save; // Flushes preference queue to persistence. + @end diff --git a/src/ios/dependencies/Branch.framework/Versions/A/Headers/Branch.h b/src/ios/dependencies/Branch.framework/Versions/A/Headers/Branch.h index a0924e88..0ddac3e9 100644 --- a/src/ios/dependencies/Branch.framework/Versions/A/Headers/Branch.h +++ b/src/ios/dependencies/Branch.framework/Versions/A/Headers/Branch.h @@ -520,6 +520,13 @@ typedef NS_ENUM(NSUInteger, BranchCreditHistoryOrder) { */ - (NSDictionary *)getLatestReferringParams; +/** + Returns the most recent referral parameters for this user. An empty object can be returned. + This call blocks the calling thread until the latest results are available. + @warning This call blocks the calling thread. + */ +- (NSDictionary*) getLatestReferringParamsSynchronous; + /** Tells Branch to act as though initSession hadn't been called. Will require another open call (this is done automatically, internally). */