Android插件化(三)载入插件apk中的Resource资源
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插件化相关资料
- 1.Android动态载入基础 ClassLoader工作机制 http://segmentfault.com/a/1190000004062880
- 2.Android动态载入黑科技 动态创建Activity模式 http://segmentfault.com/a/1190000004077469
- 3.Android插件化框架Github总结 https://github.com/liaohuqiu/android-dynamic-load-awesome
- 4.携程动态载入框架源代码 https://github.com/CtripMobile/DynamicAPK
- 5.携程Android App插件化和动态载入实践 http://www.infoq.com/cn/articles/ctrip-android-dynamic-loading
- 6.dex分包变形记 http://mp.weixin.qq.com/s?__biz=MzA3NTYzODYzMg==&mid=401345907&idx=1http://mp.weixin.qq.com/s?__biz=MzA3NTYzODYzMg==&mid=401345907&idx=1&sn=debdddf25950aaaa10f575472629b557
- 7.各大热补丁方案分析和比較 http://blog.zhaiyifan.cn/2015/11/20/HotPatchCompare/
- 8.Android App 线上热修复方案 http://lirenlong.github.io/hotfix/
- 9.Android 热补丁动态修复框架小结 http://blog.csdn.net/lmj623565791/article/details/49883661
- 10.Android热更新实现原理 http://blog.csdn.net/lzyzsd/article/details/49843581
- 11.【新技能get】让App像Web一样公布新版本号 http://bugly.qq.com/blog/?p=781
- 12.Android动态载入技术 系列索引 http://segmentfault.com/a/1190000004086213
- 13.Android对第三方类库执行时载入 http://blog.csdn.net/dzg1977/article/details/41683173
- 14.关于Android怎样动态载入res http://nobodycare.me/2014/11/07/about-loading-res-from-apk-directly/
- 15.Android应用程序资源的编译和打包过程分析 http://blog.csdn.net/luoshengyang/article/details/8744683
- 16.Android应用程序资源管理器(Asset Manager)的创建过程分析 http://blog.csdn.net/luoshengyang/article/details/8791064
- 17.Android 自己主动编译、打包生成apk文件 1 - 命令行方式 http://blog.csdn.net/androiddevelop/article/details/10948639
Android插件化(三)载入插件apk中的Resource资源的更多相关文章
- Android插件化(三):OpenAtlas的插件重建以及使用时安装
Android插件化(三):OpenAtlas的插件重建以及使用时安装 转 https://www.300168.com/yidong/show-2778.html 核心提示:在上一篇博客 An ...
- Android插件化(二):OpenAtlas插件安装过程分析
Android插件化(二):OpenAtlas插件安装过程分析 转 https://www.300168.com/yidong/show-2788.html 核心提示:在前一篇博客 Andro ...
- Android插件化(4):OpenAtlasの插件的卸载与更新
Android插件化(4):OpenAtlasの插件的卸载与更新 转 https://www.300168.com/yidong/show-2779.html 核心提示:如果看过我的前两篇博客An ...
- 插件化DPI在商用WIFI中的价值
插件化DPI是指DPI(深度包检测)技术以插件/模块的方式嵌入到各种网络设备中,是一种新型轻量级资源消耗的互联网技术,由迈科网络(股份代码:430575)独创开发. 插件化DPI(深度包检测)技术服务 ...
- Android下将图片载入到内存中
Android的系统的标准默认每一个应用程序分配的内存是16M.所以来说是很宝贵的,在创建应用的时候要尽可能的去节省内存,可是在载入一些大的文件的时候,比方图片是相当耗内存的,一个1.3M的图片,分辨 ...
- Android 签名(3)已签名的apk中的文件
已经签名 apk包中签名相关的文件在meta_INF目录下 CERT.SF:生成每个文件相对的密钥 MANIFEST.MF:数字签名信息 xxx.SF:这是JAR文件的签名文件,占位符xxx标识了签名 ...
- Android开发(三十)——ScrollView中ListView的高度自动适应
int totalHeight = 0; for (int i = 0; i < mStrings.length; i++) { //pullList ListView //mAdapter A ...
- 【Android】通过Java代码替换TabHost中的drawableTop资源
在博客 http://blog.csdn.net/jueblog/article/details/11837445 中的Tab选项卡中, 点击相应的Tab选项,图标没有发生改变. 这些资源图片也没有尽 ...
- 插件化开发—动态载入技术载入已安装和未安装的apk
首先引入一个概念,动态载入技术是什么?为什么要引入动态载入?它有什么优点呢?首先要明确这几个问题.我们先从 应用程序入手,大家都知道在Android App中.一个应用程序dex文件的方法数最大不能超 ...
随机推荐
- CodeIgniter框架中关于URL重写(index.php)的二三事
最近,在做自己的个人网站时,采用了轻量级的php框架CodeIgniter.乍一看上去,代码清晰简洁,MVC模型非常容易维护.开发时我采用的工具是Netbeans IDE 8.0,当然,本文的内容和开 ...
- CentOS的利手:“Screen”一个可以在多个进程之间多路复用一个物理终端的窗口管理器
你是不是经常需要远程登录到Linux服务器?你是不是经常为一些长时间运行的任务头疼?还在用 nohup 吗?那 么来看看 screen 吧,它会给你一个惊喜! 你是不是经常需要 SSH 或者 tele ...
- 【BZOJ】2561: 最小生成树【网络流】【最小割】
2561: 最小生成树 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2685 Solved: 1253[Submit][Status][Discu ...
- Nodejs线上日志部署
Nodejs 被越来越多的使用到线上系统中,但线上系统没有日志怎么行呢. 一.forever记录日志 我的线上系统使用forever来启动服务,最开始就直接使用了forever来记录 forever ...
- jquery常用写法简单记录
好久不写东西了......话不多说,主要记录一下,最近做的项目中用到的js的记录(虽然特别特别简单) 一 jquery常用写法记录 jQuery(this).addClass("select ...
- HTML5学习笔记1
1.HTML5概述 继html4和xhtml1.0后的超文本标记语言最新版本.最重要的三项技术:html5核心规范(标签元素),CSS3,JavaScript2008年发布,主要为了补全功能.特点:1 ...
- Redis在Windows+linux平台下的安装配置(转)
window平台Redis安装 下载地址: http://code.google.com/p/servicestack/wiki/RedisWindowsDownload Redis文件夹有以下几个文 ...
- POJ 3041(最小点覆盖)
题意: 假如你如今正处在一个N*N的矩阵中,这个矩阵里面有K个障碍物,你拥有一把武器,一发弹药一次能消灭一行或一列的障碍物,求最小的弹药消灭所有障碍物 输入为: N K 接下来有K行,每行包括 ...
- 算法学习 - 平衡二叉查找树实现(AVL树)
平衡二叉查找树 平衡二叉查找树是非常早出现的平衡树,由于全部子树的高度差不超过1,所以操作平均为O(logN). 平衡二叉查找树和BS树非常像,插入和删除操作也基本一样.可是每一个节点多了一个高度的信 ...
- C#程序集系列13,如何让CLR选择不同版本的程序集
本篇主要体验,在存在多个版本程序集的情况下,如何让CLR选择哪个版本程序集运行,以及程序集版本的切换. 分别生成非强名称程序集不同版本 □ 生成某个版本的程序集 →清理F盘as文件夹,剩下如下文件 → ...