解决 Android WebView 多进程导致App崩溃

应用场景

应用内有两个位置用到WebView加载页面,具体处理逻辑不能通用。分别扩展了WebView了。应用内独立页面使用Fragment来展示,(采用单Activity架构)。应用提供切换语言功能

问题猜想

一、WebView内核bug

具体路径:
进入app–>设置-切换语言(应用界面重新加载)-再次进入设置->跳转到WebViewFragment展示H5。随便操作滑动。退出上一页。重复该操作,会引发应用crash

MI 10 输出error 日志。

请添加图片描述

] Failed to create directory: /data/user/0/com.codeview.miniparty/cache/WebView/Default/HTTP Cache/Code Cache/js
D  Compat change id reported: 171228096; UID 10728; state: ENABLED
I  QUALCOMM build                   : db3d445dbc, Ia06b22fa1a
   Build Date                       : 10/04/21
   OpenGL ES Shader Compiler Version: EV031.32.02.16
   Local Branch                     : 
   Remote Branch                    : 
   Remote Branch                    : 
   Reconstruct Branch               : 
I  Build Config                     : S P 10.0.7 AArch64
I  Driver Path                      : /vendor/lib64/egl/libGLESv2_adreno.so
W  Application attempted to call on a destroyed WebView
   java.lang.Throwable
    at org.chromium.android_webview.AwContents.m(chromium-TrichromeWebViewGoogle6432.aab-stable-530410534:10)
    at com.android.webview.chromium.WebViewChromium.addJavascriptInterface(chromium-TrichromeWebViewGoogle6432.aab-stable-530410534:25)
    at android.webkit.WebView.addJavascriptInterface(WebView.java:1928)
    at miui.contentcatcher.sdk.utils.WebViewUtils$NativeWebViewUtils.addJavascriptInterface(WebViewUtils.java:244)
    at miui.contentcatcher.sdk.utils.WebViewUtils.initWebViewJsInterface(WebViewUtils.java:157)
    at miui.contentcatcher.InterceptorProxy$1.run(InterceptorProxy.java:193)
    at android.os.Handler.handleCallback(Handler.java:938)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loopOnce(Looper.java:210)
    at android.os.Looper.loop(Looper.java:299)
    at android.app.ActivityThread.main(ActivityThread.java:8293)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:556)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1045)

网上找到chrome 官方issue问题。
https://bugs.chromium.org/p/chromium/issues/detail?id=558377
该问题一直追踪到2021年也并没有给出具体的解决方案。

快速操作界面开关,导致WebView异常,引发应用闪退

在红米K40上(Android 12)显示

请添加图片描述

Build fingerprint: 'Verizon/kltevzw/kltevzw:5.0/LRX21T/G900VVRU2BOE1:user/release-keys'
Revision: '14'
ABI: 'arm'
pid: 30968, tid: 30968, name: com.myapp >>> com.myapp <<<
signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
Abort message: '[FATAL:jni_android.cc(295)] Check Failed: false. Please include Java exception stack in crash report
'
r0 00000000 r1 000078f8 r2 00000006 r3 00000000
r4 b6f5c114 r5 00000006 r6 0000000b r7 0000010c
r8 b6f3be04 r9 bec21408 sl 00000000 fp bec213cc
ip 000078f8 sp bec20ee0 lr b6ee5fd1 pc b6f09970 cpsr 600f0010

backtrace:
#00 pc 00037970 /system/lib/libc.so (tgkill+12)
#01 pc 00013fcd /system/lib/libc.so (pthread_kill+52)
#02 pc 00014beb /system/lib/libc.so (raise+10)
#03 pc 00011531 /system/lib/libc.so (__libc_android_abort+36)
#04 pc 0000fcbc /system/lib/libc.so (abort+4)
#05 pc 002a7569 /data/app/com.google.android.webview-2/lib/arm/libwebviewchromium.so 

这个问题在stackoverflows上找到另一个解决方
https://stackoverflow.com/questions/31416568/could-someone-help-me-with-this-crash-report

