Android插件ResourcesNotFoundException

背景

之前遇到过一种ResourceNotFoundException,是因为在WebView初始化的时候,AssetManager被重新创建了,所有被添加的插件APK路径都被清空了,所以导致资源找不到。

而这次遇到了两个问题,都是资源ID可以找到,而Context无法找到ID对应的资源

  • WindowManagerService.applyAnimationLocked
  • Activity.setContentView

以及在7.0以上Asset中的资源可以找到,而8.0系统的Asset资源无法找到

  • AssetManager.open FileNotFoundException

WindowManagerService.applyAnimationLocked

当Activity被finish的时候,会出现Crash,而问题日志如下:

11-30 13:11:31.701 1250-1338/? A/WindowManager: Unhandled exception while laying out windows
    android.content.res.Resources$NotFoundException: Resource ID #0x7a04001d
        at android.content.res.Resources.getValue(Resources.java:1375)
        at android.content.res.Resources.loadXmlResourceParser(Resources.java:2894)
        at android.content.res.Resources.getAnimation(Resources.java:1191)
        at android.view.animation.AnimationUtils.loadAnimation(AnimationUtils.java:73)
        at com.android.server.wm.OppoAppTransition.loadAnimation(OppoAppTransition.java:192)
        at com.android.server.wm.OppoAppTransition.createOppoCustomAnimLocked(OppoAppTransition.java:376)
        at com.android.server.wm.OppoAppTransition.loadAnimation(OppoAppTransition.java:242)
        at com.android.server.wm.WindowManagerService.applyAnimationLocked(WindowManagerService.java:3804)
        at com.android.server.wm.WindowManagerService.setTokenVisibilityLocked(WindowManagerService.java:4898)
        at com.android.server.wm.WindowManagerService.handleAppTransitionReadyLocked(WindowManagerService.java:9902)
        at com.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLockedInner(WindowManagerService.java:10669)
        at com.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLockedLoop(WindowManagerService.java:9461)
        at com.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLocked(WindowManagerService.java:9403)
        at com.android.server.wm.WindowManagerService.access$400(WindowManagerService.java:203)
        at com.android.server.wm.WindowManagerService$H.handleMessage(WindowManagerService.java:8282)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:179)
        at android.os.HandlerThread.run(HandlerThread.java:61)

跟踪问题

  1. 通过Android Studio解开插件的APK确认:

    • 资源的类型
    • 资源的ID
  2. 根据ID找到对应的资源名称确认:

    • 插件的APK中是存在这个资源的
    • AAPT将ID和资源名都打进了resources.arsc中。
  3. 搜索资源的引用:

    • 发现在Activity的Theme中的activityOpenEnterAnimation中使用了该动画
  4. 将该资源替换之后,发现还是报同样的错误

  5. 最后发现在Activity结束的时候,会在overridePendingTransition中使用该资源,导致的Crash

    overridePendingTransition

原因

因为在ActivityManagerService带过去的PackageName是主包的PackageName,而不是插件的,所以在主包的resource.arsc中找不到对应的插件资源ID,所以导致的Crash。

解决方案

将使用到的资源,放置到主包即可

Activity.setContentView

当启动Activity的时候,发生Crash,日志如下:

2018-12-05 19:45:14.068 16411-16411/? E/TAG: Crash
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.exapmle.test/com.example.test.TestActivity}: android.content.res.Resources$NotFoundException: Resource ID #0x7f0300f9
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2855)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2930)
        at android.app.ActivityThread.-wrap11(Unknown Source:0)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1619)
        at android.os.Handler.dispatchMessage(Handler.java:105)
        at android.os.Looper.loop(Looper.java:171)
        at android.app.ActivityThread.main(ActivityThread.java:6684)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:246)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:783)
     Caused by: android.content.res.Resources$NotFoundException: Resource ID #0x790300f9
        at android.content.res.ResourcesImpl.getValue(ResourcesImpl.java:211)
        at android.content.res.MiuiResourcesImpl.getValue(MiuiResourcesImpl.java:91)
        at android.content.res.Resources.loadXmlResourceParser(Resources.java:2158)
        at android.content.res.Resources.getLayout(Resources.java:1156)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:425)
        at android.view.LayoutInflater.inflate(LayoutInflater.java:374)
        at com.android.internal.policy.PhoneWindow.setContentView(PhoneWindow.java:418)
        at android.app.Activity.setContentView(Activity.java:2713)

问题追踪

  1. 当Activity启动的时候,调用setContentView
  2. setContentView中创建PhoneWindow对象,在PhoneWindow对象中,会调用LayoutInflater.inflate来解析layout文件
  3. LayoutInflater.inflate函数中会通过getContext().getResources().getLayout()来获取XmlResourceParser对象
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) {
        final Resources res = getContext().getResources();
        if (DEBUG) {
            Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
                    + Integer.toHexString(resource) + ")");
        }

        final XmlResourceParser parser = res.getLayout(resource);
        try {
            return inflate(parser, root, attachToRoot);
        } finally {
            parser.close();
        }
    }

解决方案

只需要重写Activity中的getResources(),返回添加了路径的Resources对象即可,从添加了路径的Resources对象中获取layout文件就可以找到这个文件了。

AssetManager.open

在项目后期,发现了在Androidi 系统7.0的手机上可以找到Asset资源,而8.0手机无法找到Asset资源的问题。由于插件资源路径是通过Resource中的AssetManager反射调用addAssetPath函数加入插件APK路径直接注入的,所以如果AssetManager不对,则无法获取。

打印日志后发现:

  • 8.0版本日志:
    Activity的Resource与注入的Application的Resource对象是同一个,但是从Activity中直接获取的AssetManager与Application、Context.getResource中的不是同一个。
2018-12-06 19:34:58.865 26210-26954/? E/GLSurfaceView: Context context:com.example.TestActivity@72e38ee
2018-12-06 19:34:58.865 26210-26954/? E/GLSurfaceView: Context Resource:android.content.res.MiuiResources@47759b2   ApplicationResource:android.content.res.MiuiResources@47759b2
2018-12-06 19:34:58.865 26210-26954/? E/GLSurfaceView: 
// Activity.getAsset()
Activity Asset:android.content.res.AssetManager@5d19d03  
// Activity.getResource().getAsset()
ContextResource Asset:android.content.res.AssetManager@b68f480  
// Application.getResource().getAsset()
Application Asset:android.content.res.AssetManager@b68f480
  • 7.x版本日志:
    可以发现,7.x的手机上获取到的AssetManager都是同一个,所以不会出现FileNotFound的问题。
2018-12-06 19:58:22.771 7971-9450/? E/GLSurfaceView: Context context:com.example.TestActivity@17d6008
2018-12-06 19:58:22.771 7971-9450/? E/GLSurfaceView: Context Resource:android.content.res.HwResources@b16ed87   ApplicationResource:android.content.res.HwResources@b16ed87
2018-12-06 19:58:22.771 7971-9450/? E/GLSurfaceView: 
// Activity.getAsset()
Activity Asset:android.content.res.AssetManager@28c74b4  
// Activity.getResource().getAsset()
ContextResource Asset:android.content.res.AssetManager@28c74b4  
// Application.getResource().getAsset()
Application Asset:android.content.res.AssetManager@28c74b4

解决方案

只需要将Activity中获取getResources()getAsset()重写即可,将对应的Resources以及AssetManager返回正确,就不会出现FileNotFoundException了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容