【问题标题】:Android WebView "tel:" links show web page not foundAndroid WebView“电话:”链接显示找不到网页
【发布时间】:2011-05-19 07:22:43
【问题描述】:

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

有没有办法让它打开 TEL 链接,而无需尝试在 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 小时我一直在寻找好东西,但没有给出任何答案。

【问题讨论】:

  • 试试 ACTION_DIAL 的电话:链接?
  • 等等,文档实际上说 ACTION_VIEW 没问题:developer.android.com/reference/android/content/Intent.html 没关系...
  • 愚蠢的问题:您是否正确设置了WebViewClient?其他一切正常吗?
  • 是的...除了 tel: 链接外,其他一切都正常运行。即使这些工作,只是当您不接电话并返回应用程序时,它位于显示未找到的页面上。
  • @EboMike:我认为您第一次是对的:developer.android.com/guide/appendix/g-app-intents.html -- 我不相信“请注意 VIEW 操作如何执行被认为对特定对象最合理的事情URI”文档中的注释。

标签: android android-webview


【解决方案1】:

好的,所以我解决了我认为的问题。我只需要按如下方式分隔 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: 链接,它不会给我带来以前在手机上打开地图时遇到的问题。

【讨论】:

  • 呃。我刚刚意识到您正在电话上调用 view.LoadUrl(url):链接。您不妨在startActivity() 之后添加一个return true
  • 添加到 Manifest。
  • @jasonflaherty 实际上 CALL_PHONE 权限是针对 ACTION_CALL 而不是 ACTION_DIAL。所以上面的代码即使没有权限也能正常工作。
  • 你不需要 view.loadUrl(url);返回 true 将导致 WebView 覆盖 URL 并按照它认为合适的方式处理它。
  • 请不要照原样复制上面的代码。从回调中返回 false 而不是调用 view.loadUrl。调用 loadUrl 会引入一个微妙的错误,如果页面中有任何带有自定义方案 URL 的 iframe(比如 ),它会将应用程序的主框架导航到最有可能破坏应用程序的 URL副作用。
【解决方案2】:

而不是调用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 中不起作用,因此您可能也想检测这些内容。

整个过程可能可以通过querying the PackageManager for Activities that handle your URI 概括为各种URI,它们也不是嵌入式浏览器。这可能有点矫枉过正,而且会被其他已安装的浏览器弄糊涂。

【讨论】:

  • 您可以使用 URLUtil.isNetworkUrl(url) 进行 http/https(和其他)检查
  • 很好的建议,@xnagyg。我已经更新了我的代码 sn-p。
  • 这比添加单独的 URL 方案实用得多。
【解决方案3】:

根据documentation 和我的经验,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;
   }

【讨论】:

    【解决方案4】:

    注意:- Android Nouget shouldOverrideUrlLoading 被弃用后

    您需要使用shouldOverrideUrlLoadingshouldOverrideUrlLoading 以获得更好的支持。此外,您可能需要检查 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;
        }
    

    【讨论】:

    • 完美... 处理预牛轧糖和牛轧糖。谢谢
    • 谢谢!使用@Suppress("DEPRECATION") 而不是@SuppressWarnings("deprecation")。您可以为这两个事件创建一种方法。使用view.getContext()startActivity() 之前插入。
    • 任何人都可以解释一下如果我得到:“错误:类 ContextCompat 中的方法 startActivity 不能应用于给定类型;startActivity(new Intent(Intent.ACTION_SENDTO, uri)); ^ 必需: Context,Intent,Bundle found: Intent 原因:实际和正式的参数列表长度不同”我已经在另一个类中实现了解决方案
    【解决方案5】:
    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());
    

    【讨论】:

      【解决方案6】:

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

      Check document: 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;
              }
          }
      

      【讨论】:

        【解决方案7】:
        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;
               }
        

        【讨论】:

        • 你能解释一下你的解决方案吗?尤其是使用 URL_SERVER 的测试(顺便说一句,缺少)可能不是每个人都清楚。
        • URL_SERVER 是“your.app.domain.com”,并且“return false;”表示您网站中的页面将在应用中打开,而不会在安卓浏览器中打开
        【解决方案8】:

        WebView 类中的一些常量是静态的。您应该使用Intent.ACTION_VIEW 而不是Intent.ACTION_DIALACTION_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;
        }
        

        【讨论】:

          【解决方案9】:
          @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;
              }
          

          【讨论】:

          • 我尝试使用上面发布的这种方法,但是当我添加“shouldoverrideurlloading”时,出现错误说这种方法已被弃用。使用此代码是否有任何 API 限制?.. 我试图将其安装在我的手机中,但应用程序会自行杀死。我该如何解决这个问题?..请帮助
          【解决方案10】:

          对于那些尝试使用@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),这对我有用。

          【讨论】:

          • 同意。您也可以将startActivity 包装在try-catch 块中。不需要view.reload();
          【解决方案11】:

          查看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:")
              }
          }
          

          【讨论】:

            猜你喜欢
            • 2012-06-18
            • 2016-10-12
            • 2013-12-13
            • 1970-01-01
            • 2023-03-13
            • 2016-12-19
            • 2020-12-11
            • 2012-08-28
            • 1970-01-01
            相关资源
            最近更新 更多