最近在研究Android应用的插件化开发,看了好几个相关的开源项目。插件化都是在解决以下几个问题:

就这几个问题,我开始研究插件化开发实现的相关技术。 在上篇文章中我讲了如何把插件apk中的class加载到当前进程 的问题,本篇文章主要讲第一点的第二点:如何加载另一个apk中的资源到当前应用中。

AssetManager介绍

当我们在组件中获取资源时使用getResource获得Resource对象,通过这个对象我们可以访问相关资源,比如文本、图片、颜色等。通过跟踪源码发现,其实 getResource 方法是Context的一个抽象方法, getResource的实现是在ContextImp中实现的。获取的Resource对象是应用的全局变量,然后继续跟踪源码,发现 Resource 中有一个AssertManager的全局变量,在Resource的构造函数中传入的,所以最终获取资源都是通过 AssertManager 获取的,于是我们把注意力放到AssertManager上。我们要解决下面两个问题。

一、如何获取 AssertManager 对象。

二、如何通过 AssertManager 对象获取插件中apk的资源。

通过对 AssertManager 的相关源码跟踪,我们找到答案。

一、AssertManager 的构造函数没有对 api 公开,不能使用 new 创建;context .getAssets() 可用获取当前上下文环境的 AssertManager;利用反射 AssetManager.class.newInstance() 这样可用获取对象。

二、如何获取插件 apk 中的资源。我们发现 AssetManager 中有个重要的方法。

/** Add an additional set of assets to the asset manager. * This can be either a directory or ZIP file.
* Not for use by applications. Returns the cookie of the added asset, * or 0 on failure.
*@{hide}
*/
public native final int addAssetPath(String path);

我们可以把一个包含资源的文件包添加到assets中。这就是AssertManager查找资源的第一个路径。这个方法是一个隐藏方法,我们可以通过反射调用。

AssetManager assetManager = AssetManager.class.newInstance() ; // context .getAssets()?
AssetManager.class.getDeclaredMethod("addAssetPath", String.class).invoke(assetManager, apkPath);

上文提到,我们可以获取当前上下文的 AssetManager,也可以通过反射创建一个 AssetManager。我们这里本文分析的是后一种。第一种能不能呢,这个问题留给读者先去思考,后续文章会单独讨论。 详细了解可以参考老罗的文章 《Android应用程序资源管理器(Asset Manager)的创建过程分析》 。下面我们来写一个demo:获取插件的文本资源和图片资源。

创建一个插件apk工程module:apkbeloaded

我把插件的包名命名为:laodresource.demo.com.loadresourcedemo。

第一步:

这个工程中我们可以不用写任何代码。在drawable目录下放一张图片:icon_be_load.png。

在string中定义字符串:<string name=”text_beload”>I am from apkBeLoaded</string>。

第二步:

打包生成apk:apkbeloaded-debug.apk。

拷贝到测试机文件路径下:$ adb push <你的路径>/apkbeloaded-debug.apk sdcard/

创建一个宿主apk工程

在布局文件中定义一个文本控件和一个图片控件,分别用来显示插件中获取的文本和图片。

<ImageView android:layout_width="wrap_content"
android:src="@mipmap/ic_launcher"
android:id="@+id/icon"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/text"
android:text="Hello World!"
android:layout_below="@+id/icon"
android:layout_centerInParent="true"
/>

MainActivity.javaonCrease:

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ImageView imageView = (ImageView) findViewById(R.id.icon);
TextView textView = (TextView) findViewById(R.id.text); /**
* 插件apk路径
*/
String apkPath = Environment.getExternalStorageDirectory()+"/apkbeloaded-debug.apk";
/**
* 插件资源对象
*/
Resources resources = getBundleResource(this,apkPath);
/**
*获取图片资源
*/
Drawable drawable = resources.getDrawable(resources.getIdentifier("icon_be_load", "drawable",
"laodresource.demo.com.apkbeloaded"));
/**
* 获取文本资源
*/
String text = resources.getString(resources.getIdentifier("text_beload","string",
"laodresource.demo.com.apkbeloaded")); imageView.setImageDrawable(drawable);
textView.setText(text); }

创建Resource对象:

public Resources getBundleResource(Context context, String apkPath){
AssetManager assetManager = createAssetManager(apkPath);
return new Resources(assetManager, context.getResources().getDisplayMetrics(), context.getResources().getConfiguration());
}

创建AssetManager对象:

private AssetManager createAssetManager(String apkPath) {
try {
AssetManager assetManager = AssetManager.class.newInstance();
AssetManager.class.getDeclaredMethod("addAssetPath", String.class).invoke(
assetManager, apkPath);
return assetManager;
} catch (Throwable th) {
th.printStackTrace();
}
return null;
}

Demo源码: https://github.com/liuguangli/LoadResourceDemo

