70

我正在尝试让我的 android webview 应用程序打开电话:手机链接。每次我打开电话链接时,它都会很好地打开电话。但是,一旦我完成通话并返回应用程序,它就会出现在一个页面上,上面写着“找不到网页,电话:0000000000”。然后我必须再次点击返回按钮才能进入我点击电话号码的页面。

有没有办法让它打开电话链接而不试图在 webview 中找到页面以及在手机上打开它?

这是我在 WebView 中用来覆盖其对 TEL 和 Mailto 链接的处理的代码:

        public boolean shouldOverrideUrlLoading(WebView view, String url) {
        if (url.startsWith("mailto:") || url.startsWith("tel:")) { 
                Intent intent = new Intent(Intent.ACTION_VIEW,
                        Uri.parse(url)); 
                startActivity(intent); 
                } 
        view.loadUrl(url);
        return true;
        }

任何帮助,将不胜感激。在过去的 2 个小时里,我一直在搜寻 Goodle,但没有给出任何答案。

4

11 回答 11

118

好的,所以我解决了我认为的问题。我只需要按如下方式分隔 URL 覆盖:

public boolean shouldOverrideUrlLoading(WebView view, String url) {
    if (url.startsWith("tel:")) { 
        Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(url)); 
        startActivity(intent);
        view.reload();
        return true;
    }

    view.loadUrl(url);
    return true;
}

现在我的常规链接和电话链接一样有效。如果需要,我还可以在其中添加 geo: 链接,它不会给我带来以前在手机上打开地图时遇到的问题。

于 2010-12-02T19:51:34.453 回答
57

而不是 call loadUrl(url),只为不应被覆盖的 URL 返回 false :

public boolean shouldOverrideUrlLoading(WebView view, String url) {
    if( URLUtil.isNetworkUrl(url) ) {
        return false;
    }

    // Otherwise allow the OS to handle it
    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
    startActivity( intent ); 
    return true;
}

我发现 VIEWing tel: 在我们尝试过的所有手机上都能正常工作。由于 DIAL 操作,无需对其进行特殊处理。

我注意到 YouTube 视频等在 WebViews 中不起作用,因此您可能也想检测这些。

通过在 PackageManager 中查询处理您的 URI(也不是嵌入式浏览器)的活动,整个过程可能会针对各种 URI 进行概括。这可能有点矫枉过正,并且会被其他已安装的浏览器弄糊涂。

于 2011-04-04T23:24:06.817 回答
19

根据文档和我的经验,解析、、、和链接是Intent.ACTION_VIEW完全可以的。tel:sms:smsto:mms:mmsto:

这是 5 合 1:

@Override
    public boolean shouldOverrideUrlLoading(WebView webview, String url)
    {
     if (url.startsWith("tel:") || url.startsWith("sms:") || url.startsWith("smsto:") || url.startsWith("mms:") || url.startsWith("mmsto:"))
       { 
         Intent intent = new Intent(Intent.ACTION_VIEW,Uri.parse(url)); 
         startActivity(intent); 
         return true;
       }
    return false;
   }
于 2015-10-15T21:59:29.627 回答
15

shouldOverrideUrlLoading注意:-弃用Android Nouget 后

您需要使用shouldOverrideUrlLoadingwith 以shouldOverrideUrlLoading获得更好的支持。此外,您可能想检查 url 是否有mailto:tel:,它们在 HTML5 中用于分别触发邮件客户端和电话拨号。

一个完整的解决方案现在看起来像这样

    @SuppressWarnings("deprecation")
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        if (url.startsWith("mailto:")) {  
            //Handle mail Urls
            startActivity(new Intent(Intent.ACTION_SENDTO, Uri.parse(url)));
        } else if (url.startsWith("tel:")) {
            //Handle telephony Urls
            startActivity(new Intent(Intent.ACTION_DIAL, Uri.parse(url)));
        } else {
            view.loadUrl(url);
        }
        return true;
    }

    @TargetApi(Build.VERSION_CODES.N)
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
        final Uri uri = request.getUrl();
        if (uri.toString().startsWith("mailto:")) {
            //Handle mail Urls
            startActivity(new Intent(Intent.ACTION_SENDTO, uri));
        } else if (uri.toString().startsWith("tel:")) {
            //Handle telephony Urls
            startActivity(new Intent(Intent.ACTION_DIAL, uri));
        } else {
            //Handle Web Urls
            view.loadUrl(uri.toString());
        }
        return true;
    }
于 2017-04-13T13:22:36.187 回答
4
public class MainActivity extends Activity {

private static final String HTML ="<!DOCTYPE html><html><body><a 
href='tel:867-5309'>Click here to call!</a></body></html>";
private static final String TEL_PREFIX = "tel:";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    WebView wv = (WebView) findViewById(R.id.webview);
    wv.setWebViewClient(new CustomWebViewClient());
    wv.loadData(HTML, "text/html", "utf-8");
}

private class CustomWebViewClient extends WebViewClient {

    @Override
    public boolean shouldOverrideUrlLoading(WebView wv, String url) {
        if(url.startsWith(TEL_PREFIX)) {
            Intent intent = new Intent(Intent.ACTION_DIAL);
            intent.setData(Uri.parse(url));
            startActivity(intent);
            return true;
        }
        return false;
    }
}

}

这是我找到的解决方法。你必须使用这种方法。

wv.setWebViewClient(new CustomWebViewClient());
于 2018-02-01T04:59:05.933 回答
3

