Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React-native android WebView handle clicked Url before loading

I'm showing a Website trough a WebView in react-native. On this Website there is a link to a PassWallet (.pkpass) file (not the only use case). When I click on any link on this Website I want to check whether it is an other Website or a .pkpass file or whatever. While this check is running I don't want to load anything, just wait until my function is finished and I'm knowing if I should open a Website or open another app or whatever. I want to make this on the JavaScript side because my whole routing functions are there and in my opinion react-native was built for this cases :-)

On iOS there is this beautiful function onShouldStartLoadWithRequest which exactly does what I need.

_onShouldStartLoadWithRequest(e) {

    if(checkUrl(e.url)) {

        let Router = this.props.navigator.props.router;
        let route = Router.getRouteFromUrl(e.url);
        this.props.navigator.push(route);

        return false;

    }

    return true;
}  

I'm getting the event (e) and can check what url it's trying to load. I can even check with e.navigationType if it was a click or whatever.

Now on Android this function does not exists. On the native side there is the function shouldOverrideUrlLoading but this function is not implemented in react-native. I found the following GitHub issue / PR https://github.com/facebook/react-native/pull/6478 I guess now, because this issue is closed and there are explanations for therefore, this function don't get implemented.

So I started to find a way by myself. I created a Native UI Component which displays a WebView and then implement this method.

CustomWebViewManager.java:

package ch.mypackage;

import android.support.annotation.Nullable;
import android.webkit.WebView;

import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.annotations.ReactProp;

public class CustomWebViewManager extends SimpleViewManager<CplusWebView> {

    @Override
    public String getName() {
        return "CplusWebView";
    }

    @Override
    protected CustomWebView createViewInstance(ThemedReactContext reactContext) {
        return new CustomWebView(reactContext);
    }

    @ReactProp(name = "url")
    public void setUrl(CustomWebView view, @Nullable String url) {
        view.loadUrl(url);
    }

    @ReactProp(name = "javascriptEnabled")
    public void setJavascriptEnabled(CustomWebView view, boolean enabled) {
        view.getSettings().setJavaScriptEnabled(enabled);
    }

}

CustomWebView.java

package ch.couponplus;

import android.util.Log;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.events.EventDispatcher;
import com.facebook.react.uimanager.events.RCTEventEmitter;

public class CustomWebView extends WebView {

    EventDispatcher eventDispatcher;
    EventWebClient eventWebClient;

    public CustomWebView(ThemedReactContext reactContext) {
        super(reactContext);
        eventWebClient = new EventWebClient();
        setWebViewClient(eventWebClient);
    }

    protected class EventWebClient extends WebViewClient {

        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {

            WritableMap event = Arguments.createMap();
            event.putString("message", "MyMessage");
            ReactContext reactContext = (ReactContext)getContext();
            reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(
                    getId(),
                    "topChange",
                    event);

            return true;
        }

    }

}

It works as expected. I can now trigger the shouldOverrideUrlLoading function in JS and make logs or whatever.

But my question is how can I now set true or false in Javascript to control my shouldOverrideUrlLoading function? And is there a possibility to make my own functions available? Until now I only managed to trigger the onChange event?

I just want to make the same as I made in iOS. Maybe someone comes up and tells me that this isn't possible for whatever reason but how should I or how do you handle cases like this? I know there are Url schemas but so much I know they don't work in this case.

like image 959
vanBrunneren Avatar asked Aug 17 '16 14:08

vanBrunneren


2 Answers

I'm showing a Website trough a WebView in react-native. On this Website there is a link to a PassWallet (.pkpass) file (not the only use case). When I click on any link on this Website I want to check whether it is an other Website or a .pkpass file or whatever.

I had a similar issue as well, where I wanted to check the type of link clicked within the webView of my react-native app. Like you said, on the iOS side the function onShouldStartLoadWithRequest, which is not present on the Android side.

This was my solution on the Android side.

   <WebView
        source={{uri: this.props.url}}
        onLoad={this.onLoad.bind(this)}
        onShouldStartLoadWithRequest={this._onShouldStartLoadWithRequest}
        onNavigationStateChange = {this._onShouldStartLoadWithRequest} 
    />

Then you can do something like this:

  _onShouldStartLoadWithRequest(e) {

if(checkUrl(e.url)) {

    let Router = this.props.navigator.props.router;
    let route = Router.getRouteFromUrl(e.url);
    this.props.navigator.push(route);

    this.refs[WEBVIEW_REF].stopLoading();  // <---- Add a similar line
    //This will tell your webView to stop processing the clicked link

    return false;

}

return true;

If I understood your problem correctly, you want a way to check the URL clicked in your WebView and then decide based on the URL to proceed or stop and do something else. The solution above the way I handled it in our app.

Check out the links below:

https://facebook.github.io/react-native/docs/webview.html#stoploading https://github.com/facebook/react-native/pull/6886

like image 126
maha_funk Avatar answered Oct 30 '22 05:10

maha_funk


onShouldStartLoadWithRequest has been supported since end-2018 in react-native-community/react-native-webview version. See PR.

like image 2
Jules Sam. Randolph Avatar answered Oct 30 '22 06:10

Jules Sam. Randolph