【问题标题】:"net::ERR_UNKNOWN_URL_SCHEME" error when url is"intent://kakaopay..."当 url 为“intent://kakaopay...”时出现“net::ERR_UNKNOWN_URL_SCHEME”错误
【发布时间】:2019-07-31 07:45:11
【问题描述】:

我已经使用 Flutter 的 web_view_plugin(webview) 构建了一个混合应用程序。 我们的一种支付方式需要打开一个 3rd 方应用程序(在本例中为 kakaotalk)。但是flutter webview插件没有提供这个功能,返回了net::ERR_UNKNOWN_URL_SCHEME。我做了一些研究,我知道问题在于url。如果url 不以httphttps 开头,则会导致此错误。

所以,为了解决这个问题,我不得不更改本机 Java 代码。现在我完全没有使用javaandroid 的经验,因此修复本机代码非常困难。我知道我必须修改shouldOverrideUrlLoading 部分,以允许以intent:// 开头的url 并且我必须进行一些验证以检查应用程序是否已安装。(如果未安装用户应该被重定向到Playstore)

我添加的代码在shouldOverrideUrlLoading。 我还做了三个导入。剩下的就是代码,由flutter生成

package com.flutter_webview_plugin;

import android.annotation.TargetApi;
import android.graphics.Bitmap;
import android.os.Build;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import android.content.Intent; //added import
import android.net.Uri; //added import
import android.content.ActivityNotFoundException; //added import
/**
 * Created by lejard_h on 20/12/2017.
 */

public class BrowserClient extends WebViewClient {
    private Pattern invalidUrlPattern = null;

    public BrowserClient() {
        this(null);
    }

    public BrowserClient(String invalidUrlRegex) {
        super();
        if (invalidUrlRegex != null) {
            invalidUrlPattern = Pattern.compile(invalidUrlRegex);
        }
    }

    public void updateInvalidUrlRegex(String invalidUrlRegex) {
        if (invalidUrlRegex != null) {
            invalidUrlPattern = Pattern.compile(invalidUrlRegex);
        } else {
            invalidUrlPattern = null;
        }
    }

    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        super.onPageStarted(view, url, favicon);
        Map<String, Object> data = new HashMap<>();
        data.put("url", url);
        data.put("type", "startLoad");
        FlutterWebviewPlugin.channel.invokeMethod("onState", data);
    }

    @Override
    public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);
        Map<String, Object> data = new HashMap<>();
        data.put("url", url);

        FlutterWebviewPlugin.channel.invokeMethod("onUrlChanged", data);

        data.put("type", "finishLoad");
        FlutterWebviewPlugin.channel.invokeMethod("onState", data);

    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
        // returning true causes the current WebView to abort loading the URL,
        // while returning false causes the WebView to continue loading the URL as usual.
        String url = request.getUrl().toString();
        boolean isInvalid = checkInvalidUrl(url);
        Map<String, Object> data = new HashMap<>();
        data.put("url", url);
        data.put("type", isInvalid ? "abortLoad" : "shouldStart");

        FlutterWebviewPlugin.channel.invokeMethod("onState", data);
        return isInvalid;
    }

    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        // returning true causes the current WebView to abort loading the URL,
        // while returning false causes the WebView to continue loading the URL as usual.
        if (url.startsWith(INTENT_PROTOCOL_START)) {
                final int customUrlStartIndex = INTENT_PROTOCOL_START.length();
                final int customUrlEndIndex = url.indexOf(INTENT_PROTOCOL_INTENT);
                if (customUrlEndIndex < 0) {
                    return false;
                } else {
                    final String customUrl = url.substring(customUrlStartIndex, customUrlEndIndex);
                    try {
                        view.getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(customUrl)));
                    } catch (ActivityNotFoundException e) {
                        final int packageStartIndex = customUrlEndIndex + INTENT_PROTOCOL_INTENT.length();
                        final int packageEndIndex = url.indexOf(INTENT_PROTOCOL_END);

                        final String packageName = url.substring(packageStartIndex, packageEndIndex < 0 ? url.length() : packageEndIndex);
                        view.getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(GOOGLE_PLAY_STORE_PREFIX + packageName)));
                    }
                    return true;
                }
            } else {
                return false;
            }
        // boolean isInvalid = checkInvalidUrl(url);
        // Map<String, Object> data = new HashMap<>();
        // data.put("url", url);
        // data.put("type", isInvalid ? "abortLoad" : "shouldStart");

        // FlutterWebviewPlugin.channel.invokeMethod("onState", data);
        // return isInvalid;
    }


    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    @Override
    public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
        super.onReceivedHttpError(view, request, errorResponse);
        Map<String, Object> data = new HashMap<>();
        data.put("url", request.getUrl().toString());
        data.put("code", Integer.toString(errorResponse.getStatusCode()));
        FlutterWebviewPlugin.channel.invokeMethod("onHttpError", data);
    }

    @Override
    public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
        super.onReceivedError(view, errorCode, description, failingUrl);
        Map<String, Object> data = new HashMap<>();
        data.put("url", failingUrl);
        data.put("code", errorCode);
        FlutterWebviewPlugin.channel.invokeMethod("onHttpError", data);
    }

    private boolean checkInvalidUrl(String url) {
        if (invalidUrlPattern == null) {
            return false;
        } else {
            Matcher matcher = invalidUrlPattern.matcher(url);
            return matcher.lookingAt();
        }
    }
}

