6
6
7
7
#import " RCTAutoInsetsProtocol.h"
8
8
9
- @interface RCTWKWebView () <WKUIDelegate >
9
+ @interface RCTWKWebView () <WKUIDelegate , WKNavigationDelegate >
10
+ @property (nonatomic , copy ) RCTDirectEventBlock onLoadingStart;
11
+ @property (nonatomic , copy ) RCTDirectEventBlock onLoadingFinish;
12
+ @property (nonatomic , copy ) RCTDirectEventBlock onLoadingError;
13
+ @property (nonatomic , copy ) WKWebView *webView;
10
14
@end
11
15
12
16
@implementation RCTWKWebView
13
17
{
14
- WKWebView *_webView;
15
18
}
16
19
17
20
- (void )dealloc
@@ -25,6 +28,7 @@ - (instancetype)initWithFrame:(CGRect)frame
25
28
super.backgroundColor = [UIColor clearColor ];
26
29
_webView = [[WKWebView alloc ] initWithFrame: self .bounds];
27
30
_webView.UIDelegate = self;
31
+ _webView.navigationDelegate = self;
28
32
[self addSubview: _webView];
29
33
}
30
34
return self;
@@ -69,4 +73,119 @@ - (void)layoutSubviews
69
73
_webView.frame = self.bounds ;
70
74
}
71
75
76
+ - (NSMutableDictionary <NSString *, id> *)baseEvent
77
+ {
78
+ NSDictionary *event = @{
79
+ @" url" : _webView.URL .absoluteString ?: @" " ,
80
+ @" title" : _webView.title ,
81
+ @" loading" : @(_webView.loading ),
82
+ @" canGoBack" : @(_webView.canGoBack ),
83
+ @" canGoForward" : @(_webView.canGoForward )
84
+ };
85
+ return [[NSMutableDictionary alloc ] initWithDictionary: event];
86
+ }
87
+
88
+ #pragma mark - WKNavigationDelegate methods
89
+
90
+ /* *
91
+ * Decides whether to allow or cancel a navigation.
92
+ * @see https://fburl.com/42r9fxob
93
+ */
94
+ - (void ) webView : (WKWebView *)webView
95
+ decidePolicyForNavigationAction : (WKNavigationAction *)navigationAction
96
+ decisionHandler : (void (^)(WKNavigationActionPolicy ))decisionHandler
97
+ {
98
+ static NSDictionary <NSNumber *, NSString *> *navigationTypes;
99
+ static dispatch_once_t onceToken;
100
+
101
+ dispatch_once (&onceToken, ^{
102
+ navigationTypes = @{
103
+ @(WKNavigationTypeLinkActivated ): @" click" ,
104
+ @(WKNavigationTypeFormSubmitted ): @" formsubmit" ,
105
+ @(WKNavigationTypeBackForward ): @" backforward" ,
106
+ @(WKNavigationTypeReload ): @" reload" ,
107
+ @(WKNavigationTypeFormResubmitted ): @" formresubmit" ,
108
+ @(WKNavigationTypeOther ): @" other" ,
109
+ };
110
+ });
111
+
112
+ WKNavigationType navigationType = navigationAction.navigationType ;
113
+ NSURLRequest *request = navigationAction.request ;
114
+
115
+ if (_onLoadingStart) {
116
+ // We have this check to filter out iframe requests and whatnot
117
+ BOOL isTopFrame = [request.URL isEqual: request.mainDocumentURL];
118
+ if (isTopFrame) {
119
+ NSMutableDictionary <NSString *, id > *event = [self baseEvent ];
120
+ [event addEntriesFromDictionary: @{
121
+ @" url" : (request.URL ).absoluteString ,
122
+ @" navigationType" : navigationTypes[@(navigationType)]
123
+ }];
124
+ _onLoadingStart (event);
125
+ }
126
+ }
127
+
128
+ // Allow all navigation by default
129
+ decisionHandler (WKNavigationResponsePolicyAllow );
130
+ }
131
+
132
+ /* *
133
+ * Called when an error occurs while the web view is loading content.
134
+ * @see https://fburl.com/km6vqenw
135
+ */
136
+ - (void ) webView : (WKWebView *)webView
137
+ didFailProvisionalNavigation : (WKNavigation *)navigation
138
+ withError : (NSError *)error
139
+ {
140
+ if (_onLoadingError) {
141
+ if ([error.domain isEqualToString: NSURLErrorDomain ] && error.code == NSURLErrorCancelled) {
142
+ // NSURLErrorCancelled is reported when a page has a redirect OR if you load
143
+ // a new URL in the WebView before the previous one came back. We can just
144
+ // ignore these since they aren't real errors.
145
+ // http://stackoverflow.com/questions/1024748/how-do-i-fix-nsurlerrordomain-error-999-in-iphone-3-0-os
146
+ return ;
147
+ }
148
+
149
+ NSMutableDictionary <NSString *, id > *event = [self baseEvent ];
150
+ [event addEntriesFromDictionary: @{
151
+ @" didFailProvisionalNavigation" : @YES ,
152
+ @" domain" : error.domain ,
153
+ @" code" : @(error.code ),
154
+ @" description" : error.localizedDescription ,
155
+ }];
156
+ _onLoadingError (event);
157
+ }
158
+ }
159
+
160
+ - (void )evaluateJS : (NSString *)js
161
+ thenCall : (void (^)(NSString *)) callback
162
+ {
163
+ [self .webView evaluateJavaScript: js completionHandler: ^(id result, NSError *error) {
164
+ if (error == nil ) {
165
+ callback ([NSString stringWithFormat: @" %@ " , result]);
166
+ }
167
+ }];
168
+ }
169
+
170
+
171
+ /* *
172
+ * Called when the navigation is complete.
173
+ * @see https://fburl.com/rtys6jlb
174
+ */
175
+ - (void ) webView : (WKWebView *)webView
176
+ didFinishNavigation : (WKNavigation *)navigation
177
+ {
178
+ if (_injectedJavaScript) {
179
+ [self evaluateJS: _injectedJavaScript thenCall: ^(NSString *jsEvaluationValue) {
180
+ NSMutableDictionary *event = [self baseEvent ];
181
+ event[@" jsEvaluationValue" ] = jsEvaluationValue;
182
+ if (self.onLoadingFinish ) {
183
+ self.onLoadingFinish (event);
184
+ }
185
+ }];
186
+ } else if (_onLoadingFinish) {
187
+ _onLoadingFinish ([self baseEvent ]);
188
+ }
189
+ }
190
+
72
191
@end
0 commit comments