Android载入插件apk中的Resource资源

简单介绍

怎样载入未安装apk中的资源文件呢?我们从android.content.res.AssetManager.java的源代码中发现,它有一个私有方法addAssetPath,仅仅须要将apk的路径作为參数传入,我们就能够获得相应的AssetsManager对象,然后我们就能够使用AssetsManager对象,创建一个Resources对象,然后就能够从Resource对象中訪问apk中的资源了。

总结例如以下:

  • 1.新建一个AssetManager对象
  • 2.通过反射调用addAssetPath方法
  • 3.以AssetsManager对象为參数。创建Resources对象就可以。

代码例如以下:

package net.mobctrl.hostapk;

import java.io.File;

import android.content.Context;
import android.content.res.AssetManager;
import android.content.res.Resources; /**
* @Author Zheng Haibo
* @PersonalWebsite http://www.mobctrl.net
* @version $Id: LoaderResManager.java, v 0.1 2015年12月11日 下午7:58:59 mochuan.zhb
* Exp $
* @Description 动态载入资源的管理器
*/
public class BundlerResourceLoader { private static AssetManager createAssetManager(String apkPath) {
try {
AssetManager assetManager = AssetManager.class.newInstance();
try {
AssetManager.class.getDeclaredMethod("addAssetPath", String.class).invoke(
assetManager, apkPath);
} catch (Throwable th) {
System.out.println("debug:createAssetManager :"+th.getMessage());
th.printStackTrace();
}
return assetManager;
} catch (Throwable th) {
System.out.println("debug:createAssetManager :"+th.getMessage());
th.printStackTrace();
}
return null;
} /**
* 获取Bundle中的资源
* @param context
* @param apkPath
* @return
*/
public static Resources getBundleResource(Context context){
AssetsManager.copyAllAssetsApk(context);
File dir = context.getDir(AssetsManager.APK_DIR, Context.MODE_PRIVATE);
String apkPath = dir.getAbsolutePath()+"/BundleApk.apk";
System.out.println("debug:apkPath = "+apkPath+",exists="+(new File(apkPath).exists()));
AssetManager assetManager = createAssetManager(apkPath);
return new Resources(assetManager, context.getResources().getDisplayMetrics(), context.getResources().getConfiguration());
} }

DEMO

注意:我们使用Resources对象。获取资源时。传递的ID必须是离线apk中R文件相应的资源的ID。

假设使用getIdentifier方法,第一个參数是资源名称。第二个參数是资源类型,第三个參数是离线apk的包名。切记第三个參数。

Resources resources = BundlerResourceLoader.getBundleResource(getApplicationContext());
imageView = (ImageView)findViewById(R.id.image_view_iv);
if(resources != null){
String str = resources.getString(resources.getIdentifier("test_str", "string", "net.mobctrl.normal.apk"));
String strById = resources.getString(0x7f050001);//注意,id參照Bundle apk中的R文件
System.out.println("debug:"+str);
Toast.makeText(getApplicationContext(),strById, Toast.LENGTH_SHORT).show(); Drawable drawable = resources.getDrawable(0x7f020000);//注意,id參照Bundle apk中的R文件
imageView.setImageDrawable(drawable);
}

上述代码是载入离线apk中的字符串和Drawable资源。那么layout资源呢?

问题引入

我们使用LayoutInflate对象。一般用法例如以下:

View view = LayoutInflater.from(context).inflate(R.layout.main_fragment, null);

当中,R.layout.main_fragment我们能够通过上述方法获取其ID,那么关键的一步就是怎样生成一个context?直接传入当前的context是不行的。

解决方式有2个:

- 1.创建一个自己的ContextImpl,Override其方法。

- 2.通过反射。直接替换当前context的mResources私有成员变量。<>br

当然。我们是使用另外一种方案:

    @Override
protected void attachBaseContext(Context context) {
replaceContextResources(context);
super.attachBaseContext(context);
} /**
* 使用反射的方式,使用Bundle的Resource对象,替换Context的mResources对象
* @param context
*/
public void replaceContextResources(Context context){
try {
Field field = context.getClass().getDeclaredField("mResources");
field.setAccessible(true);
field.set(context, mBundleResources);
System.out.println("debug:repalceResources succ");
} catch (Exception e) {
System.out.println("debug:repalceResources error");
e.printStackTrace();
}
}

我们在Activity的attachBaseContext方法中,对Context的mResources进行替换,这样,我们就能够载入离线apk中的布局了。

资源文件的打包过程

假设想要做到插件化,须要了解Android资源文件的打包过程。这样能够为每个插件进行编号。然后依照规则生成R文件。

比如。以携程DynamicAPK为例,它将插件的R文件依照例如以下规则:

  • 1.R文件为int型。前8位代表插件的Id,当中两个特殊的Id:Host是0x7f,android系统自带的是以0x01开头.
  • 2.紧跟着的8位是区分资源类型的。比方layout。id,string,dimen等
  • 3.后面16位是资源的编号

依照上述规则生成相应的插件apk。