如果没有为 WebView 分配 WebViewClient,默认情况下 WebView 将要求 Activity Manager 为 URL 选择正确的处理程序。如果提供了WebViewClient,则需要自己处理不同的URL,并在WebViewClient.shouldOverrideUrlLoading()中返回true,否则会尝试向该URL发送请求并报错,然后触发onReceiveError()。

检查文档:WebViewClient.shouldOverrideUrlLoading

     @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        if (url.startsWith("tel:")) { 
            // ...TODO: launch a Dial app or send SMS or add to contact, etc...
            return true;
        }
        else if (url.startsWith("mailto:")) {
            // ...TODO: send email to someone or add to contact, etc...
            return true;
        }
        else {
            // ...TODO: Handle URL here
            boolean handled = yourHandleUrlMethod(url);
            return handled;
        }
    }
于 2016-02-12T00:48:10.563 回答
1
public boolean shouldOverrideUrlLoading(WebView view, String url)
       {Uri query_string=Uri.parse(url);
        String query_scheme=query_string.getScheme();
        String query_host=query_string.getHost();
        if ((query_scheme.equalsIgnoreCase("https") || query_scheme.equalsIgnoreCase("http"))
            && query_host!=null && query_host.equalsIgnoreCase(Uri.parse(URL_SERVER).getHost())
            && query_string.getQueryParameter("new_window")==null
           )
           {return false;//handle the load by webview
           }
        try
           {Intent intent=new Intent(Intent.ACTION_VIEW, query_string);
            String[] body=url.split("\\?body=");
            if (query_scheme.equalsIgnoreCase("sms") && body.length>1)
               {intent=new Intent(Intent.ACTION_VIEW, Uri.parse(body[0]));
                intent.putExtra("sms_body", URLDecoder.decode(body[1]));
               }
            view.getContext().startActivity(intent);//handle the load by os
           }
        catch (Exception e) {}
        return true;
       }
于 2011-08-11T05:14:11.497 回答
1

一些常量在WebView类中是静态的。您应该使用Intent.ACTION_VIEW代替Intent.ACTION_DIALor ACTION_SENDTO

@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
    String url = request.getUrl().toString();
    if (url.startsWith(WebView.SCHEME_TEL)
            || url.startsWith(SCHEME_SMS)
            || url.startsWith(WebView.SCHEME_MAILTO)
            || url.startsWith(WebView.SCHEME_GEO)) {
        
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setData(Uri.parse(url));
        startActivity(intent); // view.context.startActivity(intent);
    }
    return true;
}
于 2020-07-24T04:13:02.123 回答
0
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    WebView wv = (WebView) findViewById(R.id.webview);
    wv.setWebViewClient(new CustomWebViewClient());
    wv.loadData(HTML, "text/html", "utf-8");
}

private class CustomWebViewClient extends WebViewClient {
    @SuppressWarnings("deprecated")
    @Override
    public boolean shouldOverrideUrlLoading(WebView wv, String url) {
        if(url.startsWith(TEL_PREFIX)) {
            Intent intent = new Intent(Intent.ACTION_DIAL);
            intent.setData(Uri.parse(url));
            startActivity(intent);
            return true;
        }
        return false;
    }
于 2018-02-20T06:16:19.000 回答
0

对于那些尝试使用@jeff Thomas 答案但出现以下错误的人:

cannot find symbol view.startActivity(intent);

您可以使用以下代码:

public boolean shouldOverrideUrlLoading(WebView view, String url) {
    if (url.startsWith("tel:")) { 
        Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(url)); 
        view.getContext().startActivity(intent);
        view.reload();
        return true;
    }

    view.loadUrl(url);
    return true;
}

我刚改成 这startActivity(intent)view.getContext().startActivity(intent)我有用。

于 2020-08-25T11:41:19.037 回答
0

看着Hitesh Sahukam C的答案,我得到了解决方案。

在 API 21 中,它引发了一个异常:“android.util.AndroidRuntimeException:从 Activity 上下文外部调用 startActivity() 需要 FLAG_ACTIVITY_NEW_TASK 标志。这真的是你想要的吗?”。

正如diyism所注意到的,也可能找不到活动。所以,我处理了这些情况。

class MyWebViewClient : WebViewClient() {

    @Suppress("DEPRECATION")
    override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
        if (view != null && url != null) {
            return resolveUri(view.context, Uri.parse(url))
        }
        return super.shouldOverrideUrlLoading(view, url)
    }

    @TargetApi(Build.VERSION_CODES.N)
    override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
        val uri = request?.url
        if (view != null && uri != null) {
            return resolveUri(view.context, uri)
        }
        return super.shouldOverrideUrlLoading(view, request)
    }

    private fun resolveUri(context: Context, uri: Uri): Boolean {
        val url = uri.toString()
        URL_SCHEMES.forEach {
            if (url.startsWith(it)) {
                val intent = Intent(Intent.ACTION_VIEW).apply {
                    data = uri
                    addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                }
                try {
                    context.startActivity(intent)
                } catch (e: ActivityNotFoundException) {
                }
                return true
            }
        }
        return false
    }

    companion object {
        private val URL_SCHEMES = arrayOf(WebView.SCHEME_TEL,
            WebView.SCHEME_MAILTO, WebView.SCHEME_GEO, "sms:", "smsto:", "mms:", "mmsto:")
    }
}
于 2020-08-25T14:56:04.383 回答