Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce onCanGoBackChange & onCanGoForwardChange #210

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions WKWebView.ios.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ class WKWebView extends React.Component {
* Report the progress
*/
onProgress: PropTypes.func,
onCanGoBackChange: PropTypes.func,
onCanGoForwardChange: PropTypes.func,
/**
* A function that is invoked when the webview calls `window.postMessage`.
* Setting this property will inject a `postMessage` global into your
Expand Down Expand Up @@ -362,6 +364,8 @@ class WKWebView extends React.Component {
onLoadingError={this._onLoadingError}
messagingEnabled={messagingEnabled}
onProgress={this._onProgress}
onCanGoBackChange={this._onCanGoBackChange}
onCanGoForwardChange={this._onCanGoForwardChange}
onMessage={this._onMessage}
onScroll={this._onScroll}
onShouldStartLoadWithRequest={onShouldStartLoadWithRequest}
Expand Down Expand Up @@ -511,6 +515,16 @@ class WKWebView extends React.Component {
onProgress && onProgress(event.nativeEvent.progress);
};

_onCanGoBackChange = (event: Event) => {
const onCanGoBackChange = this.props.onCanGoBackChange;
onCanGoBackChange && onCanGoBackChange(event.nativeEvent.canGoBack);
}

_onCanGoForwardChange = (event: Event) => {
const onCanGoForwardChange = this.props.onCanGoForwardChange;
onCanGoForwardChange && onCanGoForwardChange(event.nativeEvent.canGoForward);
}

_onMessage = (event: Event) => {
var { onMessage } = this.props;
onMessage && onMessage(event);
Expand Down
74 changes: 46 additions & 28 deletions ios/RCTWKWebView/CRAWKWebView.m
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ @interface CRAWKWebView () <WKNavigationDelegate, RCTAutoInsetsProtocol, WKScrip
@property (nonatomic, copy) RCTDirectEventBlock onMessage;
@property (nonatomic, copy) RCTDirectEventBlock onScroll;
@property (nonatomic, copy) RCTDirectEventBlock onNavigationResponse;
@property (nonatomic, copy) RCTDirectEventBlock onCanGoBackChange;
@property (nonatomic, copy) RCTDirectEventBlock onCanGoForwardChange;
@property (assign) BOOL sendCookies;
@property (nonatomic, strong) WKUserScript *atStartScript;
@property (nonatomic, strong) WKUserScript *atEndScript;
Expand Down Expand Up @@ -63,18 +65,18 @@ - (instancetype)initWithProcessPool:(WKProcessPool *)processPool
super.backgroundColor = [UIColor clearColor];
_automaticallyAdjustContentInsets = YES;
_contentInset = UIEdgeInsetsZero;

WKWebViewConfiguration* config = [[WKWebViewConfiguration alloc] init];
config.processPool = processPool;
WKUserContentController* userController = [[WKUserContentController alloc]init];
[userController addScriptMessageHandler:[[WeakScriptMessageDelegate alloc] initWithDelegate:self] name:@"reactNative"];
config.userContentController = userController;

_webView = [[WKWebView alloc] initWithFrame:self.bounds configuration:config];
_webView.UIDelegate = self;
_webView.navigationDelegate = self;
_webView.scrollView.delegate = self;

#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */
// `contentInsetAdjustmentBehavior` is only available since iOS 11.
// We set the default behavior to "never" so that iOS
Expand All @@ -86,6 +88,8 @@ - (instancetype)initWithProcessPool:(WKProcessPool *)processPool
#endif
[self setupPostMessageScript];
[_webView addObserver:self forKeyPath:@"estimatedProgress" options:NSKeyValueObservingOptionNew context:nil];
[_webView addObserver:self forKeyPath:@"canGoBack" options:NSKeyValueObservingOptionNew context:nil];
[_webView addObserver:self forKeyPath:@"canGoForward" options:NSKeyValueObservingOptionNew context:nil];
[self addSubview:_webView];
}
return self;
Expand Down Expand Up @@ -163,7 +167,7 @@ - (void)loadRequest:(NSURLRequest *)request
request = mutableRequest;
}
}

