我有一个显示本地 Assets 网站的Android应用程序,它只有1个 Activity 与共同的webview:

我使用WebViewAssetLoader作为服务文件的本地方式,我面临的最大麻烦是,如果我安装了该应用程序,并且第一次无法将其加载到WebView中,则该应用程序被我杀死了并运行它再次可以完美运行(但是我不能说用户可以这样做),如果该应用程序是由Android Studio第二次安装的,它也可以运行,但是如果从未安装过该应用程序,则它总是会失败。

这是logcat的结果



这是加载WebView的代码

private fun initializeWebViewSettings() {
    webView!!.setBackgroundColor(Color.TRANSPARENT)
    webView!!.settings.javaScriptEnabled = true
    webView!!.settings.javaScriptCanOpenWindowsAutomatically = true
    webView!!.settings.domStorageEnabled = true
    webView!!.settings.allowFileAccess = true
    webView!!.settings.allowContentAccess = true
    webView!!.settings.allowUniversalAccessFromFileURLs = true
    webView!!.settings.setGeolocationEnabled(true)
    setWebViewClient()
    setWebViewChromeClient()
    webView!!.visibility = View.INVISIBLE


    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        //ONLY API_LEVEL >= 21 can use WebViewAssetLoader
        assetLoader = WebViewAssetLoader.Builder()
            .addPathHandler("/assets/", AssetsPathHandler(this))
            .addPathHandler("/res/", ResourcesPathHandler(this))
            .build()
        webView!!.loadUrl(Constants.WEB_URL_SERVED)
    }
    else{
        webView!!.loadUrl(Constants.WEB_URL_LOCAL)
    }
}

经过研究后,发现这是与此问题相关的已知错误,但已解决了较新版本的Chrome,我正在使用Android API 28(最新)在Galaxy Note10上进行测试

有没有人遇到过类似的问题?任何线索将不胜感激。

最佳答案

我的回答不能直接解决您的问题,因为它需要更多的上下文(更多的日志以及您使用的Webview软件包和版本),但是希望这可以有所帮助。



这些日志不是崩溃发生的原因,这是WebView本身存在的问题,与WebViewAssetLoader没有任何关系。因此,请确保更新到设备上的最新WebView和Chrome版本(与Android框架不同,WebView会通过应用商店定期更新)。为了确保这不是WebViewAssetLoader问题,请尝试构建没有所有WebViewAssetLoader代码的相同应用,然后查看是否仍然发生相同的崩溃。



这是与androidx.webkit.WebViewAssetLoader相关的唯一行。我假设您正在加载的内容正在尝试打开一个不存在的/assets/dist/文件夹。但是,这不会导致任何崩溃。

除此之外,您的代码还有一些注意事项:

  • 如果API级别大于等于21,则不必保护WebViewAssetLoader,您应该可以将其用于API >= 14

  • 对于WebViewClient#shouldInterceptRequest,如果重写该方法的两个版本,而不是完全放弃对旧API使用WebViewAssetLoader,那就更好了:
    @RequiresApi(21)
    override fun shouldInterceptRequest(
        view: WebView?,
        request: WebResourceRequest?
    ): WebResourceResponse? {
        return assetLoader.shouldInterceptRequest(request.url)
    }
    
    @SuppressWarnings("deprecation") // suppress the warning if your target build API is lower than 21
    override fun shouldInterceptRequest(
        view: WebView?,
        request: String?
    ): WebResourceResponse? {
        return assetLoader.shouldInterceptRequest(Uri.parse(request))
    }
    
  • 不要将此设置设置为true:
  •   webView!!.settings.allowUniversalAccessFromFileURLs = true
    

    我假设您在未使用WebViewAssetLoader的情况下启用了此设置。此设置的高度为discouraged,因为它允许javascript的CORS。如果您曾经在WebView中加载第三方内容,这将带来安全隐患,因为它会使任何javascript代码都能够访问任何私有(private)应用程序文件。这实际上是WebViewAssetLoader试图解决的主要问题,因此当您使用allowUniversalAccessFromFileURLs = true时,您不需要-并且实际上不应设置WebViewAssetLoader

    此外,为了使事情更加安全,如果您使用WebViewAssetLoader访问所有本地应用程序 Assets 文件,还应将其设置为false:
    webView!!.settings.allowFileAccess = false
    

    08-06 11:27