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

[iOS] WebView should handle custom URL scheme correctly #9037

Closed
eggli opened this issue Jul 27, 2016 · 12 comments
Closed

[iOS] WebView should handle custom URL scheme correctly #9037

eggli opened this issue Jul 27, 2016 · 12 comments
Labels
Platform: iOS iOS applications. Resolution: Locked This issue was locked by the bot.

Comments

@eggli
Copy link

eggli commented Jul 27, 2016

Hi, we're working on a small RN project which has an in-app browser embed inside, the product itself has been released on AppStore, but yet we have received some randomly error screen rendered in the WebView, after a long time investigation, we finally figured out it's the iOS deep linking URL scheme triggered the default WebView error render view, which can be easily reproduced via entering a SlideShare.net URL(not the mobile one), which redirects the WebView to it's own app, if user has no such app installed on their device, a WebKitErrorDomain will be throw from UIWebView hence triggers all the rest error handling mechanisms.

Here's the URL we are testing:

http://www.slideshare.net/branchmetrics/the-2016-mobile-growth-handbook-64218146

RNPlay to reproduce:
https://rnplay.org/apps/TxDHtw

RNPlay is still on 0.24, but this error can also be reproduced on RN 0.30.0

And here's the screenshot from XCode where the error has been thrown:

screen shot 2016-07-27 at 3 50 05 pm

As you can see, the error from UIWebView shows the NSErrorFailingURLKey as slideshare-app://ss/64093801 which is a custom URL scheme.

If we open the test link mentioned above in Safari.app without SlideShare app installed, Safari won't show any error message and working perfectly.

I've been searched the issues reported here, found these issue might be related to this error:
#6707, #7839, #4337, #7839.

Here's few thoughts to resolve this issue:

  1. WebView shouldn't trigger onLoadingError if the URL scheme itself is not supported, just like Safari.
  2. Currently, onLoadingError is going to render WebView's view state to error thus rendered the error view, default or not, it should allow developers to decide where to show error view or not via returning true/false after invoking onError method. In such case, the error event sent from RCTWebView to WebView should had the NSErrorFailingURLKey included, not only the url from UIWebView.
@lacker
Copy link
Contributor

lacker commented Oct 28, 2016

There is at least a workaround, from one of those other issues:

<WebView
  domStorageEnabled={ true }
  javaScriptEnabled={ true }
  renderError={ (e) => {
    if (e === 'WebKitErrorDomain') {
      return
    }
  }}
  source={{ uri: "https://99f9e623.ngrok.io/auth/sign_in_with_slack?source=app" }}
  style={ styles.container }
/>

The question which I don't know the answer to is whether this behavior is inherent to WebView and the right solution is switching to WKWebView (as some have suggested), or whether this can just be fixed in WebView.

@messutied
Copy link

@lacker that workaround does not solve this issue for me :( it only hides the error message but the webview turns blank when it happens.

I'm testing in react-native 0.36.1.

@alexkasemir
Copy link

yes @lacker, that workaround does not seem to work.

@jjshammas
Copy link

jjshammas commented Dec 27, 2016

Well an easy solution would be just to return NO for shouldStartLoadWithRequest if the protocol is not HTTP or HTTPS: https://github.com/facebook/react-native/blob/master/React/Views/RCTWebView.m#L251

Any idea what the repercussions might be if that were the case?

Alternatively, could add a property to WebView supporting an array of ignored protocols. For a quick and dirty solution until this is resolved I modified the above linked line as such to support Plaid Link:

if (!isJSNavigation) {
	BOOL isPlaidNavigation = [request.URL.scheme isEqualToString:@"plaidlink"];
	return !isPlaidNavigation;
}
return YES;

There also seems to be a shouldStartLoadWithRequest prop on the WebView RN component, but it is undocumented and I am not sure if it works completely.

@indivisable
Copy link

@jjshammas Do you have working example for your RCTWebView? I am trying to get it to work with Plaid Link too with not much luck :/

@firetheworld
Copy link

firetheworld commented May 20, 2017

I'm on RN version 0.43,I have this problem too
Have you fixed this problem, please help?
@lacker @eggli

@eggli
Copy link
Author

eggli commented May 22, 2017

@firetheworld Yes, we did solve this problem by doing it in a super brutal and not-very-open-source-way: We wrote our own iOS WebView to replace React Native's built in since no one in Facebook cares about this problem and we found it's not easy to solve, here's our solution, it's brutal, not very cool, but it works:

- (BOOL)webView:(__unused UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request
 navigationType:(UIWebViewNavigationType)navigationType
{
 
  if (![request.URL.scheme isEqual:@"http"] && 
      ![request.URL.scheme isEqual:@"https"] && 
      ![request.URL.scheme isEqual:@"about:blank"]) {
         if ([[UIApplication sharedApplication]canOpenURL:request.URL]) {
             [[UIApplication sharedApplication]openURL:request.URL];
         }
      return NO;
  }

return YES;

}

In the code above, if we found the URL is not whatever we can handle, we skip it to avoid any error message being throw to React Native, and asks iOS if user's device is capable to handle that custom scheme url, if so, we hand over the URL to iOS so user still get other apps' deep linking URL working.

I believe there SHOULD be a better way ( or at least a neat one ) to handle this.

@hramos
Copy link
Contributor

hramos commented Jul 26, 2017

Hi there! This issue is being closed because it has been inactive for a while. Maybe the issue has been fixed in a recent release, or perhaps it is not affecting a lot of people. Either way, we're automatically closing issues after a period of inactivity. Please do not take it personally!

If you think this issue should definitely remain open, please let us know. The following information is helpful when it comes to determining if the issue should be re-opened:

  • Does the issue still reproduce on the latest release candidate? Post a comment with the version you tested.
  • If so, is there any information missing from the bug report? Post a comment with all the information required by the issue template.
  • Is there a pull request that addresses this issue? Post a comment with the PR number so we can follow up.

If you would like to work on a patch to fix the issue, contributions are very welcome! Read through the contribution guide, and feel free to hop into #react-native if you need help planning your contribution.

@hramos hramos added the Icebox label Jul 26, 2017
@hramos hramos closed this as completed Jul 26, 2017
@zsaraf
Copy link

zsaraf commented Nov 8, 2017

Any update on whether this will be fixed in a future release? Still having the exact same issue

@messutied
Copy link

This was indeed never fixed for me.

@Silon
Copy link

Silon commented Nov 9, 2017

This bug still occur in RN 0.49.3...

I fixed it when I've add quotation marks to boolean argument. E.g:
{uri: 'https://cdn.plaid.com/link/v2/stable/link.html?isWebview="true"&key=[...]'}

@zhiming137
Copy link

一个不好的处理方式:
renderError={ (e) => {
this.webview.setState({viewState: 'IDLE'});
});

@facebook facebook locked as resolved and limited conversation to collaborators Jul 26, 2018
@react-native-bot react-native-bot added the Resolution: Locked This issue was locked by the bot. label Jul 26, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Platform: iOS iOS applications. Resolution: Locked This issue was locked by the bot.
Projects
None yet
Development

No branches or pull requests