前言
只能说是巨坑,线上app在升级覆盖安装的时候闪退了,主要错误如下。这看的有点纳闷了,百度了一下众说纷纭,有说是:
1、图片资源太大了
2、类型不对,只能是png
3、设置通知栏图标不能直接用R引用资源,要使用ApplicationInfo#icon
字段,否则会导致使用id的时候资源实际上还没有加载
4、id是变化的,安装前发的通知使用的id安装后不存在了或者类型不对了。
试了第三种是没效果的,1没去试过、2现在用的图片本来就是png,个人认可第四种。
android.app.RemoteServiceException$BadForegroundServiceNotificationException:
Bad notification(tag=null, id=31270303) posted from package xxxx,
crashing app(uid=10401, pid=10435):
Couldn't create icon StatusBarIcon(icon=Icon(typ=RESOURCE pkg=xxx id=0x7f0e0000) visible user=0 )
排查
使用工具搜搜这个id,在旧版本中0x7f0e0000
对应的app的logo。而在线上版本中,果然这个id被一个menu资源使用了,原本的mipmap资源变成了OF
,原logo变成了0x7f0f0000
。
按之前找的资料,用户的旧版本本地的id是确认了的,只有保证线上的id不变才可能解决这个闪退。虽然不太了解原理,但是大致还是知道id是aapt/aapt2生成的,且生成的id不一定一样的,猛然惊醒,因为线上从来没有这样闪退过。再去对比旧版本的资源文件,发现旧版本就从来没有使用menu
资源,所以打包的时候到mipmap
刚好一直就是OE
,多了menu
占用了OE
。
这里猜测,aapt2(项目用的这个)生成的时候应该是按资源名字字母排序去生成的,内部估计优先级也是按字母排的。
排查到这里人一整个裂开…之前一直没怎么改过资源项目几年了都没有出现过这个问题。
解决
第一个想法是看能不能固定某些id,那只能从aapt2上面下手了。搜索了下大部分都是aapt的且aapt2不适用,aapt2的也有不过总不能手动操作吧,用gradle插件实现的话。。版本太高了,搜到的方法都不支持,整个人都不好了。
转机出现了,搜索发现aapt提供了参数可以使用固定id。如果没有配置文件,build会生成一个字段id的中间文件,如果有这个文件就按这个文件id去生成。可以先自动生成一次,把需要固定的id保留,其他的删除就好了
android {
aaptOptions {
File publicTxtFile = project.rootProject.file('public.txt')
//public文件存在,则应用,不存在则生成
if (publicTxtFile.exists()) {
//aapt2添加--stable-ids参数应用
aaptOptions.additionalParameters("--stable-ids", "${publicTxtFile}")
} else {
//aapt2添加--emit-ids参数生成
aaptOptions.additionalParameters("--emit-ids", "${publicTxtFile}")
}
}
}
文件的内容大致是这种格式
包名:mipmap/app_icon = 0x7f0e0000
重新打包后再看一下app的的id资源,menu
和mipmap
id顺序倒转了。最终id还是保持一致了。