Permalink
Browse files

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
  • Loading branch information...
RSNara authored and kelset committed Aug 16, 2018
1 parent d0b5a38 commit 0fa5bd8b9bbda59cfa56b177840899d00ff8494a
Showing with 65 additions and 1 deletion.
  1. +5 −0 React/Views/RCTWKWebView.h
  2. +15 −0 React/Views/RCTWKWebView.m
  3. +45 −1 React/Views/RCTWKWebViewManager.m
@@ -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
View
@@ -9,6 +9,7 @@ @interface RCTWKWebView () <WKUIDelegate, WKNavigationDelegate, WKScriptMessageH
@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 @@ - (void) webView:(WKWebView *)webView
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 @@ - (UIView *)view
}];
}
#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

0 comments on commit 0fa5bd8

Please sign in to comment.