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
This commit is contained in:
parent
1584108805
commit
a997c0ac16
|
@ -12,6 +12,11 @@
|
|||
@class RCTWKWebView;
|
||||
|
||||
@protocol RCTWKWebViewDelegate <NSObject>
|
||||
|
||||
- (BOOL)webView:(RCTWKWebView *)webView
|
||||
shouldStartLoadForRequest:(NSMutableDictionary<NSString *, id> *)request
|
||||
withCallback:(RCTDirectEventBlock)callback;
|
||||
|
||||
@end
|
||||
|
||||
@interface RCTWKWebView : RCTView
|
||||
|
|
|
@ -9,6 +9,7 @@ static NSString *const MessageHanderName = @"ReactNative";
|
|||
@property (nonatomic, copy) RCTDirectEventBlock onLoadingStart;
|
||||
@property (nonatomic, copy) RCTDirectEventBlock onLoadingFinish;
|
||||
@property (nonatomic, copy) RCTDirectEventBlock onLoadingError;
|
||||
@property (nonatomic, copy) RCTDirectEventBlock onShouldStartLoadWithRequest;
|
||||
@property (nonatomic, copy) RCTDirectEventBlock onMessage;
|
||||
@property (nonatomic, copy) WKWebView *webView;
|
||||
@end
|
||||
|
@ -154,6 +155,20 @@ static NSString *const MessageHanderName = @"ReactNative";
|
|||
WKNavigationType navigationType = navigationAction.navigationType;
|
||||
NSURLRequest *request = navigationAction.request;
|
||||
|
||||
if (_onShouldStartLoadWithRequest) {
|
||||
NSMutableDictionary<NSString *, id> *event = [self baseEvent];
|
||||
[event addEntriesFromDictionary: @{
|
||||
@"url": (request.URL).absoluteString,
|
||||
@"navigationType": navigationTypes[@(navigationType)]
|
||||
}];
|
||||
if (![self.delegate webView:self
|
||||
shouldStartLoadForRequest:event
|
||||
withCallback:_onShouldStartLoadWithRequest]) {
|
||||
decisionHandler(WKNavigationResponsePolicyCancel);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (_onLoadingStart) {
|
||||
// We have this check to filter out iframe requests and whatnot
|
||||
BOOL isTopFrame = [request.URL isEqual:request.mainDocumentURL];
|
||||
|
|
|
@ -3,19 +3,29 @@
|
|||
#import "RCTUIManager.h"
|
||||
#import "RCTWKWebView.h"
|
||||
|
||||
@interface RCTWKWebViewManager () <RCTWKWebViewDelegate>
|
||||
@end
|
||||
|
||||
@implementation RCTWKWebViewManager
|
||||
{
|
||||
NSConditionLock *_shouldStartLoadLock;
|
||||
BOOL _shouldStartLoad;
|
||||
}
|
||||
|
||||
RCT_EXPORT_MODULE()
|
||||
|
||||
- (UIView *)view
|
||||
{
|
||||
return [RCTWKWebView new];
|
||||
RCTWKWebView *webView = [RCTWKWebView new];
|
||||
webView.delegate = self;
|
||||
return webView;
|
||||
}
|
||||
|
||||
RCT_EXPORT_VIEW_PROPERTY(source, NSDictionary)
|
||||
RCT_EXPORT_VIEW_PROPERTY(onLoadingStart, RCTDirectEventBlock)
|
||||
RCT_EXPORT_VIEW_PROPERTY(onLoadingFinish, RCTDirectEventBlock)
|
||||
RCT_EXPORT_VIEW_PROPERTY(onLoadingError, RCTDirectEventBlock)
|
||||
RCT_EXPORT_VIEW_PROPERTY(onShouldStartLoadWithRequest, RCTDirectEventBlock)
|
||||
RCT_EXPORT_VIEW_PROPERTY(injectedJavaScript, NSString)
|
||||
|
||||
/**
|
||||
|
@ -105,4 +115,38 @@ RCT_EXPORT_METHOD(stopLoading:(nonnull NSNumber *)reactTag)
|
|||
}];
|
||||
}
|
||||
|
||||
#pragma mark - Exported synchronous methods
|
||||
|
||||
- (BOOL) webView:(RCTWKWebView *)webView
|
||||
shouldStartLoadForRequest:(NSMutableDictionary<NSString *, id> *)request
|
||||
withCallback:(RCTDirectEventBlock)callback
|
||||
{
|
||||
_shouldStartLoadLock = [[NSConditionLock alloc] initWithCondition:arc4random()];
|
||||
_shouldStartLoad = YES;
|
||||
request[@"lockIdentifier"] = @(_shouldStartLoadLock.condition);
|
||||
callback(request);
|
||||
|
||||
// Block the main thread for a maximum of 250ms until the JS thread returns
|
||||
if ([_shouldStartLoadLock lockWhenCondition:0 beforeDate:[NSDate dateWithTimeIntervalSinceNow:.25]]) {
|
||||
BOOL returnValue = _shouldStartLoad;
|
||||
[_shouldStartLoadLock unlock];
|
||||
_shouldStartLoadLock = nil;
|
||||
return returnValue;
|
||||
} else {
|
||||
RCTLogWarn(@"Did not receive response to shouldStartLoad in time, defaulting to YES");
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(startLoadWithResult:(BOOL)result lockIdentifier:(NSInteger)lockIdentifier)
|
||||
{
|
||||
if ([_shouldStartLoadLock tryLockWhenCondition:lockIdentifier]) {
|
||||
_shouldStartLoad = result;
|
||||
[_shouldStartLoadLock unlockWithCondition:0];
|
||||
} else {
|
||||
RCTLogWarn(@"startLoadWithResult invoked with invalid lockIdentifier: "
|
||||
"got %lld, expected %lld", (long long)lockIdentifier, (long long)_shouldStartLoadLock.condition);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
Loading…
Reference in New Issue