这个问题更像是应用内使用的场景,webView在Fragment中,快速打开关闭Fragment导致应用Crash。

在Application的AccachBaseContext(base:Context)中进行处理multiProcess

    override fun attachBaseContext(base: Context?) {
        super.attachBaseContext(base)
        WebViewMultiProcesspatch.apply {
            setDirectorySuffix(
                isSameProcess(this@SkyCastleApplication),
                getProcessName(this@SkyCastleApplication)
            )
        }
    }

新建一个WebViewMultiProcesspatch单例,用来做一些逻辑判断

/**
 * 
 * Date:   2022/11/29 19:00
 * Description:多进程闪退
 */


object WebViewMultiProcesspatch {

    /**
     * fix:Using WebView from more than one process at once with the same data directory is not supported
     * https://www.yisu.com/zixun/445583.html
     */
    fun tryLockOrRecreateFile(context: Context, processName: String) {
        val filePath =
            context.dataDir.absolutePath + "/${processName}/app_webview/webview_data.lock"
        File(filePath).let {
            if (it.exists()) {
                try {
                    val tryLock = RandomAccessFile(it, "rw").channel.tryLock()
                    if (tryLock != null) {
                        tryLock.close()
                    } else {
                        createLockFile(it, it.delete())
                    }
                } catch (e: Exception) {
                    e.printstacktrace()
                    var delete = false
                    if (it.exists()) {
                        delete = it.delete()
                    }
                    createLockFile(it, delete)
                }
            }
        }
    }

    private fun createLockFile(file: File, delete: Boolean) {
        try {
            if (delete && !file.exists()) {
                file.createNewFile()
            }
        } catch (e: Exception) {
            e.printstacktrace()
        }
    }

    /**
     * fix:Using WebView from more than one process at once with the same data directory is not supported
     * https://www.jianshu.com/p/f3ccc065f632
     */
    fun setDirectorySuffix(isSameProcess: Boolean, processName: String?) {
        if (!isSameProcess) {
            //see https://developer.android.google.cn/about/versions/pie/android-9.0-changes-28#web-data-dirs
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && !processName.isNullOrBlank()) {
                WebView.setDataDirectorySuffix(processName)
            }
        }
    }


    fun isSameProcess(context: Context): Boolean {
        return getProcessName(context) == getPackageName(context)
    }

    fun getProcessName(cxt: Context): String? {
        val pid = Process.myPid()
        val am = cxt.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
        val runningApps = am.runningAppProcesses ?: return null
        for (procInfo in runningApps) {
            if (procInfo.pid == pid) {
                return procInfo.processName
            }
        }
        return null
    }
    private fun getPackageName(context: Context): String? {
        return context.packageName
    }

}

总结

Android 不仅需要对不同品牌的设备适配,还需要针对不同的系统版本做适配。会有比较多的问题定位不到具体原因。这种情况不但要平时多多积累,更好掌握解决问题的方案。

引用

  1. Android webView
  2. Android 9.0 行为变更
  3. Android如何解决WebView多进程崩溃的问题

原文地址:https://weichao.blog.csdn.net" target="_blank" rel="noopener" title="灯塔@kuaidao">灯塔@kuaidao</a> <img class="article-time-img article-heard-img" src="https://csdnimg.cn/release/blo

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Mip是什么意思以及作用有哪些
怎么测试Mip页面运行情况
MIP安装的具体步骤有哪些
HTML添加超链接、锚点的方法及作用详解(附视频)
MIP的规则有哪些
Mip轮播图组件中的重要属性讲解
Mip的内联框架组件是什么
怎么创建初始的MIP配置及模板文件
HTML实现多选框及无法提交多数据的原因分析(附视频)
HTML如何设置复选框、单选框以及默认选项?(图文+视频)
怎么使用MIP组件
Div垂直居中效果怎么实现
HTML如何实现视频在线播放
如何使用Mip代码校验工具
Mip中弹出层组件是什么
如何用HTML实现简单按钮样式
Mip中快速回顶组件怎么用
Div内容居中效果如何实现
Div水平居中效果怎么实现
Mip中列表组件怎么用