详解Android插件化开发-资源访问

本文深入探讨了Android插件化开发中如何访问未安装APK的资源文件。通过分析Android系统资源加载机制,指出由于R类限制,直接通过宿主程序的Context访问插件资源不可行。文章提出自定义Resources类并利用反射获取AssetManager来加载插件资源的方法,从而实现对未安装插件资源的访问。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    动态加载技术(也叫插件化技术),当项目越来越庞大的时候,我们通过插件化开发不仅可以减轻应用的内存和CPU占用,还可以实现热插拔,即在不发布新版本的情况下更新某些模块。
    通常我们把安卓资源文件制作成插件的形式,无外乎有一下几种:

zip、jar、dex、APK(未安装APK、安装APK)

    对于用户来讲未安装的APK才是用户所需要的,不安装、不重启,无声无息的加载资源文件,这正是我们开发者追求的结果。
    但是,开发中宿主程序调起未安装的插件apk,一个很大的问题就是资源如何访问,这些资源文件的ID都映射在gen文件夹下的R.java中,而插件中凡是以R开头的资源都不能访问。究其原因是因为宿主程序中并没有插件的资源,所以通过R来加载插件的资源是行不通的,程序会抛出异常:无法找到某某id所对应的资源。
    那么开发中该怎么办呢,今天我们来一起探讨一下插件化开发中资源文件访问的解决方案。
    想必大家在开发中都写过类似代码,例如,在主程序访问字符串文件

this.getResources().getString(R.string.app_name);

    这里的this,其实就是Context,上下文对象。通常我们的的APK安装路径为:

/data/apk/packagename~1/base.apk

    APK启动,Context通过类加载器加载完毕后,会去APK中加载资源文件。想必大家都知道,Activity的工作主要是通过ContextImpl来完成的, Activity中有一个叫mBase的成员变量,它的类型就是ContextImpl。注意到Context中有如下两个抽象方法,看起来是和资源有关的,实际上Context就是通过它们来获取资源的。这两个抽象方法的真正实现在ContextImpl中,也就是说,只要实现这两个方法,就可以解决资源问题了。

/** Return an AssetManager instance for your application's package. */

public abstract AssetManager getAssets();

/** Return a Resources instance for your application's package. */

public abstract Resources getResources();

    我们若是想使用这两个方法,需要实例化Context对象,通常我们可以根据APK中的包名完成Context对象的创建:

Context pluginContext = this.createPackageContext("com.castiel.demo",flags);

    但是这样做有个前提,必须要求初始化时加载的是自己APK,如果我们加载的是未安装的插件APK,这么做肯定就不可取了。为啥呢,看源码:

Resources resources = packageInfo.getResources(mainThread);
        if (resources != null) {
            if (activityToken != null
                    || displayId != Display.DEFAULT_DISPLAY
                    || overrideConfiguration != null
                    || (compatInfo != null && compatInfo.applicationScale
                            != resources.getCompatibilityInfo().applicationScale)) {
                resources = mResourcesManager.getTopLevelResources(packageInfo.getResDir(),
                        packageInfo.getSplitResDirs(), packageInfo.getOverlayDirs(),
                        packageInfo.getApplicationInfo().sharedLibraryFiles, displayId,
                        overrideConfiguration, compatInfo, activityToken);
            }
        }
        mResources = resources;

Resources在这里被赋值,我们再去代码中第一行的packageInfo,它来自LoadedApk

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值