Android应用程序插件化研究之AssertManager的更多相关文章

  1. 蘑菇街Android组件与插件化

    插件化的基石 -- apk动态加载 随着我街业务的蓬勃发展,产品和运营随时上新功能新活动的需求越来越强烈,经常可以听到"有个功能我想周x上,行不行".行么?当然是不行啦,上新功能得 ...

  2. 携程Android App的插件化和动态加载框架

    携程Android App的插件化和动态加载框架已上线半年,经历了初期的探索和持续的打磨优化,新框架和工程配置经受住了生产实践的考验.本文将详细介绍Android平台插件式开发和动态加载技术的原理和实 ...

  3. iOS插件化研究之中的一个——JavaScriptCore

    原文:p=191">http://chentoo.com/?p=191 一.前言 一样的开篇问题,为什么要研究这个?iOS为什么要插件化?为什么要借助其它语言比方html5 js甚至脚 ...

  4. android app 的插件化、组件化、模块化开发-2

    Android 插件化 ——指将一个程序划分为不同的部分,比如一般 App的皮肤样式就可以看成一个插件 Android 组件化 ——这个概念实际跟上面相差不那么明显,组件和插件较大的区别就是:组件是指 ...

  5. android app 的插件化、组件化、模块化开发

    Android 插件化 ——指将一个程序划分为不同的部分,比如一般 App的皮肤样式就可以看成一个插件 Android 组件化 ——这个概念实际跟上面相差不那么明显,组件和插件较大的区别就是:组件是指 ...

  6. 有关Android插件化思考

    最近几年移动开发业界兴起了「 插件化技术 」的旋风,各个大厂都推出了自己的插件化框架,各种开源框架都评价自身功能优越性,令人目不暇接.随着公司业务快速发展,项目增多,开发资源却有限,如何能在有限资源内 ...

  7. 携程Android App插件化和动态加载实践

    携程Android App的插件化和动态加载框架已上线半年,经历了初期的探索和持续的打磨优化,新框架和工程配置经受住了生产实践的考验.本文将详细介绍Android平台插件式开发和动态加载技术的原理和实 ...

  8. Android Small插件化框架解读——Activity注册和生命周期

    通过对嵌入式企鹅圈原创团队成员degao之前发表的<Android Small插件化框架源码分析>的学习,对Android使用的插件化技术有了初步的了解,但还是有很多需要认真学习的地方,特 ...

  9. Android插件化的兼容性(中):Android P的适配

    Android系统的每次版本升级,都会对原有代码进行重构,这就为插件化带来了麻烦. Android P对插件化的影响,主要体现在两方面,一是它重构了H类中Activity相关的逻辑,另一个是它重构了I ...

随机推荐

  1. 多线程面试题(Google)

    有四个线程1.2.3.4.线程1的功能就是输出1,线程2的功能就是输出2,以此类推.........现在有四个文件ABCD.初始都为空.现要让四个文件呈如下格式: A:1 2 3 4 1 2.... ...

  2. JFreeChart学习

    一.步骤: 创建数据集(准备数据) 根据数据集生成JFreeChart对象,并对其做相应的设置(标题,图例,x轴,Y轴,对象渲染等) 将JFreeChart对象输出到文件或者Servlet输出流等 二 ...

  3. 查看db2表空间使用率

    select char(TABLESPACE_NAME,16) tablespace_name,decimal(PAGE_SIZE/1024,4,2) page,used_pages*100/usab ...

  4. Create a simple REST web service with Python--转载

    今日尝试用python建立一个restful服务. 原文地址:http://www.dreamsyssoft.com/python-scripting-tutorial/create-simple-r ...

  5. (原)Mac下Apache添加限制IP线程模块:mod_limitipconn.so

    1.下载:http://dominia.org/djao/limit/mod_limitipconn-0.24.tar.bz2 解压到一个目录:我的是~/Download/mod_limitipcon ...

  6. Bestcoder #47 B Senior&#39;s Gun

    Senior's Gun Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Tot ...

  7. css让div水平垂直居中

    示例1: .div1{ width:200px; height:300px; border:1px solid #000; position: relative; } .div2{ width: 40 ...

  8. 颜色矩阵 滤镜 ColorMatrix

    颜色矩阵原理 色彩的三要素 1.色相.色相通俗的说就是"颜色",色相的改变就是颜色的改变,色相的调节伴随着红橙黄绿蓝紫的变化. 2.亮度.明度通俗的说就是"光照度&quo ...

  9. NUnit单元测试初试

    创建项目,创建几个方法 创建测试类 开启NUnit测试工具,新建一个测试项目 打开测试的程序集 选择节点,点击测试,绿色通过,红色说明有错误

  10. JavaScript绑定事件的方法[3种]

    在JavaScript中,有三种常用的绑定事件的方法: 在DOM元素中直接绑定: 在JavaScript代码中绑定: 绑定事件监听函数. 一. 在DOM元素中直接绑定 这里的DOM元素,可以理解为HT ...