【问题标题】:Android Webview loads only on certain devicesAndroid Webview 仅在某些设备上加载
【发布时间】:2020-05-13 16:58:29
【问题描述】:

在某些设备上的 Webview 上加载 URL 时我遇到了一些问题:例如一般的模拟器(Nexus 5、Android API 21)和真实设备(华为 P30、Android 10)。

编辑:我使用的是 minSDK 19。网址是 https 方案。

binding.webview.apply {
        settings.javaScriptEnabled = true
        settings.loadWithOverviewMode = true
        settings.domStorageEnabled = true
        settings.databaseEnabled = true
        settings.setRenderPriority(WebSettings.RenderPriority.HIGH)
        settings.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK
        settings.setAppCacheEnabled(true)
        settings.layoutAlgorithm = WebSettings.LayoutAlgorithm.NARROW_COLUMNS
        settings.useWideViewPort = true
        settings.enableSmoothTransition()

        webViewClient = object : WebViewClient() {
            override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
                writeData(getString(XXX).toString())
                super.onPageStarted(view, url, favicon)
                binding.layoutProgress.progressLayout.show()
            }

            override fun onPageFinished(view: WebView?, url: String?) {
                super.onPageFinished(view, url)
                binding.layoutProgress.progressLayout.invisible()
            }
        }
    }

我正在 localStorage 上编写需要通过 javascript 浏览器才能加载的内容。我不确定这是不是问题...

private fun writeData(value: String) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        binding.webview.evaluateJavascript(
            "localStorage.setItem('$XXX','$value');",
        ) { returnedValue -> Log.d("chromium1", "onReceiveValue: $returnedValue") } //returns null on the devices that does not work or value on the working devices
    } else {
        binding.webview.loadUrl("javascript:localStorage.setItem('$XXX','$value');")
    }
}

在未加载的设备上出现的chromium 错误是:

"Uncaught SecurityError: Failed to read the 'localStorage' property from 'Window': Access is denied for this document.",
"Unrecognized Content-Security-Policy directive 'navigate-to'. ", source: url.com (0)
"Unrecognized Content-Security-Policy directive 'navigate-to'.   ", source: url.com (0)
"The key "shrink-to-fit" is not recognized and ignored.", source: url.com (5)
"Refused to load the stylesheet 'https://fonts.googleapis.com/css?family=Source+Code+Pro:300,600&display=swap' because it violates the following Content Security Policy directive: "style-src 'self' 'unsafe-inline' https://widget.freshworks.com blob:". ", source: url.com (11)
"Uncaught SyntaxError: Use of const in strict mode.", source: url.something.js (21)

非常感谢您。

【问题讨论】:

  • 请详细说明“某些设备”以帮助解决问题。它只发生在特定的设备品牌上吗?或者可能在某些 API 版本上?
  • 非常感谢。我用一些设备更新了评论。
  • 这里只是一个想法,但它可能与您的权限设置有关吗?如果这些未在 android 清单中列出,您将遇到问题。
  • 如果您在 Chromium 浏览器中检查其他设置怎么办? stackoverflow.com/questions/30481516/…(和类似链接)。

标签: android kotlin webview chromium


【解决方案1】:

如果您想要一致性和可靠性,不妨试试 GeckoView。它是由 Mozilla Firefox 团队构建的替代 WebView 库,用于使页面在所有设备上的行为相同。

不确定您是否会在这些设备上遇到相同的铬错误。

目前支持Android 4.3+,API 18+

https://wiki.mozilla.org/Mobile/GeckoView

【讨论】:

  • 我会马上尝试并告诉你。非常感谢。
  • 我的 BINDER 交易失败。请问有没有办法在 GeckoView 上实现发布的代码?
  • 听起来像是一个改进。看stackoverflow.com/a/23424889/974045你传递的数据有多大?尝试用一小段数据进行一次测试。
  • 有没有办法可以发布从 webview 到 geckoview 的翻译?我仍然收到错误消息。谢谢。
  • 我没有直接使用它,祝你好运。如果您拥有正在加载的网站,您也可以通过 url ?param=1 传递您的值并使用本机网络存储或在每次新访问时传递它并将值存储在您的应用中
【解决方案2】:

这可能是因为使用 webview 加载的 url。

  1. 将@xml/network_security_config 添加到您的资源中:

     <network-security-config>
        <base-config cleartextTrafficPermitted="true">
            <trust-anchors>
                <certificates src="system" />
                <certificates src="user"/>
            </trust-anchors>
        </base-config>
    </network-security-config>
    
  2. 将此安全配置添加到您的清单中,如下所示:

    <application
        ...
        android:networkSecurityConfig="@xml/network_security_config"
        ...>
    
        ...
    </application>
    

【讨论】:

  • 不幸的是,我忘了提到我使用的是 minSDK 19。这适用于 24 及更高版本,对吧?
  • @Amg91 是的,此解决方案适用于最新的操作系统版本。
【解决方案3】:

第一个错误似乎是您没有给出访问缓存路径

Uncaught SecurityError: Failed to read the 'localStorage' property from 'Window': Access is denied for this document."

如果我没记错的话,为了将数据存储在缓存中,我们必须通过setAppCachePath 显式授予访问权限。

描述如下。

设置应用程序缓存文件的路径。为了 要启用的应用程序缓存 API,必须使用此方法调用此方法 应用程序可以写入的路径。这种方法应该只 调用一次:重复调用被忽略。

路径可能是这样的(可能不完全相同)。

val cache_path = getApplicationContext().getFilesDir().getAbsolutePath() + "/cache"

settings.setAppCacheEnabled(true)
settings.setAllowFileAccess(true)
settings.setAppCachePath(cache_path)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-02-11
    • 2011-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-08
    • 1970-01-01
    • 2011-11-04
    相关资源
    最近更新 更多