Search code examples
androidkotlinwebviewandroid-webview

Android WebView failing only the very first time


I have an Android App that show a local-assets website, it only has 1 activity with the common webview:

I'm using WebViewAssetLoader as a local way to serve the files, the problem I'm facing which it's tremendously frustrating is when the app it's installed the very first time it fails loading the content in the WebView, if I kill the application and run it again it works perfectly (but I cannot say users to do that), also If the application is installed second time by Android studio, it works, but if the application has never been installed it always fails.

This is the result of logcat

2019-11-18 16:58:40.439 21492-21492/? E/Zygote: isWhitelistProcess - Process is Whitelisted 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: Failed to get gpu service 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: No such file or directory (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: No such file or directory (2) 2019-11-18 16:58:45.237 21492-21658/com.my.app.dev.debug E/AssetHelper: Unable to open asset path: dist/

This is the code that loads the 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)
    }
}

I researched and it turns out that was a known bug related to this issue, but it was solved for newer versions of Chrome, I'm performing testing on a Galaxy Note10 with the Android API 28 (latest)

Has anyone faced a similar issue? Any clue will be appreciated.


Solution

  • My answer doesn't directly solve your problem since it requires more context (more logs and what webview package and version you are using), but hope this may help.

    2019-11-18 16:58:40.439 21492-21492/? E/Zygote: isWhitelistProcess - Process is Whitelisted 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: Failed to get gpu service

    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: No such file or directory (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: No such file or directory (2)

    These logs aren't why the crash is happening, it's a problem with the WebView itself and doesn't have anything to do with WebViewAssetLoader. So make sure to update to the latest WebView and Chrome version on your device (WebView is updated regularly via app store unlike android framework). To make sure that this is not a WebViewAssetLoader issue, try to build the same app without all WebViewAssetLoader code and see if the same crashes still happen.

    2019-11-18 16:58:45.237 21492-21658/com.my.app.dev.debug E/AssetHelper: Unable to open asset path: dist/

    This is the only line that is related to androidx.webkit.WebViewAssetLoader. I assume the content you are loading is trying to open a folder /assets/dist/ that doesn't exist. However, this should not cause any crashes.


    Aside from this, there are couple of notes on your code:

    • You don't have to guard WebViewAssetLoader for API level >= 21, you should be able to use it for API >= 14.

    For WebViewClient#shouldInterceptRequest, it would be nicer if you override two versions of the method instead of giving up using WebViewAssetLoader entirely for older APIs:

    @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))
    }
    
    • Don't set this setting to true:
      webView!!.settings.allowUniversalAccessFromFileURLs = true
    

    I assume you're enabling this setting for the case when WebViewAssetLoader isn't used. This setting is highly discouraged because it allows CORS for javascript. This would be a security risk if you ever load 3rd party content in your WebView as it makes any javascript code capable of accessing any private app file. This is actually the main issue WebViewAssetLoader is trying to solve, so you don't need to - and actually shouldn't - set allowUniversalAccessFromFileURLs = true when you are using WebViewAssetLoader.

    In addition, and to make things even safer, if you access all local app assets files using WebViewAssetLoader, you should also set this to false:

    webView!!.settings.allowFileAccess = false