[_webView loadRequest:request];
}

Expand All @@ -179,29 +183,29 @@ -(void)setHideKeyboardAccessoryView:(BOOL)hideKeyboardAccessoryView
if (!hideKeyboardAccessoryView) {
return;
}

UIView* subview;
for (UIView* view in _webView.scrollView.subviews) {
if([[view.class description] hasPrefix:@"WKContent"])
subview = view;
}

if(subview == nil) return;

NSString* name = [NSString stringWithFormat:@"%@_SwizzleHelperWK", subview.class.superclass];
Class newClass = NSClassFromString(name);

if(newClass == nil)
{
newClass = objc_allocateClassPair(subview.class, [name cStringUsingEncoding:NSASCIIStringEncoding], 0);
if(!newClass) return;

Method method = class_getInstanceMethod([_SwizzleHelperWK class], @selector(inputAccessoryView));
class_addMethod(newClass, @selector(inputAccessoryView), method_getImplementation(method), method_getTypeEncoding(method));

objc_registerClassPair(newClass);
}

object_setClass(subview, newClass);
}

Expand All @@ -212,7 +216,7 @@ -(void)setKeyboardDisplayRequiresUserAction:(BOOL)keyboardDisplayRequiresUserAct
if (!keyboardDisplayRequiresUserAction) {
Class class = NSClassFromString(@"WKContentView");
NSOperatingSystemVersion iOS_11_3_0 = (NSOperatingSystemVersion){11, 3, 0};

if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion: iOS_11_3_0]) {
SEL selector = sel_getUid("_startAssistingNode:userIsInteracting:blurPreviousNode:changingActivityState:userObject:");
Method method = class_getInstanceMethod(class, selector);
Expand Down Expand Up @@ -314,20 +318,20 @@ - (void)setSource:(NSDictionary *)source
if ([source[@"customUserAgent"] length] != 0 && [_webView respondsToSelector:@selector(setCustomUserAgent:)]) {
[_webView setCustomUserAgent:source[@"customUserAgent"]];
}

// Allow loading local files:
// <WKWebView source={{ file: RNFS.MainBundlePath + '/data/index.html', allowingReadAccessToURL: RNFS.MainBundlePath }} />
// Only works for iOS 9+. So iOS 8 will simply ignore those two values
NSString *file = [RCTConvert NSString:source[@"file"]];
NSString *allowingReadAccessToURL = [RCTConvert NSString:source[@"allowingReadAccessToURL"]];

if (file && [_webView respondsToSelector:@selector(loadFileURL:allowingReadAccessToURL:)]) {
NSURL *fileURL = [RCTConvert NSURL:file];
NSURL *baseURL = [RCTConvert NSURL:allowingReadAccessToURL];
[_webView loadFileURL:fileURL allowingReadAccessToURL:baseURL];
return;
}

// Check for a static html source first
NSString *html = [RCTConvert NSString:source[@"html"]];
if (html) {
Expand All @@ -338,7 +342,7 @@ - (void)setSource:(NSDictionary *)source
[_webView loadHTMLString:html baseURL:baseURL];
return;
}

NSURLRequest *request = [RCTConvert NSURLRequest:source];
// Because of the way React works, as pages redirect, we actually end up
// passing the redirect urls back here, so we ignore them if trying to load
Expand Down Expand Up @@ -391,7 +395,7 @@ - (UIColor *)backgroundColor
@"canGoBack": @(_webView.canGoBack),
@"canGoForward" : @(_webView.canGoForward),
}];

return event;
}

Expand All @@ -413,6 +417,20 @@ - (void)observeValueForKeyPath:(NSString *)keyPath
}
_onProgress(@{@"progress": [change objectForKey:NSKeyValueChangeNewKey]});
}

