当 url 为“intent://kakaopay...”时出现“net::ERR_UNKNOWN_URL_SCHEME”错误

问题描述 投票:0回答:4

我使用 flutter 的

web_view_plugin
(webview)构建了一个混合应用程序。 我们的一种付款方式需要打开第 3 方应用程序(在本例中为 kakaotalk)。但是flutter webview插件不提供这个功能,返回了
net::ERR_UNKNOWN_URL_SCHEME
。我做了一些研究,我明白问题出在
url
。如果
url
不是以
http
https
开头,就会导致这个错误。

因此,为了解决这个问题,我必须更改本机java代码。现在我对

java
android
完全没有经验,所以修复原生代码非常困难。我知道我必须修改
shouldOverrideUrlLoading
部分,以便允许以
url
开头的
intent://
,而且我还必须进行一些验证来检查应用程序是否已安装。(如果未安装,用户应该被重定向到 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();
        }
    }
}

代码可以编译,但当我尝试使用“第 3 方应用程序(kakaotalk)”付款时,它仍然返回相同的错误

net::ERR_UNKNOWN_URL_SCHEME

java android flutter webview
4个回答
2
投票

我之前在 Android 上遇到过类似的错误,当时 Firebase 动态链接被强制加载到 WebView 中。就我而言,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
) 已发布,我建议检查它是否适合您的用例。


1
投票

听着,在某些情况下使用@omatt的答案可能不起作用,特别是对于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';
  }
}

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

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

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

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


0
投票

1.使用您的APP在flutter中使用参数(在您的动态链接中)打开其他应用程序; 2.使用:url_launcher:^6.1.6;

首先,他们的应用程序必须支持动态链接; 其次,他们为您提供他们的交易的动态链接; 这样我们就可以点击你APP中的动态链接,跳转到他们APP的指定页面了。

代码:

 final Uri toLaunch = Uri(scheme: 'https', host: 'link.fitstop.com', path: 'link/qbvQ/');
  //https://link.fitstop.com/link/qbvQ   is dynamic link

  Future<void>? _launched;

    ElevatedButton(
              onPressed: () => setState(() {
                _launched = _launchInBrowser(toLaunch);
              }),
              child: Text(
                'url_launcher',
              ),
            )

  Future<void> _launchInBrowser(Uri url) async {
    if (!await launchUrl(
      url,
      mode: LaunchMode.externalApplication,
    )) {
      throw 'Could not launch $url';
    }
  }

0
投票

您可以使用flutter_inappwebview

InAppWebViewSettings settings = InAppWebViewSettings(
  useShouldOverrideUrlLoading: true,
  ...
);

@override
Widget build(BuildContext context) {
    super.build(context);
    return 
    ...
    InAppWebView(
        ...
        shouldOverrideUrlLoading: (controller, navigationAction) async {
            var uri = navigationAction.request.url!;
            if (uri.scheme == "intent") {
              return NavigationActionPolicy.CANCEL;
            } else {
              return NavigationActionPolicy.ALLOW;
            }
        },
        ...
    ),
    ...
}
© www.soinside.com 2019 - 2024. All rights reserved.