Android WebView在第一次加载时失败

4
我有一个Android应用程序,显示本地资产网站,它只有1个常规webview活动:
我正在使用WebViewAssetLoader作为本地提供文件的方式,我面临的问题非常令人沮丧,即当应用程序第一次安装时,它无法在WebView中加载内容。如果我杀死应用程序并再次运行它,它就可以完美地工作(但我不能要求用户这样做)。此外,如果应用程序是通过Android Studio第二次安装的,则它可以正常工作,但如果应用程序从未安装过,则始终会失败。
这是logcat的结果。
2019年11月18日16:58:40.439 21492-21492 /?E / Zygote:isWhitelistProcess-进程已列入白名单 2019年11月18日16:58:40.439 21492-21492 /?E / Zygote:accessInfo:1 2019年11月18日16:58:40.628 21492-21544 com.my.app.dev.debug E / GraphicsEnv:无法获取GPU服务 2019年11月18日16:58:40.805 21492-21492 com.my.app.dev.debug E / chromium:[ERROR:filesystem_posix.cc(89)]stat / data / user / 0 / com.my.app.dev.debug / cache / WebView / Crashpad:没有该文件或目录(2) 2019年11月18日16:58:40.805 21492-21492 com.my.app.dev.debug E / chromium:[ERROR:filesystem_posix.cc(62)]mkdir / data / user / 0 / com.my.app.dev.debug / cache / WebView / Crashpad:没有该文件或目录(2) 2019年11月18日16:58:45.237 21492-21658 com.my.app.dev.debug E / AssetHelper:无法打开资产路径:dist/

这是加载 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上进行测试。
有人遇到类似的问题吗?任何线索将不胜感激。
2个回答

6

我的回答并不能直接解决你的问题,因为它需要更多的上下文信息(更多日志以及您正在使用的webview包和版本),但希望这可以帮助到你。

2019-11-18 16:58:40.439 21492-21492/? E/Zygote: isWhitelistProcess - 进程在白名单中 2019-11-18 16:58:40.439 21492-21492/? E/Zygote: accessInfo : 1

2019-11-18 16:58:40.628 21492-21544/com.my.app.dev.debug E/GraphicsEnv: 无法获取gpu服务

2019-11-18 16:58:40.805 21492-21492/com.my.app.dev.debug E/chromium: [ERROR:filesystem_posix.cc(89)] stat /data/user/0/com.my.app.dev.debug/cache/WebView/Crashpad: 没有那个文件或目录 (2)

2019-11-18 16:58:40.805 21492-21492/com.my.app.dev.debug E/chromium: [ERROR:filesystem_posix.cc(62)] mkdir /data/user/0/com.my.app.dev.debug/cache/WebView/Crashpad: 没有那个文件或目录 (2)

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

2019-11-18 16:58:45.237 21492-21658/com.my.app.dev.debug E/AssetHelper: 无法打开资产路径:dist/

这是唯一与 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的情况。这个设置是高度不建议的,因为它允许javascript使用CORS。如果您在WebView中加载第三方内容,则会存在安全风险,因为它使任何javascript代码都能够访问任何私有应用程序文件。实际上,这正是WebViewAssetLoader试图解决的主要问题,因此当您正在使用WebViewAssetLoader时,您不需要设置allowUniversalAccessFromFileURLs = true,实际上也不应该这样做。
另外,为了使事情更加安全,如果您使用WebViewAssetLoader访问所有本地应用程序资产文件,您还应将其设置为false:
webView!!.settings.allowFileAccess = false

谢谢提供这些信息,对我来说非常有价值。另一方面,原来WebView运行的网站是一个使用哈希作为路由模型的Angular应用程序,因此第一次运行应用程序时会重定向到/assets/dist/#,这似乎与WebViewAssetLoader拦截器冲突,我过滤了该重定向并使一切正常运行。 - CSharper
关于 WebViewAssetLoader 和 API 级别,感谢您澄清了它的工作版本,但我遇到了一个与 WebViewClient 配置相关的问题,“shouldInterceptRequest” 在尝试访问 request.url 时显示错误,要求至少 API 21。 - CSharper
很高兴这有所帮助,我更新了我的答案,因为我无法在评论中很好地添加代码块。 - zshmawy
另外一点评论,如果您的所有Web应用程序文件都存储在assets下,则不需要添加.addPathHandler("/res/", ResourcesPathHandler(this) - zshmawy
我也很好奇事情最终是怎么样的,新安装后的崩溃是否停止了?当你将重定向请求过滤到“dist”时是否停止了?或者你也更新了 WebView 吗?如果它在你过滤掉重定向后立即停止了,那就不太好了。我认为最好使用此链接[这里](https://issuetracker.google.com/issues/new?component=460423&template=1157790)向 Google 的 androidx.webkit 团队报告。 - zshmawy
是的,在我过滤了根哈希重定向之后,它停止崩溃了。我还留下了一份报告:https://issuetracker.google.com/issues/144925597。 - CSharper

0
在我的情况下,问题与URL缺少https方案有关。这意味着我需要刷新才能看到我的Android资产加载。 之前
webview.loadUrl("www.example.com/my/asset/path")

之后

webview.loadUrl("https://www.example.com/my/asset/path")

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