Android应用程序插件化研究之AssertManager

最近在研究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

时间: 2024-11-06 14:23:52

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

iOS插件化研究之一——JavaScriptCore

原文:http://chentoo.com/?p=191 一.前言 一样的开篇问题,为什么要研究这个?iOS为什么要插件化?为什么要借助其他语言比如html5 js甚至脚本lua等来实现原本OC/Swift应该实现的东西? 原因可以归结为两点: 1. iOS平台 appstore 审核速度不可控,而很多活动页面需要频繁更新,如果每次更新都走appstore审核流程,那活动也就不要做了. 2. 可多平台复用代码,节省开发成本.比如同一个活动的页面,用html5+js完成,就可以通用的在iOS An

android 广播的插件化

------本文转载自 Android插件化原理解析--广播的管理 这一系列的文章实在是写的好! 1, 概述 为了实现Activity的插件化我们付出了相当多的努力:那么Android系统的 其他组件,比如BroadcastReceiver,Service还有ContentProvider,它们又该如何处理呢? 相比Activity,BroadcastReceiver要简单很多--广播的生命周期相当简单:如果希望插件能够支持广播,这意味着什么? 回想一下我们日常开发的时候是如何使用Broadca

Android高级:插件化、热修复、AMS、Binder

Android插件化原理解析 写给 Android 应用工程师的 Binder 原理剖析 原文地址:https://www.cnblogs.com/wytiger/p/10772853.html

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

Android 插件化 ——指将一个程序划分为不同的部分,比如一般 App的皮肤样式就可以看成一个插件 Android 组件化 ——这个概念实际跟上面相差不那么明显,组件和插件较大的区别就是:组件是指通用及复用性较高的构件,比如图片缓存就可以看成一个组件被多个 App共用 插件的方式只有三种:1,apk安装,2,apk不安装,3,dex包 滴滴插件化项目VirtualAPK开源!https://mp.weixin.qq.com/s?__biz=MzUxMzcxMzE5Ng==&mid=22474

android插件化研究

使用 android:sharedUserId="com.wallj.skin" 1.总共三个工程,包名分别为com.wallj.main/com.wallj.spring/com.wallj.summer 其中com.wallj.main为主工程,其他两个为插件工程,均只为主工程提供资源. 三个工程需要使用同一个 android:sharedUserId=" com.wallj.skin"以达到资源共享的目的. 设置了该属性后,三个工程之间的ClassLoader

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

携程Android App的插件化和动态加载框架已上线半年,经历了初期的探索和持续的打磨优化,新框架和工程配置经受住了生产实践的考验.本文将详细介绍Android平台插件式开发和动态加载技术的原理和实现细节,回顾携程Android App的架构演化过程,期望我们的经验能帮助到更多的Android工程师. 需求驱动 2014年,随着业务发展需要和携程无线部门的拆分,各业务产品模块归属到各业务BU,原有携程无线App开发团队被分为基础框架.酒店.机票.火车票等多个开发团队,从此携程App的开发和发布

Android Small插件化框架解读——Activity注册和生命周期[阿里工程师分享]

通过对嵌入式企鹅圈原创团队成员degao之前发表的<Android Small插件化框架源码分析>的学习,对Android使用的插件化技术有了初步的了解,但还是有很多需要认真学习的地方,特别是大部分知识都需要结合虚拟机和Androidframwork的原理才能慢慢理解.比如,文中作者提到了插件化框架要解决的三个核心问题: 1)插件类的加载: 2)插件资源的处理: 3)Activity注册和生命周期问题: 其中第3点作者是这样解释的,"大部分插件化框架解决办法都是采用在宿主工程里预先注

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

Android系统的每次版本升级,都会对原有代码进行重构,这就为插件化带来了麻烦. Android P对插件化的影响,主要体现在两方面,一是它重构了H类中Activity相关的逻辑,另一个是它重构了Instrumentation. 3.1 H类的变身 3.1.1 从Message和Handler说起 对于App开发人员而言,Message和Handler是耳熟能详的两个概念.我们简单回顾一下,一条消息是怎么发送和接收的. 首先,在App启动的时候,会创建ActivityThread,这就是主线程

64、插件化(携程)转载

本文转自:微信 携程Android App插件化和动态加载实践 2015-11-04 白总 CtripMobile 携程Android App的插件化和动态加载框架已上线半年,经历了初期的探索和持续的打磨优化,新框架和工程配置经受住了生产实践的考验.本文将详细介绍Android平台插件式开发和动态加载技术的原理和实现细节,回顾携程Android App的架构演化过程,期望我们的经验能帮助到更多的Android工程师. 需求驱动 2014年,随着业务发展需要和携程无线部门的拆分,各业务产品模块归属