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

Posted

技术标签:

【中文标题】React-native android WebView句柄在加载前点击了Url【英文标题】:React-native android WebView handle clicked Url before loading 【发布时间】:2016-12-24 06:44:13 【问题描述】:

我正在通过 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) 并且可以检查它尝试加载的 url。我什至可以检查 e.navigationType 是否是点击或其他。

现在在 android 上不存在此功能。在原生端有函数shouldOverrideUrlLoading,但这个函数在 react-native 中没有实现。 我发现了以下 GitHub 问题/PR https://github.com/facebook/react-native/pull/6478 我想现在,因为这个问题已经关闭并且有解释,所以这个功能没有得到实现。

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

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;
        

    


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

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

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

【问题讨论】:

【参考方案1】:

我正在通过 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

【讨论】:

感谢您的回答。这是一个非常好的解决方案,我在其他情况下使用它,例如当有一个链接并且我希望它在我自己的视图中而不是在网络浏览器中打开时。但是,如果您想打开一个不针对网页(如 .pkpass 文件)的链接,则应用程序会崩溃,因为它在您停止之前就开始加载该链接。使用 iOS 功能,您可以在执行任何操作之前停止请求。据我所知,onNavigationStateChange 在第一次加载请求后被调用。或者您是否找到了在单击无效链接时停止加载的方法? 我能想到的解决这个问题的唯一方法是使用stopLoading 函数停止加载webview。但是你说onNavigationStateChage 在加载请求之后被调用.. 所以当stopLoading() 被调用时——可能为时已晚,应用程序会崩溃。但我会尝试一次,看看上述解决方案是否有效。 我不能准确地说出哪个函数在哪个时间被调用,但我可以看到应用程序在我想打开像 .pkpass 这样的链接后立即停止它之前崩溃了跨度> 【参考方案2】:

自 2018 年底以来,react-native-community/react-native-webview 版本已支持onShouldStartLoadWithRequest。 See PR.

【讨论】:

以上是关于React-native android WebView句柄在加载前点击了Url的主要内容,如果未能解决你的问题,请参考以下文章

解决 React-Native: Android project not found. Maybe run react-native android first?

react-native 跳转到ios/android 权限设置界面

在react-native中,我如何在ios和android的图像上添加水印

使用 react-native 克隆本机 android 警报屏幕

React-Native 开发 Android环境部署,Hello react-native

react-native 在 Android 中有抖动功能吗?