美文网首页二次打包Android知识Android技术知识
Android RemoteView 资源ID索引错误解决方案

Android RemoteView 资源ID索引错误解决方案

作者: 古月XYZ | 来源:发表于2016-10-21 15:07 被阅读564次

应用升级时,如果替换了通知的 RemoteView 中的资源文件,则可能会导致新的升级包资源 id 发生变动,在部分机型上体现为android.app.RemoteServiceException的崩溃。崩溃日志大致如下:

Bad notification posted from package com.mypkg.name: Couldn't create icon: StatusBarIcon(pkg=com.mypkg.name user=0 id=0x7f0200dc level=0 visible=true num=0 )
android.app.ActivityThread$H.handleMessage(ActivityThread.java:1638) 
android.os.Handler.dispatchMessage(Handler.java:111) 
android.os.Looper.loop(Looper.java:194) 
android.app.ActivityThread.main(ActivityThread.java:5637) 
java.lang.reflect.Method.invoke(Native Method) 
java.lang.reflect.Method.invoke(Method.java:372) 
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:960) 
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

前段时间升级直接导致 crash 收集平台被该 bug 刷屏,而测试过程又一次都没有复现。StackOverFlow 上也没有太好的解决方案。这里探索了一种固化资源 id 的解决方案,线上验证也是可行的,bug率明显下降。

通过反编译可以发现,Android App 会在 res/values/public.xml 里存储所有的资源文件名到资源文件 id 的映射关系。如果在编译前手动添加部分资源的 id 到 public.xml 下,那么这些资源的 id 就得以固化,升级以及添加修改资源都不会对这些 id 产生影响。此外,res/values/ids.xml 也起到了类似作用,只不过仅覆盖 id 资源。

因此,解决思路应该是反编译 Apk 包,获得最新的public.xml,讲所有RemoteView涉及到的资源文件,包括string, dimen, drawable, id, layout等,提取出来并保存在项目源码中的res/values/public.xmlres/values/ids.xml文件中。

注意:Gradle 自 1.3.0 以后版本编译时会默认忽略本地的 public.xml 文件,因此还需要添加 Gradle 脚本使 public.xml 生效。打开 app 的 build.gradle 文件,在最后添加如下脚本 (参考连接中也提到了利用 Gradle 插件的解决方案):

afterEvaluate {
    for (variant in android.applicationVariants) {
        def scope = variant.getVariantData().getScope()
        String mergeTaskName = scope.getMergeResourcesTask().name
        def mergeTask = tasks.getByName(mergeTaskName)

        mergeTask.doLast {
            copy {
                int i=0
                from(['res']) {
                    include 'values/public.xml'
                    rename 'public.xml', (i == 0? "public.xml": "public_${i}.xml")
                    i++
                }

                into(mergeTask.outputDir)
            }
        }
    }
}

Update 2016.11.09

  1. 如果需要对submodule中的资源增加id固化,则可以在上面代码['res']中增加相应资源路径即可。
  2. 如果上述方法仍然失效,则只能用最sb的办法了:把submodule需要固化的资源在主工程下固化

参考:

  1. android gradle plugin 1.3.0 以上使用 public.xml 固定 id

相关文章

网友评论

  • 碎念枫子:我也遇到了 ,有一个版本升级的时候我替换了一些图片,但是并不是remoteView的资源。在接下来的版本中每个版本都有找不到资源的错误 (少量非必现)。但是这个错误并不单指向那些修改的图片有些是找不到颜色 有些找不到xml文件 有些找不到系统的资源文件 不知道该怎么处理。反编译apk文件资源是存在的
    古月XYZ:你这可能是另外一种问题. 我们应用也遇到过, 当时做了一个很挫的解决方法是吧相关资源调用推迟几秒, 线上看 crash 是没了
  • c6909b7c95c8:请问这个问题 在源码中是怎么触发到这个崩溃的呢?
    古月XYZ:目前还未找到触发 bug 的源码, 只是因为机制猜测这个原因并线上验证成功了. 当然, 不排除不做任何修复 bug 也会自愈的可能.

本文标题:Android RemoteView 资源ID索引错误解决方案

本文链接:https://www.haomeiwen.com/subject/mdqcuttx.html