使用目标API 24链接到WebView中的本地文件

时间:2017-07-07 20:45:25

标签: android android-webview

如果定位到API 24或更高版本,如何使用HTML链接导航到WebView中的本地文件(HTML页面)?

之前已经讨论过,解决方案使用file:// URI方案。 到目前为止工作的是

<a href="file:///android_asset/my_page.html">Go to local page</a>

WebView中显示的HTML文件中,点击该链接会加载本地页面app/src/main/assets/my_page.html

但是,从API 24开始,单击此类链接时会引发FileUriExposedException。来自logcat:

mypackage.myapp W/System.err: android.os.FileUriExposedException: file:///android_asset/my_page.html exposed beyond app through Intent.getData()
...
mypackage.myapp W/System.err:     at org.chromium.android_webview.ResourcesContextWrapperFactory$WebViewContextWrapper.startActivity(ResourcesContextWrapperFactory.java:121)
mypackage.myapp W/System.err:     at org.chromium.android_webview.AwContentsClient.sendBrowsingIntent(AwContentsClient.java:203)

根据文档,当“应用程序将file:// Uri暴露给另一个应用程序时,会抛出此错误。”我想知道为什么会这样,因为根据日志,一切似乎都发生在mypackage.myapp内。

文档建议使用content:// URI方案,但这在HTML文件中不起作用。

2 个答案:

答案 0 :(得分:3)

以下解决方法(基于this answer)拦截file://WebView URI的加载,然后使用WebView.loadUrl(...)的应用代码直接加载它。这可以通过覆盖传递给WebView.shouldOverrideUrlLoading的{​​{1}}中的WebViewClient来实现,例如初始化时。

由于API 24中的此方法有API更改,为了兼容性,代码中有两个版本(技术上在API&lt; 24情况下,也可以像以前一样,让WebView打开{{ 1}} URI,因为在运行API&lt; 24)的设备上不会引发异常。

WebView

file://打开链接时出现异常的原因必须与if (android.os.Build.VERSION.SDK_INT >= 24) { webView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView webView, WebResourceRequest webResourceRequest) { if (webResourceRequest.getUrl().getScheme().equals("file")) { webView.loadUrl(webResourceRequest.getUrl().toString()); } else { // If the URI is not pointing to a local file, open with an ACTION_VIEW Intent webView.getContext().startActivity(new Intent(Intent.ACTION_VIEW, webResourceRequest.getUrl())); } return true; // in both cases we handle the link manually } }); } else { webView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView webView, String url) { if (Uri.parse(url).getScheme().equals("file")) { webView.loadUrl(url); } else { // If the URI is not pointing to a local file, open with an ACTION_VIEW Intent webView.getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); } return true; // in both cases we handle the link manually } }); } 创建的WebView有关,但我不知道是否或如何它暴露给另一个应用程序。

解决方法的工作原理是因为Intent对链接没有任何作用(没有创建WebView),而是在点击链接时,应用程序获得控制权并打开{ {1}} URI direclty将其传递给WebView - 这似乎没问题。

我假设(但不要求)关于安全性这很好,因为URI仅用于加载它指向的单个Intent中的文件(如果这是有问题的,系统应抛出{ {1}})。

答案 1 :(得分:0)

如果您需要加载其他页面,我从不在HTML中链接:

<a href="file:///android_asset/my_page.html">Go to local page</a>

我这样链接是因为我的地图结构看起来像this

<a href="my_page.html">Go to local page</a>

您只需在MainActivity.java中使用该方法即可:

private class MyBrowser extends WebViewClient {
    @Override
    public boolean shouldOverrideUrlLoading(WebView view, String url) {
        if (url.startsWith("tel:") || url.startsWith("sms:") || url.startsWith("smsto:") || url.startsWith("mailto:") || url.startsWith("mms:") || url.startsWith("mmsto:") || url.startsWith("market:")) {
            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            startActivity(intent);
            return true;
        }
        else {
            view.loadUrl(url);
            return true;
        }
    }
}

如果您有任何问题或仍然无法解决,请告诉我