React-native android WebView 句柄在加载前单击了 Url

IT技术 javascript android reactjs webview react-native
2021-05-17 10:08:53

我正在通过 react-native 中的 WebView 展示一个网站。在本网站上有一个指向 PassWallet (.pkpass) 文件的链接(不是唯一的用例)。当我单击本网站上的任何链接时,我想检查它是其他网站还是 .pkpass 文件或其他任何内容。在此检查运行时,我不想加载任何内容,只需等到我的功能完成并且我知道是否应该打开网站或打开另一个应用程序或其他任何内容。我想在 JavaScript 端做这个,因为我的整个路由功能都在那里,我认为 react-native 是为这种情况构建的 :-)

在 iOS 上有这个漂亮的功能onShouldStartLoadWithRequest,它正是我需要的。

_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;
}  

我收到事件 (e) 并且可以检查它正在尝试加载的网址。我什至可以用 e.navigationType 检查它是否是点击或其他任何东西。

现在在Android上这个功能不存在。在本机方面有该功能,shouldOverrideUrlLoading但该功能未在 react-native 中实现。我发现了以下 GitHub 问题/PR https://github.com/facebook/react-native/pull/6478 我想现在,因为这个问题已经关闭,因此有解释,这个功能没有得到实现。

于是我开始自己寻找方法。我创建了一个显示 WebView 的本机 UI 组件,然后实现了这个方法。

自定义WebViewManager.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);
    }

}

自定义WebView.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;
        }

    }

}

它按预期工作。我现在可以shouldOverrideUrlLoading在 JS 中触发该功能并制作日志或其他任何东西。

但我的问题是我现在如何设置truefalse在 Javascript 中控制我的shouldOverrideUrlLoading功能?是否有可能使我自己的功能可用?直到现在我才设法触发onChange事件?

我只想做出与我在 iOS 中所做的相同的事情。也许有人过来告诉我无论出于何种原因这是不可能的,但是我应该如何或您如何处理这样的情况?我知道有 Url 模式,但我知道它们在这种情况下不起作用。

2个回答

我正在通过 react-native 中的 WebView 展示一个网站。在本网站上有一个指向 PassWallet (.pkpass) 文件的链接(不是唯一的用例)。当我单击本网站上的任何链接时,我想检查它是其他网站还是 .pkpass 文件或其他任何内容。

我也有类似的问题,我想检查在我的 react-native 应用程序的 webView 中单击的链接类型。就像你说的,在 iOS 端的功能onShouldStartLoadWithRequest,在 Android 端不存在。

这是我在 Android 方面的解决方案。

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

然后你可以做这样的事情:

  _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;

如果我正确理解了您的问题,您需要一种方法来检查在 WebView 中单击的 URL,然后根据 URL 决定是继续还是停止并执行其他操作。我在我们的应用程序中处理它的方式上面的解决方案。

检查下方的链接:

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

onShouldStartLoadWithRequest自 2018 年底以来已在react-native-community/react-native-webview版本中得到支持见公关