代码编译,但当我尝试使用“3rd party app(kakaotalk)”付款时,它仍然返回相同的错误net::ERR_UNKNOWN_URL_SCHEME

【问题讨论】:

    标签: java android flutter webview


    【解决方案1】:

    之前,当 Firebase 动态链接被强制加载到 WebView 中时,我在 Android 上遇到了类似的错误。就我而言,FDL 预计将由 Android 中的 Google Play 服务处理。但由于 WebView 不知道如何处理它强制显示的链接,因此 WebView 返回“net::ERR_UNKNOWN_URL_SCHEME”错误。我不确定这是否与您的情况相同,因为除了“intent://kakaopay...”之外,我无法验证您尝试加载的链接

    您可以尝试使用url_launcher 从外部打开链接。使用 RegEx 过滤意图 URL 并检查 URL 是否可以在外部(应用程序外部)启动和处理。

    var yourURL = "URL goes here";
    // Check if URL contains "intent"
    yourURL.contains(RegExp('^intent://.*\$')){
      // Check if the URL can be launched
      if (await canLaunch(yourURL)) {
        await launch(yourURL);
      } else {
        print('Could not launch $yourURL');
      }
    }
    

    另外,您使用的插件 (web_view_plugin) 似乎已经过时,我在 https://pub.dev/packages?q=web_view_plugin 找不到它。 Flutter 的官方 WebView 插件 (webview_flutter) 已经发布,我建议您检查一下它是否适合您的用例。

    【讨论】:

      【解决方案2】:

      听着,在某些情况下使用@omat 的答案可能不起作用,尤其是对于 webview_flutter。我努力寻找解决方案,所以我这样做了:

      _launchURL(url) async {
        var link = "https://hiddenwords.page.link/deposit";
      
        if (await canLaunch(link)) {
            await launch(link,
            forceWebView: false, enableJavaScript: true, forceSafariVC: 
          false);
        } else {
          throw 'Could not launch $link';
        }
      }
      

      我手动将我希望它打开的 url/链接放在 _launch 函数中...不要介意 _launch 括号中的 url。

      我还将它添加到 Webview 小部件中:

      navigationDelegate: (NavigationRequest request) {
         if (request.url.contains(RegExp('^intent://.*\$')))  {
              _launchURL(request.url);
              return NavigationDecision.prevent;
         }
           return NavigationDecision.navigate;
      },
      

      希望这对你有用。它对我有用...

      【讨论】:

        猜你喜欢
        • 2017-05-05
        • 2018-06-14
        • 1970-01-01
        • 2013-03-06
        • 2020-12-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多