if ([keyPath isEqualToString:@"canGoBack"]) {
if (!_onCanGoBackChange) {
return;
}
_onCanGoBackChange(@{@"canGoBack": [change objectForKey:NSKeyValueChangeNewKey]});
}

if ([keyPath isEqualToString:@"canGoForward"]) {
if (!_onCanGoForwardChange) {
return;
}
_onCanGoForwardChange(@{@"canGoForward": [change objectForKey:NSKeyValueChangeNewKey]});
}
}

- (void)dealloc
Expand Down Expand Up @@ -468,9 +486,9 @@ - (void)webView:(__unused WKWebView *)webView decidePolicyForNavigationAction:(W
NSURLRequest *request = navigationAction.request;
NSURL* url = request.URL;
NSString* scheme = url.scheme;

BOOL isJSNavigation = [scheme isEqualToString:RCTJSNavigationScheme];

// handle mailto and tel schemes
if ([scheme isEqualToString:@"mailto"] || [scheme isEqualToString:@"tel"]) {
if ([app canOpenURL:url]) {
Expand All @@ -479,7 +497,7 @@ - (void)webView:(__unused WKWebView *)webView decidePolicyForNavigationAction:(W
return;
}
}

// skip this for the JS Navigation handler
if (!isJSNavigation && _onShouldStartLoadWithRequest) {
NSMutableDictionary<NSString *, id> *event = [self baseEvent];
Expand All @@ -493,7 +511,7 @@ - (void)webView:(__unused WKWebView *)webView decidePolicyForNavigationAction:(W
return decisionHandler(WKNavigationActionPolicyCancel);
}
}

if (_onLoadingStart) {
// We have this check to filter out iframe requests and whatnot
BOOL isTopFrame = [url isEqual:request.mainDocumentURL];
Expand All @@ -506,7 +524,7 @@ - (void)webView:(__unused WKWebView *)webView decidePolicyForNavigationAction:(W
_onLoadingStart(event);
}
}

if (isJSNavigation) {
decisionHandler(WKNavigationActionPolicyCancel);
}
Expand All @@ -525,7 +543,7 @@ - (void)webView:(__unused WKWebView *)webView didFailProvisionalNavigation:(__un
// http://stackoverflow.com/questions/1024748/how-do-i-fix-nsurlerrordomain-error-999-in-iphone-3-0-os
return;
}

NSMutableDictionary<NSString *, id> *event = [self baseEvent];
[event addEntriesFromDictionary:@{
@"domain": error.domain,
Expand All @@ -548,7 +566,7 @@ - (void)webView:(WKWebView *)webView didFinishNavigation:(__unused WKNavigation

- (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler {
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:message message:nil preferredStyle:UIAlertControllerStyleAlert];

[alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Close", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
completionHandler();
}]];
Expand All @@ -557,7 +575,7 @@ - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSStrin
}

- (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler {

// TODO We have to think message to confirm "YES"
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:message message:nil preferredStyle:UIAlertControllerStyleAlert];
[alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
Expand All @@ -571,17 +589,17 @@ - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSStr
}

- (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString *))completionHandler {

UIAlertController *alertController = [UIAlertController alertControllerWithTitle:prompt message:nil preferredStyle:UIAlertControllerStyleAlert];
[alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) {
textField.text = defaultText;
}];

[alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) {
NSString *input = ((UITextField *)alertController.textFields.firstObject).text;
completionHandler(input);
}]];

[alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", nil) style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) {
completionHandler(nil);
}]];
Expand Down
2 changes: 2 additions & 0 deletions ios/RCTWKWebView/CRAWKWebViewManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ - (UIView *)view
RCT_EXPORT_VIEW_PROPERTY(onLoadingError, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onShouldStartLoadWithRequest, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onProgress, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onCanGoBackChange, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onCanGoForwardChange, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onMessage, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onScroll, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(hideKeyboardAccessoryView, BOOL)
Expand Down