然后在执行时,我们能够写一个ResourceManager类。它继承自Resource对象,然后全部的Activity。都将其context的mResource成员变量改动为ResourceManager类,然后Override其方法,然后在载入资源时。依据不同的id的前缀,查找相应插件的Resource就可以。也就是说,用一个类做分发。

Android插件化相关资料

Android插件化(三)载入插件apk中的Resource资源的更多相关文章

  1. Android插件化(三):OpenAtlas的插件重建以及使用时安装

    Android插件化(三):OpenAtlas的插件重建以及使用时安装 转 https://www.300168.com/yidong/show-2778.html    核心提示:在上一篇博客 An ...

  2. Android插件化(二):OpenAtlas插件安装过程分析

    Android插件化(二):OpenAtlas插件安装过程分析   转 https://www.300168.com/yidong/show-2788.html   核心提示:在前一篇博客 Andro ...

  3. Android插件化(4):OpenAtlasの插件的卸载与更新

    Android插件化(4):OpenAtlasの插件的卸载与更新   转 https://www.300168.com/yidong/show-2779.html 核心提示:如果看过我的前两篇博客An ...

  4. ​插件化DPI在商用WIFI中的价值

    插件化DPI是指DPI(深度包检测)技术以插件/模块的方式嵌入到各种网络设备中,是一种新型轻量级资源消耗的互联网技术,由迈科网络(股份代码:430575)独创开发. 插件化DPI(深度包检测)技术服务 ...

  5. Android下将图片载入到内存中

    Android的系统的标准默认每一个应用程序分配的内存是16M.所以来说是很宝贵的,在创建应用的时候要尽可能的去节省内存,可是在载入一些大的文件的时候,比方图片是相当耗内存的,一个1.3M的图片,分辨 ...

  6. Android 签名(3)已签名的apk中的文件

    已经签名 apk包中签名相关的文件在meta_INF目录下 CERT.SF:生成每个文件相对的密钥 MANIFEST.MF:数字签名信息 xxx.SF:这是JAR文件的签名文件,占位符xxx标识了签名 ...

  7. Android开发(三十)——ScrollView中ListView的高度自动适应

    int totalHeight = 0; for (int i = 0; i < mStrings.length; i++) { //pullList ListView //mAdapter A ...

  8. 【Android】通过Java代码替换TabHost中的drawableTop资源

    在博客 http://blog.csdn.net/jueblog/article/details/11837445 中的Tab选项卡中, 点击相应的Tab选项,图标没有发生改变. 这些资源图片也没有尽 ...

  9. 插件化开发—动态载入技术载入已安装和未安装的apk

    首先引入一个概念,动态载入技术是什么?为什么要引入动态载入?它有什么优点呢?首先要明确这几个问题.我们先从 应用程序入手,大家都知道在Android App中.一个应用程序dex文件的方法数最大不能超 ...

随机推荐

  1. bzoj 1069

    最开始想到的是枚举3个点,另一个点用卡壳的思想,但实际上可以只枚举两个点(对角线上的两个点),其余两个点用卡壳. /****************************************** ...

  2. bzoj 3653

    每个点维护一颗以深度为下标,size-1为值的线段树,保存整颗子树的信息,这样就可以查询了,但是如果为每个节点都建立这么一颗树,显然会MLE,所以考虑在DFS序上建立主席树,然后每个节点原来对应的线段 ...

  3. Codeforces Round #359 (Div. 1) B. Kay and Snowflake dfs

    B. Kay and Snowflake 题目连接: http://www.codeforces.com/contest/685/problem/B Description After the pie ...

  4. HDU 5714 拍照 前缀和

    拍照 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5714 Description 小明在旅游的路上看到了一条美丽的河,河上有许多船只,有的船只向左 ...

  5. Spring Batch 批处理框架介绍

    前言 在大型的企业应用中,或多或少都会存在大量的任务需要处理,如邮件批量通知所有将要过期的会员,日终更新订单信息等.而在批量处理任务的过程中,又需要注意很多细节,如任务异常.性能瓶颈等等.那么,使用一 ...

  6. visio2013 激活工具,仅供交流学习

    visio2013激活软件 环境是 win7, 64 bit 装了 visio 2013 , 可以却不能用它来画图,在网上找了一些破解工具,大都不能解决问题.网上不靠谱的广告型文章太多了 所幸,终于找 ...

  7. Linux终端(Xshell等)的编码设置

    先简单说说一下遇到的情况吧: 在用类似Xshell的工具连接远端Linux时,运行命令ls时,如果有中文,就会显示有乱码: 网上查资料时,也把相应的连接属性修改为utf-8了(见下图),但是还是不行: ...

  8. wrote a programming language

    https://medium.freecodecamp.org/the-programming-language-pipeline-91d3f449c919

  9. 数据库中间件OneProxy and onemysql

    http://blog.itpub.net/28944233/cid-176181-list-1/ http://www.onexsoft.com/ 官网 http://pan.baidu.com/s ...

  10. 值得借鉴的Objective-C编程规范

    Daniel's Objective-C Coding Style Guidelines http://google-styleguide.googlecode.com/svn/trunk/objcg ...