-
Notifications
You must be signed in to change notification settings - Fork 10
/
JPXUIWebViewJSBridge.m
136 lines (122 loc) · 5.54 KB
/
JPXUIWebViewJSBridge.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
//
// JPXUIWebViewJSBridge.m
// WebViewJSBridge
//
// Created by jianpx on 6/26/14.
// Copyright (c) 2014 JPX. All rights reserved.
//
#import "JPXUIWebViewJSBridge.h"
@interface JPXUIWebViewJSBridge()
@property (nonatomic, strong) id handler;
@end
NSString * const JPXUIWebViewJSBridgeErrorDomain = @"JPXUIWebViewJSBridgeErrorDomain";
const NSInteger JPXUIWebViewJSBridgeErrorCode = 1;
@implementation JPXUIWebViewJSBridge
- (instancetype)initWithHandler:(id)handler
{
self = [super init];
if (self) {
self.handler = handler;
}
return self;
}
- (BOOL)canHandleRequest:(NSURLRequest *)request error:(NSError **)error
{
NSInteger matchIndex = [self findMatchIndexOfURLScheme:request.URL.absoluteString error:error];
if (matchIndex == NSNotFound) {
*error = [NSError errorWithDomain:JPXUIWebViewJSBridgeErrorDomain
code:JPXUIWebViewJSBridgeErrorCode
userInfo:@{NSLocalizedDescriptionKey: NSLocalizedString(@"can not match any of your url pattern", @"")}];
}
return !(matchIndex == NSNotFound) ;
}
- (NSInteger)findMatchIndexOfURLScheme:(NSString *)url error:(NSError **)error
{
NSPredicate *p = nil;
NSInteger matchIndex = NSNotFound;
for (NSUInteger i = 0; i < self.routines.count; i++) {
if (![self.routines[i] isKindOfClass:[NSArray class]]) {
*error = [NSError errorWithDomain:JPXUIWebViewJSBridgeErrorDomain
code:JPXUIWebViewJSBridgeErrorCode
userInfo:@{NSLocalizedDescriptionKey: NSLocalizedString(@"element in routines is not NSArray", @"")}];
break;
}
NSArray *routinePair = self.routines[i];
if (routinePair.count != 2) {
*error = [NSError errorWithDomain:JPXUIWebViewJSBridgeErrorDomain
code:JPXUIWebViewJSBridgeErrorCode
userInfo:@{NSLocalizedDescriptionKey: NSLocalizedString(@"element in routines should be NSArray that contains 2 items", @"")}];
break;
}
NSString *pattern = routinePair[0];
p = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", pattern];
if ([p evaluateWithObject:url]) {
matchIndex = i;
}
}
return matchIndex;
}
- (NSString *)getQueryStringInURL:(NSString *)url
{
NSURL *_url = [NSURL URLWithString:url];
return _url.query;
}
- (NSDictionary *)dictionaryFromQueryString:(NSString *)queryString
{
NSArray *urlComponents = [queryString componentsSeparatedByString:@"&"];
if (urlComponents.count <= 0) {
return nil;
}
NSMutableDictionary *queryDict = [NSMutableDictionary dictionary];
for (NSString *keyValuePair in urlComponents) {
NSArray *pairComponents = [keyValuePair componentsSeparatedByString:@"="];
if ([pairComponents[1] isKindOfClass:[NSString class]]) {
[queryDict setObject:[pairComponents[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]
forKey:pairComponents[0]];
} else {
[queryDict setObject:pairComponents[1] forKey:pairComponents[0]];
}
}
return [queryDict copy];
}
- (void)handleRequest:(NSURLRequest *)request error:(NSError **)error
{
NSString *url = request.URL.absoluteString;
NSInteger matchIndex = [self findMatchIndexOfURLScheme:url error:error];
NSDictionary *errorUserInfo = nil;
if (matchIndex == NSNotFound) {
errorUserInfo = @{NSLocalizedDescriptionKey: NSLocalizedString(@"url pattern not found!", @"")};
*error = [NSError errorWithDomain:JPXUIWebViewJSBridgeErrorDomain
code:JPXUIWebViewJSBridgeErrorCode
userInfo:errorUserInfo];
NSLog(@"error:can not find one url that matches your url pattern");
return;
}
NSString *handlerName = self.routines[matchIndex][1];
if (!handlerName) {
errorUserInfo = @{NSLocalizedDescriptionKey: NSLocalizedString(@"handler of match url pattern is nil!", @"")};
*error = [NSError errorWithDomain:JPXUIWebViewJSBridgeErrorDomain
code:JPXUIWebViewJSBridgeErrorCode
userInfo:errorUserInfo];
NSLog(@"error:pass nil handler!");
return;
}
NSString *queryString = [self getQueryStringInURL:url];
NSDictionary *parameters = [self dictionaryFromQueryString:queryString];
//selector signature should be: (void) methodName:(NSDictionary *)parameters
SEL selector = NSSelectorFromString([NSString stringWithFormat:@"%@:", handlerName]);
if (![self.handler respondsToSelector:selector]) {
NSString *e = [NSString stringWithFormat:@"method:%@ of handler:%@ not define!", handlerName, NSStringFromClass([self.handler class])];
errorUserInfo = @{NSLocalizedDescriptionKey: NSLocalizedString(e, @"")};
*error = [NSError errorWithDomain:JPXUIWebViewJSBridgeErrorDomain
code:JPXUIWebViewJSBridgeErrorCode
userInfo:errorUserInfo];
return;
}
//the following will cause this warning:performSelector may cause a leak because its selector is unknown, solve it with:http://stackoverflow.com/a/20058585/544251
//[self.handler performSelector:selector withObject:parameters];
IMP imp = [self.handler methodForSelector:selector];
void (*func)(id, SEL, NSDictionary *) = (void *)imp;
func(self.handler, selector, parameters);
}
@end