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

onShouldStartLoadWithRequest not working consistently across different platforms #381

Closed
c1ngular opened this issue Mar 4, 2019 · 22 comments
Labels

Comments

@c1ngular
Copy link

c1ngular commented Mar 4, 2019

"react": "16.6.3", "react-native": "0.58.5", "react-native-webview": "^5.2.1"

on iOS : onShouldStartLoadWithRequest event fires 3 TIMEs with 3 different URLs
on Android: onShouldStartLoadWithRequest event fires 1 TIME with 1 URL

async requests/iframe ignored on android ?

UPDATE:
i did a little research , found this https://stackoverflow.com/questions/26651586/difference-between-shouldoverrideurlloading-and-shouldinterceptrequest/26652169
may be we should use shouldInterceptRequest method instead of shouldOverrideUrlLoading on Android , since it captures all request(css/script/iframe/ajax...), make it more consistent with iOS behavior ?

@Titozzz
Copy link
Collaborator

Titozzz commented Mar 5, 2019

Feel free to submit a PR cc @maxammann

@c1ngular
Copy link
Author

c1ngular commented Mar 5, 2019

@Titozzz willingly , i tried couple of times, but i could not make it work , i walked thought this repo and followed the implementation of shouldOverrideUrlLoading ,no avail. for most of the steps , i was justing shooting in the dark , i have zero experience of mobile development . sorry~

@punksta
Copy link
Contributor

punksta commented Mar 6, 2019

Ios and android methods don't work in a same way. Ios methods are asynchronous, android are synchronous. So I believe that shouldInterceptRequest can't be used until we get sync calls from java to js in react-native core. It can be used with white lists only(without async calls to js). Maybe that can help.

Unfortunately that's not only bad news. shouldOverrideUrlLoading and other webview methods may not be even called on some devices or in some cases or due to bad implementation by manufacturers.
https://stackoverflow.com/questions/6738328/shouldoverrideurlloading-in-webview-for-android-not-running/6739042
https://stackoverflow.com/questions/41600497/android-webview-shouldoverrideurlloading-not-working-with-https
https://stackoverflow.com/questions/9940354/android-webview-shouldoverrideurlloading-is-not-called
etc...
mobile development is full of surprises =)

@c1ngular
Copy link
Author

c1ngular commented Mar 7, 2019

@punksta thanks, i added the shouldInterceptRequest to Android side, and was able to intercept and dispatch the event to React side on my emulator(Pixel_API_23), but i found it's quiet different from shouldOverrideUrlLoading , it intercepts every request(css/js/font/....),so there will be a lot frequent data communication between the Native side and React Side .

does it raise performance concern ?
what is the best way for the the shouldInterceptRequest to wait for result from React side ?

i see that current shouldOverrideUrlLoading implementation is just reject loading and handle the request url to React side , calling loadUrl method when TRUE return from React Side.

i found ServiceWorkerClient seems relevant , but it is overwhelming to me , and it says "added in API level 24" .

@jamonholmgren jamonholmgren added Help wanted Extra attention is needed android labels Mar 7, 2019
@maxammann
Copy link
Contributor

shouldOverrideUrlLoading and shouldInterceptRequest are doing different things which should be handled in react-native. shouldInterceptRequest is working on individual http requests which is currently not implemented in react-native.

shouldOverrideUrlLoading kind of handles "clicks". The behaviour of onShouldStartLoadWithRequest is inconsitent during the loading of the webview. I'm currently using this to work around this issue:

  onShouldStartLoadWithRequest = (event: WebViewNavigation) => {
    const url = event.url
    // Needed on iOS for the initial load
    if (url === URL_PREFIX + OFFLINE_CACHE_PATH) {
      return true
    }

    this.onLinkPress(url)

    return false
  }

(I'm feeding html directly to the webview, therefore I'm using URL_PREFIX + OFFLINE_CACHE_PATH here)

I don't have time currently to make the calling consistent but this should be tackled some day 📦
I'm also a fan of simplifying this: #192

This is just way to confusing to know what is happening behind the scenes.

@c1ngular
Copy link
Author

@maxammann I am using shouldInterceptRequest method to filter specific request on Android now, cuz my use case does not really need to intercept any request, just need to inform the react side which request is being made , the current shouldOverrideUrlLoading method on Android is not able to capture iframe(verified) and Ajax request .

I do hope shouldInterceptRequest method could be implemented somehow ,but I am not experienced of Native mobile development, so it is beyond my reach due to what I found from my previous comments .

@ericlathrop
Copy link

I'm having a problem with onShouldStartLoadWithRequest acting differently on iOS vs Android.

I'm using source={{html: myHtml}} to inject my HTML and then onShouldStartLoadWithRequest to open any links the user clicks on in an external browser like this:

function onShouldStartLoadWithRequest(request) {
  Linking.openURL(request.url)
    .catch(err => console.error(`Could not open URL ${request.url}`, err));
  return false;
}

My problem is that on iOS this function gets called for embedded Youtube videos, which I believe are iframes. On Android, this function is only called when the user taps on something.

I'd prefer onShouldStartLoadWithRequest to act like Android's version on iOS. If that's not possible I'd like some way to distinguish URLs opened from embedded content from URLs opened from user clicks.

@kulbhushan-ucreate
Copy link

kulbhushan-ucreate commented Aug 8, 2019

