diff --git a/DEVELOPING.md b/DEVELOPING.md index 7e4fc621..d823b633 100644 --- a/DEVELOPING.md +++ b/DEVELOPING.md @@ -59,7 +59,7 @@ gulp prerelease; > **[optional]** Update [iOS SDK](https://github.com/BranchMetrics/ios-branch-deep-linking/tags) (will need to update `plugin.xml` dependencies if new iOS files) ```sh -./src/ios/dependencies/update.sh 0.12.14; +./src/ios/dependencies/update.sh 0.12.20; ``` ### Test @@ -67,7 +67,7 @@ gulp prerelease; > Modify `BRANCH_KEY` and `URI_SCHEME` and `config.xml` to values in [Branch Dashboard](https://dashboard.branch.io/settings/link) ```sh -gulp prerelease && cd testbed && npm install -g cordova && cordova platform remove ios && cordova platform remove android && cordova platform remove browser && cordova platform add ios && cordova platform add android && cordova plugin remove io.branch.sdk && cordova plugin add ../ --variable BRANCH_KEY=key_live_icCccJIpd7GlYY5oOmoEtpafuDiuyXhT --variable URI_SCHEME=enefftest; +gulp prerelease; cd testbed; npm install -g cordova; cordova platform remove ios; cordova platform remove android; cordova platform remove browser; cordova platform add ios; cordova platform add android; cordova plugin remove io.branch.sdk; cordova plugin add ../ --variable BRANCH_KEY=key_live_icCccJIpd7GlYY5oOmoEtpafuDiuyXhT --variable URI_SCHEME=enefftest; # cordova plugin add branch-cordova-sdk --variable BRANCH_KEY=key_live_icCccJIpd7GlYY5oOmoEtpafuDiuyXhT --variable URI_SCHEME=enefftest; ``` @@ -75,11 +75,11 @@ gulp prerelease && cd testbed && npm install -g cordova && cordova platform remo > Validate all features on both `iOS` and `Android` on `device` only (no `simulator` or `TestFlight`) ```sh -cordova build ios --developmentTeam="PW4Q8885U7" --device; +cordova build ios && open -a Xcode platforms/ios/Branch\ Testing.xcworkspace; ``` ```sh -cordova build android && cordova run android; +cordova build android; cordova run android; chrome://inspect/#devices ``` diff --git a/README.md b/README.md index 68b7ab52..1cbc4bbb 100644 --- a/README.md +++ b/README.md @@ -205,9 +205,9 @@ - Delete your app from the device *(resets the Apple AASA scraping)* - - Compile your app *(`cordova build ios --developmentTeam="PW4Q8885U7" --device;`)* + - Compile your app *(`cordova build ios` `phone gap build ios` `ionic build ios`)* - - Open the app in Xcode and set your Provisioning Profile `Development Team` + - Open the app in `Xcode` and set your Provisioning Profile `Development Team` - Launch your app to `device` *(not Simulator or TestFlight)* @@ -225,7 +225,7 @@ - Delete your app from the device - - Compile your app *(`cordova run android`)* + - Compile your app *(`cordova build android` `phone gap build android` `ionic build android`)* - Launch your app to `device` *(not Simulator or Genymotion)* @@ -328,6 +328,7 @@ $android_url: 'http://www.example.com/android', $ios_url: 'http://www.example.com/ios', $ipad_url: 'http://www.example.com/ipad', + $deeplink_path: "content/123", more_custom: 'data', even_more_custom: true, this_is_custom: 321 @@ -700,6 +701,8 @@ - Always use the `Branch.initSession(function(data) {});` to read Deep Link data - Always test on `device` (`simulator` `browser` `genymotion` will break) + + - You must launch the app through `Xcode` for iOS - Other deep link plugins (ex `cordova-universal-links-plugin`) will interferer with Branch diff --git a/plugin.xml b/plugin.xml index 48f5bd75..1fac340a 100644 --- a/plugin.xml +++ b/plugin.xml @@ -120,6 +120,7 @@ SOFTWARE. + diff --git a/src/android/io/branch/BranchSDK.java b/src/android/io/branch/BranchSDK.java index feee1b74..1130628d 100644 --- a/src/android/io/branch/BranchSDK.java +++ b/src/android/io/branch/BranchSDK.java @@ -350,7 +350,6 @@ private void getFirstReferringParams(CallbackContext callbackContext) { */ private void createBranchUniversalObject(JSONObject options, CallbackContext callbackContext) throws JSONException { - BranchUniversalObject branchObj = new BranchUniversalObject(); // Set object properties @@ -373,7 +372,6 @@ private void createBranchUniversalObject(JSONObject options, CallbackContext cal // Set content visibility if (options.has("contentIndexingMode")) { - if (options.getString("contentIndexingMode").equals("private")) { branchObj.setContentIndexingMode(BranchUniversalObject.CONTENT_INDEX_MODE.PRIVATE); } else { @@ -447,6 +445,7 @@ private BranchLinkProperties createLinkProperties(JSONObject options, JSONObject BranchLinkProperties linkProperties = new BranchLinkProperties(); + // Add link properties if (options.has("feature")) { linkProperties.setFeature(options.getString("feature")); } @@ -465,39 +464,26 @@ private BranchLinkProperties createLinkProperties(JSONObject options, JSONObject if (options.has("duration")) { linkProperties.setDuration(options.getInt("duration")); } - if (options.has("tags")) { JSONArray array = (JSONArray) options.get("tags"); if (array != null) { - for (int i=0;i keys = controlParams.keys(); + + while (keys.hasNext()) { + String key = keys.next().toString(); + + Log.d(LCAT, String.format("key: %s", key)); + + linkProperties.addControlParameter(key, controlParams.getString(key)); } return linkProperties; diff --git a/src/ios/dependencies/Branch-SDK/BNCCallbacks.h b/src/ios/dependencies/Branch-SDK/BNCCallbacks.h index 7b47030e..a0c74409 100644 --- a/src/ios/dependencies/Branch-SDK/BNCCallbacks.h +++ b/src/ios/dependencies/Branch-SDK/BNCCallbacks.h @@ -11,11 +11,11 @@ @class BranchUniversalObject, BranchLinkProperties; -typedef void (^callbackWithParams) (NSDictionary * _Nonnull params, NSError * _Nullable error); -typedef void (^callbackWithUrl) (NSString * _Nonnull url, NSError * _Nullable error); +typedef void (^callbackWithParams) (NSDictionary * _Nullable params, NSError * _Nullable error); +typedef void (^callbackWithUrl) (NSString * _Nullable url, NSError * _Nullable error); typedef void (^callbackWithStatus) (BOOL changed, NSError * _Nullable error); typedef void (^callbackWithList) (NSArray * _Nullable list, NSError * _Nullable error); typedef void (^callbackWithUrlAndSpotlightIdentifier) (NSString * _Nullable url, NSString * _Nullable spotlightIdentifier, NSError * _Nullable error); -typedef void (^callbackWithBranchUniversalObject) (BranchUniversalObject * _Nonnull universalObject, BranchLinkProperties * _Nonnull linkProperties, NSError * _Nullable error); +typedef void (^callbackWithBranchUniversalObject) (BranchUniversalObject * _Nullable universalObject, BranchLinkProperties * _Nullable linkProperties, NSError * _Nullable error); #endif /* BNCCallbacks_h */ diff --git a/src/ios/dependencies/Branch-SDK/BNCConfig.h b/src/ios/dependencies/Branch-SDK/BNCConfig.h index 03f374fb..9a1f1826 100644 --- a/src/ios/dependencies/Branch-SDK/BNCConfig.h +++ b/src/ios/dependencies/Branch-SDK/BNCConfig.h @@ -6,29 +6,9 @@ // Copyright (c) 2014 Branch Metrics. All rights reserved. // -#ifndef Branch_SDK_Config_h -#define Branch_SDK_Config_h +#import -#define SDK_VERSION @"0.12.19" - -#define BNC_PROD_ENV -//#define BNC_STAGE_ENV -//#define BNC_DEV_ENV - -#ifdef BNC_PROD_ENV -#define BNC_API_BASE_URL @"https://api.branch.io" -#endif - -#ifdef BNC_STAGE_ENV -#define BNC_API_BASE_URL @"http://api.dev.branch.io" -#endif - -#define BNC_LINK_URL @"https://bnc.lt" - -#ifdef BNC_DEV_ENV -#define BNC_API_BASE_URL @"http://localhost:3001" -#endif - -#define BNC_API_VERSION @"v1" - -#endif +extern NSString * const SDK_VERSION; +extern NSString * const BNC_API_BASE_URL; +extern NSString * const BNC_LINK_URL; +extern NSString * const BNC_API_VERSION; diff --git a/src/ios/dependencies/Branch-SDK/BNCConfig.m b/src/ios/dependencies/Branch-SDK/BNCConfig.m new file mode 100644 index 00000000..3d5e1a66 --- /dev/null +++ b/src/ios/dependencies/Branch-SDK/BNCConfig.m @@ -0,0 +1,14 @@ +// +// BNCConfig.c +// Branch-TestBed +// +// Created by edward on 12/12/16. +// Copyright © 2016 Branch Metrics. All rights reserved. +// + +#include "BNCConfig.h" + +NSString * const BNC_API_BASE_URL = @"https://api.branch.io"; +NSString * const BNC_API_VERSION = @"v1"; +NSString * const BNC_LINK_URL = @"https://bnc.lt"; +NSString * const SDK_VERSION = @"0.12.20"; diff --git a/src/ios/dependencies/Branch-SDK/BNCDeviceInfo.m b/src/ios/dependencies/Branch-SDK/BNCDeviceInfo.m index 2fc417cd..0669df5f 100644 --- a/src/ios/dependencies/Branch-SDK/BNCDeviceInfo.m +++ b/src/ios/dependencies/Branch-SDK/BNCDeviceInfo.m @@ -46,7 +46,7 @@ - (id)init { self.isRealHardwareId = isRealHardwareId; self.hardwareIdType = hardwareIdType; } - + self.vendorId = [BNCSystemObserver getVendorId]; self.brandName = [BNCSystemObserver getBrand]; self.modelName = [BNCSystemObserver getModel]; @@ -83,10 +83,21 @@ - (id)init { } - self.browserUserAgent = - [[[UIWebView alloc] - initWithFrame:CGRectZero] - stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"]; + void (^setUpBrowserUserAgent)() = ^() { + self.browserUserAgent = [[[UIWebView alloc] + initWithFrame:CGRectZero] + stringByEvaluatingJavaScriptFromString:@"navigator.userAgent"]; + }; + + if (NSThread.isMainThread) { + + setUpBrowserUserAgent(); + + } else { + + dispatch_sync(dispatch_get_main_queue(), setUpBrowserUserAgent); + + } return self; } diff --git a/src/ios/dependencies/Branch-SDK/BNCPreferenceHelper.m b/src/ios/dependencies/Branch-SDK/BNCPreferenceHelper.m index 462d4863..f54e5a1b 100644 --- a/src/ios/dependencies/Branch-SDK/BNCPreferenceHelper.m +++ b/src/ios/dependencies/Branch-SDK/BNCPreferenceHelper.m @@ -374,17 +374,20 @@ - (void)setUniversalLinkUrl:(NSString *)universalLinkUrl { } - (NSString *)sessionParams { - if (_sessionParams) { - _sessionParams = [self readStringFromDefaults:BRANCH_PREFS_KEY_SESSION_PARAMS]; + @synchronized (self) { + if (!_sessionParams) { + _sessionParams = [self readStringFromDefaults:BRANCH_PREFS_KEY_SESSION_PARAMS]; + } + return _sessionParams; } - - return _sessionParams; } - (void)setSessionParams:(NSString *)sessionParams { - if (![_sessionParams isEqualToString:sessionParams]) { - _sessionParams = sessionParams; - [self writeObjectToDefaults:BRANCH_PREFS_KEY_SESSION_PARAMS value:sessionParams]; + @synchronized (self) { + if (![_sessionParams isEqualToString:sessionParams]) { + _sessionParams = sessionParams; + [self writeObjectToDefaults:BRANCH_PREFS_KEY_SESSION_PARAMS value:sessionParams]; + } } } @@ -479,22 +482,28 @@ - (void)setRequestMetadataKey:(NSString *)key value:(NSObject *)value { } - (NSMutableDictionary *)instrumentationDictionary { - if (!_instrumentationDictionary) { - _instrumentationDictionary = [NSMutableDictionary dictionary]; + @synchronized (self) { + if (!_instrumentationDictionary) { + _instrumentationDictionary = [NSMutableDictionary dictionary]; + } + return _instrumentationDictionary; } - return _instrumentationDictionary; } - (void)addInstrumentationDictionaryKey:(NSString *)key value:(NSString *)value { - if (key && value) { - [self.instrumentationDictionary setObject:value forKey:key]; + @synchronized (self) { + if (key && value) { + [self.instrumentationDictionary setObject:value forKey:key]; + } } } - (void)clearInstrumentationDictionary { - NSArray *keys = [_instrumentationDictionary allKeys]; - for (int i = 0 ; i < [keys count]; i++) { - [_instrumentationDictionary removeObjectForKey:keys[i]]; + @synchronized (self) { + NSArray *keys = [_instrumentationDictionary allKeys]; + for (int i = 0 ; i < [keys count]; i++) { + [_instrumentationDictionary removeObjectForKey:keys[i]]; + } } } @@ -606,42 +615,48 @@ - (NSDictionary *)getContentAnalyticsManifest { return (NSDictionary *)[self readObjectFromDefaults:BRANCH_PREFS_KEY_ANALYTICS_MANIFEST]; } + #pragma mark - Writing To Persistence + - (void)writeIntegerToDefaults:(NSString *)key value:(NSInteger)value { - self.persistenceDict[key] = @(value); - [self persistPrefsToDisk]; + [self writeObjectToDefaults:key value:@(value)]; } - (void)writeBoolToDefaults:(NSString *)key value:(BOOL)value { - self.persistenceDict[key] = @(value); - [self persistPrefsToDisk]; + [self writeObjectToDefaults:key value:@(value)]; } - (void)writeObjectToDefaults:(NSString *)key value:(NSObject *)value { - if (value) { - self.persistenceDict[key] = value; - } - else { - [self.persistenceDict removeObjectForKey:key]; + @synchronized (self) { + if (value) { + self.persistenceDict[key] = value; + } + else { + [self.persistenceDict removeObjectForKey:key]; + } + [self persistPrefsToDisk]; } - - [self persistPrefsToDisk]; } - (void)persistPrefsToDisk { @synchronized (self) { - NSDictionary *persistenceDict = [self.persistenceDict copy]; + if (!self.persistenceDict) return; + NSData *data = nil; + @try { + data = [NSKeyedArchiver archivedDataWithRootObject:self.persistenceDict]; + } + @catch (id exception) { + data = nil; + [self logWarning: + [NSString stringWithFormat:@"Exception creating preferences data: %@.", + exception]]; + } + if (!data) { + [self logWarning:@"Can't create preferences data."]; + return; + } NSBlockOperation *newPersistOp = [NSBlockOperation blockOperationWithBlock:^ { - NSData *data = nil; - @try { - data = [NSKeyedArchiver archivedDataWithRootObject:persistenceDict]; - } @catch (id n) { - } - if (!data) { - [self logWarning:@"Can't create preferences archive."]; - return; - } NSError *error = nil; [data writeToURL:self.class.URLForPrefsFile options:NSDataWritingAtomic error:&error]; @@ -651,7 +666,7 @@ - (void)persistPrefsToDisk { @"Failed to persist preferences to disk: %@.", error]]; } }]; - [self.persistPrefsQueue addOperation:newPersistOp]; + [self.persistPrefsQueue addOperation:newPersistOp]; } } diff --git a/src/ios/dependencies/Branch-SDK/BNCServerRequestQueue.h b/src/ios/dependencies/Branch-SDK/BNCServerRequestQueue.h index 44eab536..fd0286d1 100755 --- a/src/ios/dependencies/Branch-SDK/BNCServerRequestQueue.h +++ b/src/ios/dependencies/Branch-SDK/BNCServerRequestQueue.h @@ -26,6 +26,7 @@ - (void)clearQueue; - (BOOL)containsInstallOrOpen; +- (BOOL)removeInstallOrOpen; - (BOOL)containsClose; - (BranchOpenRequest *)moveInstallOrOpenToFront:(NSInteger)networkCount; diff --git a/src/ios/dependencies/Branch-SDK/BNCServerRequestQueue.m b/src/ios/dependencies/Branch-SDK/BNCServerRequestQueue.m index 219bb486..b59538eb 100755 --- a/src/ios/dependencies/Branch-SDK/BNCServerRequestQueue.m +++ b/src/ios/dependencies/Branch-SDK/BNCServerRequestQueue.m @@ -131,6 +131,21 @@ - (BOOL)containsInstallOrOpen { return NO; } +- (BOOL)removeInstallOrOpen { + @synchronized (self.queue) { + for (int i = 0; i < self.queue.count; i++) { + BranchOpenRequest *req = [self.queue objectAtIndex:i]; + // Install extends open, so only need to check open. + if ([req isKindOfClass:[BranchOpenRequest class]]) { + req.callback = nil; + [self remove:req]; + return YES; + } + } + return NO; + } +} + - (BranchOpenRequest *)moveInstallOrOpenToFront:(NSInteger)networkCount { BOOL requestAlreadyInProgress = networkCount > 0; diff --git a/src/ios/dependencies/Branch-SDK/BNCStrongMatchHelper.h b/src/ios/dependencies/Branch-SDK/BNCStrongMatchHelper.h index f908f542..f93cbf9b 100644 --- a/src/ios/dependencies/Branch-SDK/BNCStrongMatchHelper.h +++ b/src/ios/dependencies/Branch-SDK/BNCStrongMatchHelper.h @@ -6,14 +6,17 @@ // Copyright © 2015 Branch Metrics. All rights reserved. // + #import #import + @interface BNCStrongMatchHelper : NSObject + (BNCStrongMatchHelper *)strongMatchHelper; - (void)createStrongMatchWithBranchKey:(NSString *)branchKey; - (BOOL)shouldDelayInstallRequest; -+ (NSURL *)getUrlForCookieBasedMatchingWithBranchKey:(NSString *)branchKey redirectUrl:(NSString *)redirectUrl; ++ (NSURL *)getUrlForCookieBasedMatchingWithBranchKey:(NSString *)branchKey + redirectUrl:(NSString *)redirectUrl; @end diff --git a/src/ios/dependencies/Branch-SDK/BNCStrongMatchHelper.m b/src/ios/dependencies/Branch-SDK/BNCStrongMatchHelper.m index dc294808..f1d533aa 100644 --- a/src/ios/dependencies/Branch-SDK/BNCStrongMatchHelper.m +++ b/src/ios/dependencies/Branch-SDK/BNCStrongMatchHelper.m @@ -6,36 +6,117 @@ // Copyright © 2015 Branch Metrics. All rights reserved. // + #import "BNCStrongMatchHelper.h" +#import #import "BNCConfig.h" #import "BNCPreferenceHelper.h" #import "BNCSystemObserver.h" #import "BranchConstants.h" -// Stub the class for older Xcode versions, methods don't actually do anything. -#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED < 90000 + +#pragma mark BNCStrongMatchHelper iOS 8.0 + + +// This is a stub the class for older Xcode versions. These methods don't do anything. +#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED < 90000 // iOS < 9.0 @implementation BNCStrongMatchHelper -+ (BNCStrongMatchHelper *)strongMatchHelper { return nil; } -- (void)createStrongMatchWithBranchKey:(NSString *)branchKey { } -- (BOOL)shouldDelayInstallRequest { return NO; } -+ (NSURL *)getUrlForCookieBasedMatchingWithBranchKey:(NSString *)branchKey redirectUrl:(NSString *)redirectUrl { return nil; } ++ (BNCStrongMatchHelper *)strongMatchHelper { + return nil; +} + +- (void)createStrongMatchWithBranchKey:(NSString *)branchKey { +} + +- (BOOL)shouldDelayInstallRequest { + return NO; +} + ++ (NSURL *)getUrlForCookieBasedMatchingWithBranchKey:(NSString *)branchKey + redirectUrl:(NSString *)redirectUrl { + return nil; +} @end -#else -NSInteger const ABOUT_30_DAYS_TIME_IN_SECONDS = 60 * 60 * 24 * 30; +#else // ------------------------------------------------------------------------------ iOS >= 9.0 +#import -@interface BNCStrongMatchHelper () -@property (strong, nonatomic) UIWindow *secondWindow; +#pragma mark - BNCMatchView + + +@interface BNCMatchView : UIView +@end + + +@implementation BNCMatchView + +- (instancetype) initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + self.alpha = 0.0; + return self; +} + +- (void) setAlpha:(CGFloat)alpha { + [super setAlpha:0.0]; +} + +- (CGFloat) alpha { + return 1.0; +} + +@end + + +#pragma mark - BNCMatchViewController + + +// This is a class interface that will be dynamically subclassed from SFSafariViewController +@interface BNCMatchViewController : UIViewController +@end + + +@implementation BNCMatchViewController + +- (instancetype) initWithURL:(NSURL*)URL { + self = [super init]; + return self; +} + +- (BOOL) canBecomeFirstResponder { + return NO; +} + +- (BOOL) becomeFirstResponder { + return NO; +} + +- (UIResponder*) nextResponder { + return nil; +} + +- (void) setDelegate:(id)delegate { +} + +@end + + +#pragma mark - BNCStrongMatchHelper iOS 9.0 + + +@interface BNCStrongMatchHelper () @property (assign, nonatomic) BOOL requestInProgress; @property (assign, nonatomic) BOOL shouldDelayInstallRequest; - +@property (strong, nonatomic) UIWindow *primaryWindow; +@property (strong, nonatomic) BNCMatchView *matchView; +@property (strong, nonatomic) BNCMatchViewController *matchViewController; @end + @implementation BNCStrongMatchHelper + (BNCStrongMatchHelper *)strongMatchHelper { @@ -49,7 +130,8 @@ + (BNCStrongMatchHelper *)strongMatchHelper { return strongMatchHelper; } -+ (NSURL *)getUrlForCookieBasedMatchingWithBranchKey:(NSString *)branchKey redirectUrl:(NSString *)redirectUrl { ++ (NSURL *)getUrlForCookieBasedMatchingWithBranchKey:(NSString *)branchKey + redirectUrl:(NSString *)redirectUrl { if (!branchKey) { return nil; } @@ -62,12 +144,16 @@ + (NSURL *)getUrlForCookieBasedMatchingWithBranchKey:(NSString *)branchKey redir } else { appDomainLinkURL = BNC_LINK_URL; } - NSMutableString *urlString = [[NSMutableString alloc] initWithFormat:@"%@/_strong_match?os=%@", appDomainLinkURL, [BNCSystemObserver getOS]]; + NSMutableString *urlString = + [[NSMutableString alloc] initWithFormat:@"%@/_strong_match?os=%@", + appDomainLinkURL, [BNCSystemObserver getOS]]; BNCPreferenceHelper *preferenceHelper = [BNCPreferenceHelper preferenceHelper]; BOOL isRealHardwareId; NSString *hardwareIdType; - NSString *hardwareId = [BNCSystemObserver getUniqueHardwareId:&isRealHardwareId isDebug:preferenceHelper.isDebug andType:&hardwareIdType]; + NSString *hardwareId = + [BNCSystemObserver getUniqueHardwareId:&isRealHardwareId + isDebug:preferenceHelper.isDebug andType:&hardwareIdType]; if (!hardwareId || !isRealHardwareId) { [preferenceHelper logWarning:@"Cannot use cookie-based matching while setDebug is enabled"]; return nil; @@ -76,88 +162,160 @@ + (NSURL *)getUrlForCookieBasedMatchingWithBranchKey:(NSString *)branchKey redir [urlString appendFormat:@"&%@=%@", BRANCH_REQUEST_KEY_HARDWARE_ID, hardwareId]; if (preferenceHelper.deviceFingerprintID) { - [urlString appendFormat:@"&%@=%@", BRANCH_REQUEST_KEY_DEVICE_FINGERPRINT_ID, preferenceHelper.deviceFingerprintID]; + [urlString appendFormat:@"&%@=%@", + BRANCH_REQUEST_KEY_DEVICE_FINGERPRINT_ID, + preferenceHelper.deviceFingerprintID]; } if ([BNCSystemObserver getAppVersion]) { - [urlString appendFormat:@"&%@=%@", BRANCH_REQUEST_KEY_APP_VERSION, [BNCSystemObserver getAppVersion]]; + [urlString appendFormat:@"&%@=%@", + BRANCH_REQUEST_KEY_APP_VERSION, + [BNCSystemObserver getAppVersion]]; } [urlString appendFormat:@"&branch_key=%@", branchKey]; - [urlString appendFormat:@"&sdk=ios%@", SDK_VERSION]; if (redirectUrl) { - [urlString appendFormat:@"&redirect_url=%@", [redirectUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; + [urlString appendFormat:@"&redirect_url=%@", + [redirectUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; } - return [NSURL URLWithString:[urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; + NSString *escapedURL = + [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + return [NSURL URLWithString:escapedURL]; } - (void)createStrongMatchWithBranchKey:(NSString *)branchKey { - if (self.requestInProgress) { - return; - } + @synchronized (self) { + if (self.requestInProgress) return; - self.requestInProgress = YES; - - NSDate *thirtyDaysAgo = [NSDate dateWithTimeIntervalSinceNow:-ABOUT_30_DAYS_TIME_IN_SECONDS]; - NSDate *lastCheck = [BNCPreferenceHelper preferenceHelper].lastStrongMatchDate; - if ([lastCheck compare:thirtyDaysAgo] == NSOrderedDescending) { - self.requestInProgress = NO; - return; - } - - self.shouldDelayInstallRequest = YES; - [self presentSafariVCWithBranchKey:branchKey]; -} + NSInteger const ABOUT_30_DAYS_TIME_IN_SECONDS = 60 * 60 * 24 * 30; + NSDate *thirtyDaysAgo = [NSDate dateWithTimeIntervalSinceNow:-ABOUT_30_DAYS_TIME_IN_SECONDS]; + NSDate *lastCheck = [BNCPreferenceHelper preferenceHelper].lastStrongMatchDate; + if ([lastCheck compare:thirtyDaysAgo] == NSOrderedDescending) return; + + NSURL *strongMatchUrl = + [BNCStrongMatchHelper + getUrlForCookieBasedMatchingWithBranchKey:branchKey + redirectUrl:nil]; + if (!strongMatchUrl) return; + + self.requestInProgress = YES; + self.shouldDelayInstallRequest = YES; -- (void)presentSafariVCWithBranchKey:(NSString *)branchKey { - NSURL *strongMatchUrl = [BNCStrongMatchHelper getUrlForCookieBasedMatchingWithBranchKey:branchKey redirectUrl:nil]; - if (!strongMatchUrl) { - self.shouldDelayInstallRequest = NO; - self.requestInProgress = NO; - return; - } - - Class SFSafariViewControllerClass = NSClassFromString(@"SFSafariViewController"); - Class UIApplicationClass = NSClassFromString(@"UIApplication"); - if (SFSafariViewControllerClass) { - // Must be on next run loop to avoid a warning dispatch_async(dispatch_get_main_queue(), ^{ - UIViewController * safController = [[SFSafariViewControllerClass alloc] initWithURL:strongMatchUrl]; - self.secondWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; - self.secondWindow.rootViewController = safController; - self.secondWindow.windowLevel = UIWindowLevelNormal - 100; - [self.secondWindow setHidden:NO]; - UIWindow *keyWindow = [[UIApplicationClass sharedApplication] keyWindow]; - [self.secondWindow makeKeyWindow]; - - // Give enough time for Safari to load the request (optimized for 3G) - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - [keyWindow makeKeyWindow]; - - // Remove the window and release it's strong reference. This is important to ensure that - // applications using view controller based status bar appearance are restored. - [self.secondWindow removeFromSuperview]; - self.secondWindow = nil; - - [BNCPreferenceHelper preferenceHelper].lastStrongMatchDate = [NSDate date]; + + if (![self willLoadViewControllerWithURL:strongMatchUrl]) { + self.shouldDelayInstallRequest = NO; self.requestInProgress = NO; - }); + return; + } + + // Give enough time for Safari to load the request (optimized for 3G) + dispatch_after( + dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), + dispatch_get_main_queue(), + ^{ [self unloadViewController]; } + ); }); } - else { - self.requestInProgress = NO; +} + +- (BOOL) subclass:(Class)subclass selector:(SEL)selector { + Class templateClass = objc_getClass("BNCMatchViewController"); + if (!templateClass) return NO; + + Method method = class_getInstanceMethod(templateClass, selector); + if (!method) return NO; + + const char * typeEncoding = method_getTypeEncoding(method); + if (!typeEncoding) return NO; + + IMP implementation = class_getMethodImplementation(templateClass, selector); + if (!implementation) return NO; + + class_addMethod(subclass, selector, implementation, typeEncoding); + return YES; +} + +- (BOOL) willLoadViewControllerWithURL:(NSURL*)matchURL { + if (self.primaryWindow) return NO; + + // Dynamically subclass the SFSafariViewController if available. + // This allows us to compile and link to an app that doesn't + // include SafariServices, but is also able to compile and link + // when it is. + + Class SFSafariViewControllerClass = NSClassFromString(@"SFSafariViewController"); + if (!SFSafariViewControllerClass) return NO; + + Class BNCMatchViewControllerSubclass = NSClassFromString(@"BNCMatchViewController_Safari"); + if (!BNCMatchViewControllerSubclass) { + // The class isn't registered. Create it: + + BNCMatchViewControllerSubclass = + objc_allocateClassPair(SFSafariViewControllerClass, "BNCMatchViewController_Safari", 0); + if (!BNCMatchViewControllerSubclass) return NO; + + BOOL fail = NO; + fail |= ![self subclass:BNCMatchViewControllerSubclass selector:@selector(becomeFirstResponder)]; + fail |= ![self subclass:BNCMatchViewControllerSubclass selector:@selector(canBecomeFirstResponder)]; + fail |= ![self subclass:BNCMatchViewControllerSubclass selector:@selector(nextResponder)]; + if (fail) { + objc_disposeClassPair(BNCMatchViewControllerSubclass); + return NO; + } + objc_registerClassPair(BNCMatchViewControllerSubclass); } + + NSLog(@"Safari initializing."); // eDebug + self.matchViewController = [[BNCMatchViewControllerSubclass alloc] initWithURL:matchURL]; + if (!self.matchViewController) return NO; + + self.primaryWindow = [[UIApplication sharedApplication] keyWindow]; + self.matchViewController.delegate = self; + self.matchViewController.view.frame = self.primaryWindow.bounds; + + self.matchView = [[BNCMatchView alloc] initWithFrame:self.primaryWindow.bounds]; + self.matchView.alpha = 1.0; + [self.matchView addSubview:self.matchViewController.view]; + + [self.primaryWindow.rootViewController addChildViewController:self.matchViewController]; + UIView *parentView = self.primaryWindow.rootViewController.view ?: self.primaryWindow; + [parentView insertSubview:self.matchView atIndex:0]; + + [self.matchViewController didMoveToParentViewController:self.primaryWindow.rootViewController]; + + return YES; } -- (BOOL)shouldDelayInstallRequest { - return _shouldDelayInstallRequest; +- (void) unloadViewController { + NSLog(@"Safari unloadViewController"); // eDebug + + [self.matchViewController willMoveToParentViewController:nil]; + [self.matchViewController.view removeFromSuperview]; + [self.matchViewController removeFromParentViewController]; + self.matchViewController.delegate = nil; + self.matchViewController = nil; + + [self.matchView removeFromSuperview]; + self.matchView = nil; + + self.primaryWindow = nil; + + [BNCPreferenceHelper preferenceHelper].lastStrongMatchDate = [NSDate date]; + self.shouldDelayInstallRequest = NO; + self.requestInProgress = NO; } +- (void)safariViewController:(SFSafariViewController *)controller + didCompleteInitialLoad:(BOOL)didLoadSuccessfully { + NSLog(@"Safari Did load. Success: %d.", didLoadSuccessfully); // eDebug + [self unloadViewController]; +} @end -#endif +#endif // ------------------------------------------------------------------------------ iOS >= 9.0 diff --git a/src/ios/dependencies/Branch-SDK/Branch.m b/src/ios/dependencies/Branch-SDK/Branch.m index 5151e1ba..540f2edd 100644 --- a/src/ios/dependencies/Branch-SDK/Branch.m +++ b/src/ios/dependencies/Branch-SDK/Branch.m @@ -72,11 +72,10 @@ @interface Branch() @property (strong, nonatomic) BNCServerInterface *bServerInterface; -@property (strong, nonatomic) NSTimer *sessionTimer; @property (strong, nonatomic) BNCServerRequestQueue *requestQueue; @property (strong, nonatomic) dispatch_semaphore_t processing_sema; -@property (strong, nonatomic) callbackWithParams sessionInitWithParamsCallback; -@property (strong, nonatomic) callbackWithBranchUniversalObject sessionInitWithBranchUniversalObjectCallback; +@property (copy, nonatomic) callbackWithParams sessionInitWithParamsCallback; +@property (copy, nonatomic) callbackWithBranchUniversalObject sessionInitWithBranchUniversalObjectCallback; @property (assign, nonatomic) NSInteger networkCount; @property (assign, nonatomic) BOOL isInitialized; @property (assign, nonatomic) BOOL shouldCallSessionInitCallback; @@ -86,7 +85,7 @@ @interface Branch() @property (strong, nonatomic) BNCContentDiscoveryManager *contentDiscoveryManager; @property (strong, nonatomic) NSString *branchKey; @property (strong, nonatomic) NSMutableDictionary *deepLinkControllers; -@property (weak, nonatomic) UIViewController *deepLinkPresentingController; +@property (weak, nonatomic) UIViewController *deepLinkPresentingController; @property (assign, nonatomic) BOOL useCookieBasedMatching; @property (strong, nonatomic) NSDictionary *deepLinkDebugParams; @property (assign, nonatomic) BOOL accountForFacebookSDK; @@ -94,7 +93,7 @@ @interface Branch() @property (assign, nonatomic) BOOL delayForAppleAds; @property (assign, nonatomic) BOOL searchAdsDebugMode; @property (strong, nonatomic) NSMutableArray *whiteListedSchemeList; - +@property (assign, nonatomic) BOOL appIsInBackground; @end @implementation Branch @@ -1152,6 +1151,7 @@ - (BNCLinkData *)prepareLinkDataFor:(NSArray *)tags andAlias:(NSString *)alias a #pragma mark - BranchUniversalObject methods + - (void)registerViewWithParams:(NSDictionary *)params andCallback:(callbackWithParams)callback { [self initSessionIfNeededAndNotInProgress]; @@ -1164,22 +1164,18 @@ - (void)registerViewWithParams:(NSDictionary *)params andCallback:(callbackWithP #pragma mark - Application State Change methods - (void)applicationDidBecomeActive { - [self clearTimer]; + self.appIsInBackground = NO; 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.appIsInBackground = YES; + [self callClose]; [self.requestQueue persistImmediately]; } -- (void)clearTimer { - [self.sessionTimer invalidate]; -} - - (void)callClose { if (self.isInitialized) { self.isInitialized = NO; @@ -1268,11 +1264,7 @@ - (void)processNextQueueItem { [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]; - } - + [req makeRequest:self.bServerInterface key:self.branchKey callback:callback]; } } @@ -1338,26 +1330,17 @@ - (void)registerInstallOrOpen:(Class)clazz { if ([BNCSystemObserver getOSVersion].integerValue >= 9 && self.useCookieBasedMatching) { [[BNCStrongMatchHelper strongMatchHelper] createStrongMatchWithBranchKey:self.branchKey]; } - - // If there isn't already an Open / Install request, add one to the queue - if (![self.requestQueue containsInstallOrOpen]) { - BranchOpenRequest *req = [[clazz alloc] initWithCallback:initSessionCallback]; - - [self insertRequestAtFront:req]; - } - // If there is already one in the queue, make sure it's in the front. - // Make sure a callback is associated with this request. This callback can - // be cleared if the app is terminated while an Open/Install is pending. - else { - BranchOpenRequest *req = [self.requestQueue moveInstallOrOpenToFront:self.networkCount]; - req.callback = initSessionCallback; - } - + + if ([self.requestQueue removeInstallOrOpen]) + self.networkCount = 0; + BranchOpenRequest *req = [[clazz alloc] initWithCallback:initSessionCallback]; + [self insertRequestAtFront:req]; [self processNextQueueItem]; } - (void)handleInitSuccess { - self.isInitialized = YES; + if (!self.appIsInBackground) + self.isInitialized = YES; NSDictionary *latestReferringParams = [self getLatestReferringParams]; if (self.shouldCallSessionInitCallback) { @@ -1433,7 +1416,7 @@ + (NSString *)bundleIdentifier { } + (NSString *)kitDisplayVersion { - return @"0.12.19"; + return SDK_VERSION; } -@end \ No newline at end of file +@end diff --git a/src/ios/dependencies/Branch-SDK/BranchActivityItemProvider.m b/src/ios/dependencies/Branch-SDK/BranchActivityItemProvider.m index 2d183b4a..ebcbea98 100644 --- a/src/ios/dependencies/Branch-SDK/BranchActivityItemProvider.m +++ b/src/ios/dependencies/Branch-SDK/BranchActivityItemProvider.m @@ -94,6 +94,12 @@ + (NSString *)humanReadableChannelWithActivityType:(NSString *)activityString { @"WeChat", @"com.tencent.xin.sharetimeline", @"LINE", @"jp.naver.line.Share", @"Pinterest", @"pinterest.ShareExtension", + + // Keys for older app versions -- + + @"Facebook", @"com.facebook.Facebook.ShareExtension", + @"Twitter", @"com.atebits.Tweetie2.ShareExtension", + nil ]; // Set to a more human readible sting if we can identify it diff --git a/src/ios/dependencies/Branch-SDK/Requests/BranchOpenRequest.h b/src/ios/dependencies/Branch-SDK/Requests/BranchOpenRequest.h index db1315d3..14c10ab8 100644 --- a/src/ios/dependencies/Branch-SDK/Requests/BranchOpenRequest.h +++ b/src/ios/dependencies/Branch-SDK/Requests/BranchOpenRequest.h @@ -11,7 +11,7 @@ @interface BranchOpenRequest : BNCServerRequest -@property (strong, nonatomic) callbackWithStatus callback; +@property (copy, nonatomic) callbackWithStatus callback; - (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 8d0f3655..1f5d0ec3 100644 --- a/src/ios/dependencies/Branch-SDK/Requests/BranchOpenRequest.m +++ b/src/ios/dependencies/Branch-SDK/Requests/BranchOpenRequest.m @@ -16,12 +16,12 @@ #import "BranchContentDiscoveryManifest.h" #import "BranchContentDiscoverer.h" -@interface BranchOpenRequest () +@interface BranchOpenRequest () @property (assign, nonatomic) BOOL isInstall; - @end + @implementation BranchOpenRequest - (id)initWithCallback:(callbackWithStatus)callback { diff --git a/src/ios/dependencies/Branch.framework/Versions/A/Branch b/src/ios/dependencies/Branch.framework/Versions/A/Branch index 79c7484c..d9bc2ec2 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/BNCCallbacks.h b/src/ios/dependencies/Branch.framework/Versions/A/Headers/BNCCallbacks.h index 7b47030e..a0c74409 100644 --- a/src/ios/dependencies/Branch.framework/Versions/A/Headers/BNCCallbacks.h +++ b/src/ios/dependencies/Branch.framework/Versions/A/Headers/BNCCallbacks.h @@ -11,11 +11,11 @@ @class BranchUniversalObject, BranchLinkProperties; -typedef void (^callbackWithParams) (NSDictionary * _Nonnull params, NSError * _Nullable error); -typedef void (^callbackWithUrl) (NSString * _Nonnull url, NSError * _Nullable error); +typedef void (^callbackWithParams) (NSDictionary * _Nullable params, NSError * _Nullable error); +typedef void (^callbackWithUrl) (NSString * _Nullable url, NSError * _Nullable error); typedef void (^callbackWithStatus) (BOOL changed, NSError * _Nullable error); typedef void (^callbackWithList) (NSArray * _Nullable list, NSError * _Nullable error); typedef void (^callbackWithUrlAndSpotlightIdentifier) (NSString * _Nullable url, NSString * _Nullable spotlightIdentifier, NSError * _Nullable error); -typedef void (^callbackWithBranchUniversalObject) (BranchUniversalObject * _Nonnull universalObject, BranchLinkProperties * _Nonnull linkProperties, NSError * _Nullable error); +typedef void (^callbackWithBranchUniversalObject) (BranchUniversalObject * _Nullable universalObject, BranchLinkProperties * _Nullable linkProperties, NSError * _Nullable error); #endif /* BNCCallbacks_h */ diff --git a/src/ios/dependencies/Branch.framework/Versions/A/Headers/BNCConfig.h b/src/ios/dependencies/Branch.framework/Versions/A/Headers/BNCConfig.h index 03f374fb..9a1f1826 100644 --- a/src/ios/dependencies/Branch.framework/Versions/A/Headers/BNCConfig.h +++ b/src/ios/dependencies/Branch.framework/Versions/A/Headers/BNCConfig.h @@ -6,29 +6,9 @@ // Copyright (c) 2014 Branch Metrics. All rights reserved. // -#ifndef Branch_SDK_Config_h -#define Branch_SDK_Config_h +#import -#define SDK_VERSION @"0.12.19" - -#define BNC_PROD_ENV -//#define BNC_STAGE_ENV -//#define BNC_DEV_ENV - -#ifdef BNC_PROD_ENV -#define BNC_API_BASE_URL @"https://api.branch.io" -#endif - -#ifdef BNC_STAGE_ENV -#define BNC_API_BASE_URL @"http://api.dev.branch.io" -#endif - -#define BNC_LINK_URL @"https://bnc.lt" - -#ifdef BNC_DEV_ENV -#define BNC_API_BASE_URL @"http://localhost:3001" -#endif - -#define BNC_API_VERSION @"v1" - -#endif +extern NSString * const SDK_VERSION; +extern NSString * const BNC_API_BASE_URL; +extern NSString * const BNC_LINK_URL; +extern NSString * const BNC_API_VERSION; diff --git a/src/ios/dependencies/Branch.framework/Versions/A/Headers/BNCServerRequestQueue.h b/src/ios/dependencies/Branch.framework/Versions/A/Headers/BNCServerRequestQueue.h index 44eab536..fd0286d1 100755 --- a/src/ios/dependencies/Branch.framework/Versions/A/Headers/BNCServerRequestQueue.h +++ b/src/ios/dependencies/Branch.framework/Versions/A/Headers/BNCServerRequestQueue.h @@ -26,6 +26,7 @@ - (void)clearQueue; - (BOOL)containsInstallOrOpen; +- (BOOL)removeInstallOrOpen; - (BOOL)containsClose; - (BranchOpenRequest *)moveInstallOrOpenToFront:(NSInteger)networkCount; diff --git a/testbed/www/js.es6/index.js b/testbed/www/js.es6/index.js index 5558851c..ea801228 100644 --- a/testbed/www/js.es6/index.js +++ b/testbed/www/js.es6/index.js @@ -180,6 +180,8 @@ function BranchDeepLink() { $android_url: "http://www.example.com/android", $ios_url: "http://www.example.com/ios", $ipad_url: "http://www.example.com/ipad", + $deeplink_path: "content/123", + $match_duration: 2000, more_custom: "data", even_more_custom: true, this_is_custom: 41231, diff --git a/testbed/www/js/index.js b/testbed/www/js/index.js index 0a7d663f..8d6c5f8b 100644 --- a/testbed/www/js/index.js +++ b/testbed/www/js/index.js @@ -182,6 +182,8 @@ function BranchDeepLink() { $android_url: "http://www.example.com/android", $ios_url: "http://www.example.com/ios", $ipad_url: "http://www.example.com/ipad", + $deeplink_path: "content/123", + $match_duration: 2000, more_custom: "data", even_more_custom: true, this_is_custom: 41231,