Skip to content

Commit a997c0a

Browse files
RSNarafacebook-github-bot
authored andcommitted
Implement 'onShouldStartLoadWithRequest' prop
Summary: @public This diff introduces the native backend for a new WKWebView prop: `onShouldStartLoadWithRequest`. In the final component, the behaviour will be as follows: Whenever the user navigates around in the web view, we call `onShouldStartLoadWithRequest` with the navigation event. If `onShouldStartLoadWithRequest` returns `true`, we continue the navigation. Otherwise, we abort it. Reviewed By: shergin Differential Revision: D6370317 fbshipit-source-id: e3cdd7e2a755125aebdb6df67e7b39116228bdfb
1 parent 1584108 commit a997c0a

File tree

3 files changed

+65
-1
lines changed

3 files changed

+65
-1
lines changed

React/Views/RCTWKWebView.h

+5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212
@class RCTWKWebView;
1313

1414
@protocol RCTWKWebViewDelegate <NSObject>
15+
16+
- (BOOL)webView:(RCTWKWebView *)webView
17+
shouldStartLoadForRequest:(NSMutableDictionary<NSString *, id> *)request
18+
withCallback:(RCTDirectEventBlock)callback;
19+
1520
@end
1621

1722
@interface RCTWKWebView : RCTView

React/Views/RCTWKWebView.m

+15
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ @interface RCTWKWebView () <WKUIDelegate, WKNavigationDelegate, WKScriptMessageH
99
@property (nonatomic, copy) RCTDirectEventBlock onLoadingStart;
1010
@property (nonatomic, copy) RCTDirectEventBlock onLoadingFinish;
1111
@property (nonatomic, copy) RCTDirectEventBlock onLoadingError;
12+
@property (nonatomic, copy) RCTDirectEventBlock onShouldStartLoadWithRequest;
1213
@property (nonatomic, copy) RCTDirectEventBlock onMessage;
1314
@property (nonatomic, copy) WKWebView *webView;
1415
@end
@@ -154,6 +155,20 @@ - (void) webView:(WKWebView *)webView
154155
WKNavigationType navigationType = navigationAction.navigationType;
155156
NSURLRequest *request = navigationAction.request;
156157

158+
if (_onShouldStartLoadWithRequest) {
159+
NSMutableDictionary<NSString *, id> *event = [self baseEvent];
160+
[event addEntriesFromDictionary: @{
161+
@"url": (request.URL).absoluteString,
162+
@"navigationType": navigationTypes[@(navigationType)]
163+
}];
164+
if (![self.delegate webView:self
165+
shouldStartLoadForRequest:event
166+
withCallback:_onShouldStartLoadWithRequest]) {
167+
decisionHandler(WKNavigationResponsePolicyCancel);
168+
return;
169+
}
170+
}
171+
157172
if (_onLoadingStart) {
158173
// We have this check to filter out iframe requests and whatnot
159174
BOOL isTopFrame = [request.URL isEqual:request.mainDocumentURL];

React/Views/RCTWKWebViewManager.m

+45-1
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,29 @@
33
#import "RCTUIManager.h"
44
#import "RCTWKWebView.h"
55

6+
@interface RCTWKWebViewManager () <RCTWKWebViewDelegate>
7+
@end
8+
69
@implementation RCTWKWebViewManager
10+
{
11+
NSConditionLock *_shouldStartLoadLock;
12+
BOOL _shouldStartLoad;
13+
}
714

815
RCT_EXPORT_MODULE()
916

1017
- (UIView *)view
1118
{
12-
return [RCTWKWebView new];
19+
RCTWKWebView *webView = [RCTWKWebView new];
20+
webView.delegate = self;
21+
return webView;
1322
}
1423

1524
RCT_EXPORT_VIEW_PROPERTY(source, NSDictionary)
1625
RCT_EXPORT_VIEW_PROPERTY(onLoadingStart, RCTDirectEventBlock)
1726
RCT_EXPORT_VIEW_PROPERTY(onLoadingFinish, RCTDirectEventBlock)
1827
RCT_EXPORT_VIEW_PROPERTY(onLoadingError, RCTDirectEventBlock)
28+
RCT_EXPORT_VIEW_PROPERTY(onShouldStartLoadWithRequest, RCTDirectEventBlock)
1929
RCT_EXPORT_VIEW_PROPERTY(injectedJavaScript, NSString)
2030

2131
/**
@@ -105,4 +115,38 @@ - (UIView *)view
105115
}];
106116
}
107117

118+
#pragma mark - Exported synchronous methods
119+
120+
- (BOOL) webView:(RCTWKWebView *)webView
121+
shouldStartLoadForRequest:(NSMutableDictionary<NSString *, id> *)request
122+
withCallback:(RCTDirectEventBlock)callback
123+
{
124+
_shouldStartLoadLock = [[NSConditionLock alloc] initWithCondition:arc4random()];
125+
_shouldStartLoad = YES;
126+
request[@"lockIdentifier"] = @(_shouldStartLoadLock.condition);
127+
callback(request);
128+
129+
// Block the main thread for a maximum of 250ms until the JS thread returns
130+
if ([_shouldStartLoadLock lockWhenCondition:0 beforeDate:[NSDate dateWithTimeIntervalSinceNow:.25]]) {
131+
BOOL returnValue = _shouldStartLoad;
132+
[_shouldStartLoadLock unlock];
133+
_shouldStartLoadLock = nil;
134+
return returnValue;
135+
} else {
136+
RCTLogWarn(@"Did not receive response to shouldStartLoad in time, defaulting to YES");
137+
return YES;
138+
}
139+
}
140+
141+
RCT_EXPORT_METHOD(startLoadWithResult:(BOOL)result lockIdentifier:(NSInteger)lockIdentifier)
142+
{
143+
if ([_shouldStartLoadLock tryLockWhenCondition:lockIdentifier]) {
144+
_shouldStartLoad = result;
145+
[_shouldStartLoadLock unlockWithCondition:0];
146+
} else {
147+
RCTLogWarn(@"startLoadWithResult invoked with invalid lockIdentifier: "
148+
"got %lld, expected %lld", (long long)lockIdentifier, (long long)_shouldStartLoadLock.condition);
149+
}
150+
}
151+
108152
@end

0 commit comments

Comments
 (0)