Hey folks,
I am also stuck in this is an issue from webview and finally am fix this issue by getting a fork from react-native-community/react-native-webview by doing some android native code.
You guys check out my git package.

https://github.com/kulbhushan-ucreate/react-native-web-view.

@gfpacheco
Copy link

@ericlathrop I want the same thing, did you manage to make it work? I only want to intercept what would be changes to the window.href, not all the background requests

@ericlathrop
Copy link

@gfpacheco I ended up writing a blacklist of URL prefixes to ignore. Far from ideal. At least I stored the blacklist in Firebase so I can update it without having to push a new version of my app.

@github-actions
Copy link

Hello 👋, this issue has been opened for more than 2 months with no activity on it. If the issue is still here, please keep in mind that we need community support and help to fix it! Just comment something like still searching for solutions and if you found one, please open a pull request! You have 7 days until this gets closed automatically

@github-actions github-actions bot added the Stale label Nov 14, 2019
@punksta
Copy link
Contributor

punksta commented Nov 14, 2019

cat

@ldco2016
Copy link

ldco2016 commented Dec 26, 2019

@ericlathrop , were you able to solve it? Could you assist me?

I have this implementation:

<WebViewAutoHeight
                key={s.Body.substr(10)}
                source={{
                  //prettier-ignore
                  html: `<body style="font-family: -apple-system, Roboto, sans-serif; background-color: ${lightTheme.grey2} !important; color: ${v2Colors.charcoalDarkest}; font-size: ${moderateScale(14, 0.2)}px;">${s.Body}</body>`
                }}
                // onShouldStartLoadWithRequest={request => {
                //   if (Platform.OS === "android") {
                //     const url = request.url;
                //     console.log(request);
                //     if (url !== uri) {
                //       Linking.openURL(url);
                //     }
                //     // return false;
                //   }
                // }}
                onNavigationStateChange={event => {
                  if (Platform.OS === "ios") {
                    if (event.url !== uri) {
                      Linking.openURL(event.url);
                    }
                  }
                }}
              />

So onShouldStartLoadWithRequest works for Android and onNavigationStateChange works for iOS, but even if I add an if conditional checking for Platform.OS they are still somehow interacting in a way that its causing problem on iOS where the webview does not completely load up. I tried placing wrapping the properties and their respective logic inside a big if/else and even an ternary but I kept getting syntax errors.

@2xSamurai
Copy link

@ldco2016 I am having the same issue. Were you able to solve in anyways? Can Someone please help.

@ericlathrop
Copy link

@ldco2016 @2xSamurai Here's my workaround for this issue:

const webViewAllowedEmbeddingUrlPrefixes = [
  "https://m.facebook.com/plugins/video.php",
  "https://platform.twitter.com/jot.html",
  "https://syndication.twitter.com/i/jot",
  "https://www.facebook.com/plugins/video.php",
  "https://www.scribd.com/embeds/",
  "https://www.youtube.com/embed/",
];
const webViewAllowedEmbeddingUrlRegexes = [
  "https://www.iheart.com/podcast/.*\\?embed=true"
];
const webViewRestrictedEmbeddingUrlPrefixes = [
  "https://accounts.google.com/o/oauth2/iframe",
  "https://clearchannel.demdex.net/",
  "https://staticxx.facebook.com/connect/",
  "https://synchroscript.deliveryengine.adswizz.com/",
  "https://www.facebook.com/connect/",
];
function onShouldStartLoadWithRequest(request) {
  if (request.url === "about:blank") {
    return true;
  }

  // HACK: allow some urls to be embedded, and reject others
  // https://github.com/react-native-community/react-native-webview/issues/381
  if (Platform.OS === 'ios') {
    if (webViewAllowedEmbeddingUrlPrefixes.some(prefix => request.url.indexOf(prefix) === 0)) {
      return true;
    }
    if (webViewAllowedEmbeddingUrlRegexes.map(r => new RegExp(r)).some(regexp => request.url.match(regexp) !== null)) {
      return true;
    }
    if (webViewRestrictedEmbeddingUrlPrefixes.some(prefix => request.url.indexOf(prefix) === 0)) {
      return false;
    }
  }

  Linking.openURL(request.url)
    .catch(err => console.error(`Could not open URL ${request.url}`, err));
  return false;
}

@webdevbyjoss
Copy link

Have the same issue with the Youtube iframe player being catched with onShouldStartLoadWithRequest() on iOS
Are there alternative ways to resolve this?

@anzorb
Copy link

anzorb commented Jan 5, 2022

@c1ngular

Can I ask, how did you expose shouldInterceptRequest to the React Native side? Did you fork the webview, or is there another way. Thanks in advance!

@vk562398
Copy link

Any solution

@vk562398
Copy link

Any solution to intercept internal api calls

@kvlknctk
Copy link

+1

@cruzlutor
Copy link

@c1ngular

Can I ask, how did you expose shouldInterceptRequest to the React Native side? Did you fork the webview, or is there another way. Thanks in advance!

Same question, how we can expose shouldInterceptRequest to react native?

@rvasseur31
Copy link

I discover the mainDocumentURL from onshouldstartloadwithrequest which might meet our needs.

I'm using it that way :

        onShouldStartLoadWithRequest={({
          url: interceptedUrl,
          mainDocumentURL,
        }) => {
          const url =
            IS_IOS && mainDocumentURL ? mainDocumentURL : interceptedUrl

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests