Skip to content

Commit

Permalink
Merge pull request #21 from hokolinks/feature/fingerprint
Browse files Browse the repository at this point in the history
Feature/fingerprint
  • Loading branch information
ivanbruel committed Sep 28, 2015
2 parents cb13765 + 10c2fa0 commit 31335f0
Show file tree
Hide file tree
Showing 17 changed files with 1,137 additions and 1,079 deletions.
Binary file added .DS_Store
Binary file not shown.
6 changes: 3 additions & 3 deletions Hoko/HOKDeeplink.m
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ - (NSDictionary *)generateSmartlinkJSON {
@"metadata": [HOKUtils jsonValue:self.metadata]};
} else {
return @{@"uri": [HOKUtils jsonValue:self.url],
@"routes": self.urls,
@"routes": [HOKUtils jsonValue:self.urls],
@"unique": [HOKUtils jsonValue:@(self.unique)],
@"metadata": [HOKUtils jsonValue:self.metadata]};
}
Expand All @@ -294,9 +294,9 @@ - (NSDictionary *)smartlinkJSON {

- (NSDictionary *)metadataJSON {
if (self.smartlinkClickIdentifier) {
return @{HOKDeeplinkSmartlinkClickIdentifierKey: self.smartlinkClickIdentifier};
return @{HOKDeeplinkSmartlinkClickIdentifierKey: [HOKUtils jsonValue:self.smartlinkClickIdentifier]};
} else {
return @{HOKDeeplinkSmartlinkIdentifierKey: self.smartlinkIdentifier};
return @{HOKDeeplinkSmartlinkIdentifierKey: [HOKUtils jsonValue:self.smartlinkIdentifier]};
}
}

Expand Down
2 changes: 1 addition & 1 deletion Hoko/HOKDeeplinking+Private.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

@interface HOKDeeplinking (Private)

- (instancetype)initWithToken:(NSString *)token customDomains:(NSArray *)customDomains debugMode:(BOOL)debugMode;
- (instancetype)initWithToken:(NSString *)token customDomain:(NSString *)customDomain debugMode:(BOOL)debugMode;

- (BOOL)handleOpenDeferredURL:(NSURL *)url;

Expand Down
10 changes: 5 additions & 5 deletions Hoko/HOKDeeplinking.m
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

@interface HOKDeeplinking ()

@property (nonatomic, strong) NSArray *customDomains;
@property (nonatomic, strong) NSString *customDomain;
@property (nonatomic, strong) HOKResolver *resolver;
@property (nonatomic, strong) HOKRouting *routing;
@property (nonatomic, strong) HOKHandling *handling;
Expand All @@ -39,10 +39,10 @@ @interface HOKDeeplinking ()
@implementation HOKDeeplinking

#pragma mark - Initialization
- (instancetype)initWithToken:(NSString *)token customDomains:(NSArray *)customDomains debugMode:(BOOL)debugMode {
- (instancetype)initWithToken:(NSString *)token customDomain:(NSString *)customDomain debugMode:(BOOL)debugMode {
self = [super init];
if (self) {
_customDomains = customDomains;
_customDomain = customDomain;
_routing = [[HOKRouting alloc] initWithToken:token debugMode:debugMode];
_handling = [HOKHandling new];
_filtering = [HOKFiltering new];
Expand Down Expand Up @@ -128,7 +128,7 @@ - (BOOL)continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(
if ([userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb]) {
NSURL *webpageURL = userActivity.webpageURL;
if (webpageURL) {
if ([webpageURL.host rangeOfString:@"hoko.link"].location != NSNotFound || [self.customDomains containsObject:webpageURL.host]) {
if ([webpageURL.host rangeOfString:@"hoko.link"].location != NSNotFound || [self.customDomain isEqualToString:webpageURL.host]) {
[self openSmartlink:webpageURL.absoluteString completion:^(HOKDeeplink *deeplink) {
if (!deeplink) {
[self handleOpenURL:nil];
Expand Down Expand Up @@ -171,7 +171,7 @@ - (void)generateSmartlinkForDeeplink:(HOKDeeplink *)deeplink

- (NSString *)generateLazySmartlinkForDeeplink:(HOKDeeplink *)deeplink domain:(NSString *)domain
{
return [self.linkGenerator generateLazySmartlinkForDeeplink:deeplink domain:domain customDomains:self.customDomains];
return [self.linkGenerator generateLazySmartlinkForDeeplink:deeplink domain:domain customDomain:self.customDomain];
}

#pragma mark - Deferred Deeplinking
Expand Down
78 changes: 64 additions & 14 deletions Hoko/HOKDeferredDeeplinking.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,35 @@
//

#import "HOKDeferredDeeplinking.h"

#import "HOKUtils.h"
#import "HOKLogger.h"
#import "HOKDevice.h"
#import "HOKNetworking.h"
#import "HOKNetworkOperation.h"
#import "HOKNotificationObserver.h"
#import "HOKObserver.h"
#import "HOKNavigation.h"

#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000
#import <SafariServices/SafariServices.h>
#endif


NSString *const HOKDeferredDeeplinkingNotFirstRun = @"isNotFirstRun";
NSString *const HOKDeferredDeeplinkingPath = @"installs/ios";
NSString *const HOKFingerprintMatchingPath = @"fingerprints/match";

@interface HOKDeferredDeeplinking ()
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000
<SFSafariViewControllerDelegate>
#endif

@property (nonatomic, strong) NSString *token;
@property (nonatomic, copy) void (^handler)(NSString *deeplink);

#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000
@property (nonatomic, strong) SFSafariViewController *safariViewController;
#endif

@end

Expand All @@ -38,24 +52,60 @@ - (instancetype)initWithToken:(NSString *)token {
- (void)requestDeferredDeeplink:(void (^)(NSString *))handler {
BOOL isFirstRun = ![[HOKUtils objectForKey:HOKDeferredDeeplinkingNotFirstRun] boolValue];
if (isFirstRun) {
[HOKUtils saveObject:@YES key:HOKDeferredDeeplinkingNotFirstRun];
[HOKNetworking postToPath:[HOKNetworkOperation urlFromPath:HOKDeferredDeeplinkingPath] parameters:self.json token:self.token successBlock:^(id json) {
NSString *deeplink = [json objectForKey:@"deeplink"];
if (deeplink && [deeplink isKindOfClass:[NSString class]] && handler) {
handler(deeplink);
}
} failedBlock:^(NSError *error) {
HOKErrorLog(error);
}];
self.handler = handler;

#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000
if (HOKSystemVersionGreaterThanOrEqualTo(@"9.0")) {
NSString *fingerprintURL = [NSString stringWithFormat:@"%@?uid=%@", [HOKNetworkOperation urlFromPath:HOKFingerprintMatchingPath], [HOKDevice device].uid];
self.safariViewController = [[SFSafariViewController alloc] initWithURL:[NSURL URLWithString:fingerprintURL]];
self.safariViewController.delegate = self;

UIViewController *rootViewController = [[UIViewController alloc] init];

UIWindow *window = [[UIWindow alloc] initWithFrame:CGRectZero];
window.rootViewController = rootViewController;
[window makeKeyAndVisible];
window.alpha = 0;

[rootViewController presentViewController:self.safariViewController animated:NO completion:nil];
} else {
[self requestDeferredDeeplink];
}
#else
[self requestDeferredDeeplink];
#endif
}
}

- (void)requestDeferredDeeplink {
[HOKUtils saveObject:@YES key:HOKDeferredDeeplinkingNotFirstRun];
[HOKNetworking postToPath:[HOKNetworkOperation urlFromPath:HOKDeferredDeeplinkingPath] parameters:self.json token:self.token successBlock:^(id json) {
NSString *deeplink = [json objectForKey:@"deeplink"];
if (deeplink && [deeplink isKindOfClass:[NSString class]] && self.handler) {
self.handler(deeplink);
}
} failedBlock:^(NSError *error) {
HOKErrorLog(error);
}];
}

- (NSDictionary *)json {
return @{@"device": @{@"os_version": [HOKDevice device].systemVersion,
@"device_type": [HOKDevice device].platform,
@"language": [HOKDevice device].systemLanguage.lowercaseString,
@"screen_size": [HOKDevice device].screenSize}
return @{@"device": @{@"os_version": [HOKUtils jsonValue:[HOKDevice device].systemVersion],
@"device_type": [HOKUtils jsonValue:[HOKDevice device].platform],
@"language": [HOKUtils jsonValue:[HOKDevice device].systemLanguage.lowercaseString],
@"screen_size": [HOKUtils jsonValue:[HOKDevice device].screenSize],
@"uid": [HOKUtils jsonValue:[HOKDevice device].uid] }
};
}



#pragma mark - SFSafariViewController delegate method
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 90000
- (void)safariViewController:(SFSafariViewController *)controller didCompleteInitialLoad:(BOOL)didLoadSuccessfully {
[self.safariViewController.presentingViewController dismissViewControllerAnimated:NO completion:nil];
[self requestDeferredDeeplink];
}
#endif

@end
2 changes: 1 addition & 1 deletion Hoko/HOKError.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
+ (NSError *)serverWarning:(NSDictionary *)warningJSON;
+ (NSError *)invalidJSONMetadata;
+ (NSError *)lazySmartlinkCantHaveURLsError;
+ (NSError *)domainUnknown:(NSString *)domain customDomains:(NSArray *)customDomains;
+ (NSError *)domainUnknown:(NSString *)domain customDomain:(NSString *)customDomain;
+ (NSError *)invalidDomain:(NSString *)domain;

@end
6 changes: 3 additions & 3 deletions Hoko/HOKError.m
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,12 @@ + (NSError *)lazySmartlinkCantHaveURLsError
return [self errorWithCode:17 description:@"Lazy smartlinks cannot have custom URLs for each platform."];
}

+ (NSError *)domainUnknown:(NSString *)domain customDomains:(NSArray *)customDomains
+ (NSError *)domainUnknown:(NSString *)domain customDomain:(NSString *)customDomain
{
if (!customDomains || customDomains.count == 0) {
if (!customDomain) {
return [self errorWithCode:18 description:[NSString stringWithFormat:@"To generate a lazy smartlink you need to provide a known domain. %@ is not a hoko.link subdomain.", domain]];
} else {
return [self errorWithCode:18 description:[NSString stringWithFormat:@"To generate a lazy smartlink you need to provide a known domain. %@ is not a hoko.link subdomain nor is it included in your custom domains %@.", domain, [customDomains description]]];
return [self errorWithCode:18 description:[NSString stringWithFormat:@"To generate a lazy smartlink you need to provide a known domain. %@ is not a hoko.link subdomain nor is it your custom domain %@.", domain, customDomain]];
}
}

Expand Down
2 changes: 1 addition & 1 deletion Hoko/HOKLinkGenerator.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@
- (void)generateSmartlinkForDeeplink:(HOKDeeplink *)deeplink
success:(void (^)(NSString *smartlink))success
failure:(void (^)(NSError *error))failure;
- (NSString *)generateLazySmartlinkForDeeplink:(HOKDeeplink *)deeplink domain:(NSString *)domain customDomains:(NSArray *)customDomains;
- (NSString *)generateLazySmartlinkForDeeplink:(HOKDeeplink *)deeplink domain:(NSString *)domain customDomain:(NSString *)customDomain;

@end
6 changes: 3 additions & 3 deletions Hoko/HOKLinkGenerator.m
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ - (void)generateSmartlinkForDeeplink:(HOKDeeplink *)deeplink
}
}

- (NSString *)generateLazySmartlinkForDeeplink:(HOKDeeplink *)deeplink domain:(NSString *)domain customDomains:(NSArray *)customDomains
- (NSString *)generateLazySmartlinkForDeeplink:(HOKDeeplink *)deeplink domain:(NSString *)domain customDomain:(NSString *)customDomain
{
if (deeplink && domain) {
if (deeplink.hasURLs) {
Expand All @@ -58,10 +58,10 @@ - (NSString *)generateLazySmartlinkForDeeplink:(HOKDeeplink *)deeplink domain:(N
strippedDomain = [strippedDomain stringByReplacingOccurrencesOfString:@"https://" withString:@""];
if ([strippedDomain rangeOfString:@"/"].location != NSNotFound) {
HOKErrorLog([HOKError invalidDomain:domain]);
} else if ([customDomains containsObject:strippedDomain] || [strippedDomain rangeOfString:@"hoko.link"].location != NSNotFound) {
} else if ([customDomain isEqualToString:strippedDomain] || [strippedDomain rangeOfString:@"hoko.link"].location != NSNotFound) {
return [NSString stringWithFormat:@"http://%@/lazy?uri=%@", strippedDomain, [HOKLinkGenerator URLEncodeStringFromString:deeplink.url]];
} else {
HOKErrorLog([HOKError domainUnknown:domain customDomains:customDomains]);
HOKErrorLog([HOKError domainUnknown:domain customDomain:customDomain]);
}
}
return nil;
Expand Down
5 changes: 3 additions & 2 deletions Hoko/HOKResolver.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#import "HOKResolver.h"

#import "HOKUtils.h"
#import "HOKDevice.h"
#import "HOKLogger.h"
#import "HOKNetworking.h"
Expand Down Expand Up @@ -54,8 +55,8 @@ - (id)jsonWithSmartlink:(NSString *)smartlink {
smartlinkString = [(NSURL *)smartlink absoluteString];
}

return @{@"smartlink": smartlinkString,
@"uid": [HOKDevice device].uid};
return @{@"smartlink": [HOKUtils jsonValue:smartlinkString],
@"uid": [HOKUtils jsonValue:[HOKDevice device].uid] };
}


Expand Down
10 changes: 5 additions & 5 deletions Hoko/HOKRoute.m
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,11 @@ - (void)postWithToken:(NSString *)token {

#pragma mark - Serialization
- (NSDictionary *)json {
return @{@"route": @{@"build": [HOKApp app].build,
@"device": [HOKDevice device].platform,
@"path": self.route,
@"url_schemes": [HOKApp app].urlSchemes,
@"version": [HOKApp app].version}};
return @{@"route": @{@"build": [HOKUtils jsonValue:[HOKApp app].build],
@"device": [HOKUtils jsonValue:[HOKDevice device].platform],
@"path": [HOKUtils jsonValue:self.route],
@"url_schemes": [HOKUtils jsonValue:[HOKApp app].urlSchemes],
@"version": [HOKUtils jsonValue:[HOKApp app].version]}};
}


Expand Down
11 changes: 7 additions & 4 deletions Hoko/HOKSwizzling.m
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ + (NSString *)appDelegateClassName {
for (int i = 0; i < numClasses; i++) {
Class class = classes[i];
// Avoiding StoreKit inner classes
if (class_conformsToProtocol(class, @protocol(UIApplicationDelegate)) && ![class isSubclassOfClass:[UIApplication class]]) {
if (class_conformsToProtocol(class, @protocol(UIApplicationDelegate)) && ![class isSubclassOfClass:[UIApplication class]] && class_getSuperclass(class) == [UIResponder class]) {
appDelegates = [appDelegates arrayByAddingObject:NSStringFromClass(classes[i])];
}
}
Expand All @@ -50,8 +50,11 @@ + (NSString *)appDelegateClassName {

if (appDelegates.count == 1) {
return appDelegates.firstObject;
} else if (appDelegates.count > 1) {
NSLog(@"[HOKO] We have detected that you have %@ classes that implement the UIApplicationDelegate protocol (%@), please go to http://goo.gl/DGZGSL for how to manually delegate deep links to HOKO.", @(appDelegates.count), appDelegates);
} else {
NSLog(@"[HOKO] We could not detect your AppDelegate class, HOKO requires your AppDelegate to descend from UIResponder and implement UIApplicationDelegate. Please go to http://goo.gl/DGZGSL for how to manually delegate deep links to HOKO.");
}
NSLog(@"[HOKO] We have detected that you have %@ classes that implement the UIApplicationDelegate protocol (%@), please go to http://goo.gl/DGZGSL for how to manually delegate deep links to HOKO.", @(appDelegates.count), appDelegates);
return nil;
}

Expand Down Expand Up @@ -121,7 +124,7 @@ + (void)swizzleHOKDeeplinking {
[self swizzleOpenURLWithAppDelegateClassName:appDelegateClassName];
[self swizzleLegacyOpenURLWithAppDelegateClassName:appDelegateClassName];

#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 80000
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
[self swizzleContinueUserActivityWithAppDelegateClassName:appDelegateClassName];
#endif

Expand Down Expand Up @@ -158,7 +161,7 @@ + (void)swizzleLegacyOpenURLWithAppDelegateClassName:(NSString *)appDelegateClas
}];
}

#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 80000
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
+ (void)swizzleContinueUserActivityWithAppDelegateClassName:(NSString *)appDelegateClassName {
__block IMP implementation = [HOKSwizzling swizzleClassWithClassname:appDelegateClassName originalSelector:@selector(application:continueUserActivity:restorationHandler:) block:^BOOL (id blockSelf, UIApplication *application, NSUserActivity *userActivity, id restorationHandler){

Expand Down
4 changes: 4 additions & 0 deletions Hoko/HOKURL.m
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@ + (NSString *)pathForURLString:(NSString *)urlString urlScheme:(NSString *)urlSc
[path deleteCharactersInRange:NSMakeRange(0, 1)];
}

if ([path hasSuffix:@"/"] && path.length > 0) {
[path deleteCharactersInRange:NSMakeRange(path.length-1, 1)];
}

return path;
}
}
Expand Down
4 changes: 2 additions & 2 deletions Hoko/Hoko.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@
* as you will be able to track everything through automatic Analytics, which
* will be shown on your Hoko dashboards. Will also make sure HOKO works with your custom domains.
* <pre>
* [Hoko setupWithToken:@"YOUR-API-TOKEN" customDomains:@[@"your.custom.domain.com"]];
* [Hoko setupWithToken:@"YOUR-API-TOKEN" customDomain:@"your.custom.domain.com"];
* </pre>
*
* @param token Hoko service API key.
*/
+ (void)setupWithToken:(hok_nonnull NSString *)token customDomains:(hok_nullable NSArray hok_generic(NSString *) *)customDomains;
+ (void)setupWithToken:(hok_nonnull NSString *)token customDomain:(hok_nullable NSString *)customDomain;


/**
Expand Down
10 changes: 5 additions & 5 deletions Hoko/Hoko.m
Original file line number Diff line number Diff line change
Expand Up @@ -42,25 +42,25 @@ + (instancetype)hoko {

#pragma mark - Setup
+ (void)setupWithToken:(NSString *)token {
[self setupWithToken:token customDomains:nil];
[self setupWithToken:token customDomain:nil];
}

+ (void)setupWithToken:(NSString *)token customDomains:(NSArray *)customDomains {
+ (void)setupWithToken:(NSString *)token customDomain:(NSString *)customDomain {
if (onceToken != 0) {
HOKErrorLog([HOKError setupCalledMoreThanOnceError]);
NSAssert(NO, [HOKError setupCalledMoreThanOnceError].description);
}

dispatch_once(&onceToken, ^{
_sharedInstance = [[Hoko alloc] initWithToken:token
customDomains:customDomains
customDomain:customDomain
debugMode:[HOKApp app].isDebugBuild];
});
}

#pragma mark - Initializer
- (instancetype)initWithToken:(NSString *)token
customDomains:(NSArray *)customDomains
customDomain:(NSString *)customDomain
debugMode:(BOOL)debugMode {

if (self = [super init]) {
Expand All @@ -70,7 +70,7 @@ - (instancetype)initWithToken:(NSString *)token
[[HOKDevice device] setupReachability];

[[HOKNetworkOperationQueue sharedQueue] setup];
_deeplinking = [[HOKDeeplinking alloc] initWithToken:token customDomains:customDomains debugMode:debugMode];
_deeplinking = [[HOKDeeplinking alloc] initWithToken:token customDomain:customDomain debugMode:debugMode];

[self checkVersions];

Expand Down
Loading

0 comments on commit 31335f0

Please sign in to comment.