API Level 30无法加载本地HTML文件

9
我的应用程序通过WebView#loadUrl()加载位于getFilesDir()下的本地 HTML 文件。
targetSdkVersion = 29之前,以下代码可以工作。
        copyAssetsFile(this, "sample.html", getFilesDir().getAbsolutePath());
        webView.getSettings().setJavaScriptEnabled(true);
        String url = "file://" + getFilesDir().getAbsolutePath() + "/sample.html";
        webView.loadUrl(url);
    }

    private static void copyAssetsFile(Context context, String fileName, String directoryPath) {
        try {
            InputStream inputStream = context.getResources().getAssets().open(fileName);
            FileOutputStream fileOutputStream = new FileOutputStream(
                    new File(directoryPath, fileName), false);
            byte[] buffer = new byte[1024];
            int length = 0;
            while ((length = inputStream.read(buffer)) >= 0) {
                fileOutputStream.write(buffer, 0, length);
            }

            fileOutputStream.close();
            inputStream.close();

完整示例位于此处

然而,当更改targetSdkVersion = 30后,它无法正常工作。

  • WebView 响应 net::ERR_ACCESS_DINIED
  • 如果本地 HTML 文件位于 android_asset 中,则可以加载该文件

如何在 targetSdkVersion = 30 上加载本地 HTML 文件?
是否被 Android FW 拒绝了?


我们不相信你,因为使用那段代码后,WebView 不会开始讨论资产。 - blackapps
3个回答

13

1
尝试设置 webview.getSettings().setAllowFileAccess(true);

非常好用。只需要一行代码。我在 Cordova 中发现了这个问题,但我注意到最新版本有一个开关可以启用它。请参见 https://github.com/apache/cordova-android/blob/master/framework/src/org/apache/cordova/engine/SystemWebViewEngine.java 中的 AndroidInsecureFileModeEnabled。 - mike nelson

0

为了在api 30中在webView中显示本地html文件,我使用了这段代码

binding.webView.apply {
        visible()
        settings.apply {
            useWideViewPort = true
            loadWithOverviewMode = true
            builtInZoomControls = true
            displayZoomControls = false
            allowFileAccess = false
            allowFileAccessFromFileURLs = false
            allowUniversalAccessFromFileURLs = false
            allowContentAccess = true
        }
        val contentUri = FileProvider.getUriForFile(
            this@DocViewerActivity,
            "${BuildConfig.APPLICATION_ID}.provider",
            File(filePath!!)
        )
        webViewClient = MyWebClient(this@DocViewerActivity)

        contentUri?.let { loadUrl(contentUri.toString()) }
    }

现在WebClient类是

import android.content.Context
import android.content.Intent
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebView
import androidx.webkit.WebViewAssetLoader
import androidx.webkit.WebViewClientCompat
import java.io.File

class MyWebClient(context: Context) : WebViewClientCompat() {
private val assetLoader: WebViewAssetLoader = WebViewAssetLoader.Builder()
    .addPathHandler(
        "/public/", WebViewAssetLoader.InternalStoragePathHandler(
            context,
            File(context.filesDir, "public")
        )
    )
    .build()

override fun shouldInterceptRequest(
    view: WebView,
    request: WebResourceRequest
): WebResourceResponse? {
    return assetLoader.shouldInterceptRequest(request.url)
}

override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
    return if (request.isForMainFrame) {
        view.context.startActivity(
            Intent(Intent.ACTION_VIEW, request.url)
        )
        true
    } else false
}
}

并使用webKit依赖项

implementation 'androidx.webkit:webkit:1.4.0'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接