Android动态加载代码技术
Android动态加载代码技术
在开发Android App的过程当中,可能希望实现插件式软件架构,将一部分代码以另外一个APK的形式单独发布,而在主程序中加载并执行这个APK中的代码。
实现这个任务的一般方法是:

// 加载类cls
Context pluginContext = mainContext.createPackageContext(PLUGIN_PKG, Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE);
ClassLoader loader = pluginContext.getClassLoader();
Class<?> cls = loader.loadClass(CLASS_NAME);
// 通过反射技术,调用cls中的方法,下面是一个示例,实际代码因情况而定
Object obj = cls.newInstance();
Method method = cls.getDeclaredMethod("someMethod");
method.invoke(obj);

但是,这个方法在Android 4.1及之后的系统中存在一些问题:对于收费应用,Google Play会将其安装在一个加密目录之下(具体就是/data/app-asec),而不是一个普通目录之下(具体就是/data/app);安装在加密目 录中的应用,我们是无法使用上述方法来加载并执行代码的;而实际情况是,我们经常就是依靠插件应用来收费的。
解决上述问题的一个方案是:将插件的二进制代码拷贝到SD卡中,主程序从SD卡中加载并执行其代码。
实现这个任务的具体方法是:

Class<?> cls = null;
try { // 尝试第一种方法
cls = loadClass1(mainContext, pkg, entryCls);
} catch (Exception e) { // 尝试第二种方法
cls = loadClass2(mainContext, pkg, entryCls);
}// 示例代码Object obj = cls.newInstance();Method method = cls.getDeclaredMethod("someMethod");method.invoke(obj);
// 第一种加载方法private Class<?> loadClass1(Context mainContext, String pkg, String entryCls) throws Exception { Context pluginContext = mainContext.createPackageContext(pkg, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY); ClassLoader loader = pluginContext.getClassLoader(); return loader.loadClass(entryCls); }
// 第二种加载方法private Class<?> loadClass2(Context mainContext, String pkg, String entryCls) throws Exception { Context pluginContext = mainContext.createPackageContext(pkg, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY); String path = generatePluginDexPath(mainContext, pkg); ensureFileExist(pluginContext, pkg, path); // cacheDir必须是主程序的私有目录,否则DexClassLoader可能会拒绝加载 String cacheDir = mainContext.getApplicationInfo().dataDir; ClassLoader parentLoader = pluginContext.getClassLoader(); DexClassLoader loader = new DexClassLoader(path, cacheDir, null, parentLoader); return loader.loadClass(entryCls);}
// 获取程序版本号private int getVersionCode(Context context, String pkg) { PackageInfo info = null; int versionCode = 0; try { info = context.getPackageManager().getPackageInfo(pkg, PackageManager.GET_ACTIVITIES); versionCode = info.versionCode; } catch (Exception e) {} return versionCode;}
// 获取插件二进制代码的存储位置,注意做好版本控制;路径必须是以.dex结束,否则加载会出问题private String generatePluginDexPath(Context context, String pkg) { int version = getVersionCode(context, pkg); String path = getMyAppPath() + ".classes/" + pkg + version + ".dex"; return path;}
// 主程序在SD卡上的数据目录private String getMyAppPath() { return Environment.getExternalStorageDirectory().getAbsolutePath() + "/MyApp/";}
// 拷贝插件的二进制代码到SD卡private void ensureFileExist(Context pluginContext, String pkg, String path) throws Exception { File file = new File(path); if(file.exists()) return; file.getParentFile().mkdirs(); Resources res = pluginContext.getResources(); int id = res.getIdentifier("classes", "raw", pkg); InputStream in = res.openRawResource(id); FileOutputStream out = new FileOutputStream(file); try { byte[] buffer = new byte[1024 * 1024]; int n = 0; while((n = in.read(buffer)) > 0) { out.write(buffer, 0, n); } out.flush(); } catch (IOException e) { in.close(); out.close(); }}

插件工程这边也需要做相应的修改:
1.编译插件工程;
2.将bin目录之下的classes.dex拷贝到/res/raw目录之下;
3.重新编译插件工程;
4.发布插件APK。
来自 :frydsh
Android动态加载代码技术的更多相关文章
- Android 插件技术:动态加载dex技术初探
1.Android动态加载dex技术初探 http://blog.csdn.net/u013478336/article/details/50734108 Android使用Dalvik虚拟机加载可执 ...
- Android动态加载技术初探
一.前言: 现在,已经有实力强大的公司用这个技术开发应用了,比如淘宝,大众点评,百度地图等,之所以采用这个技术,实际上,就是方便更新功能,当然,前提是新旧功能的接口一致,不然会报Not Found等错 ...
- 深入浅出Android动态加载jar包技术
在实际项目中,由于某些业务频繁变更而导致频繁升级客户端的弊病会造成较差的用户体验,而这也恰是Web App的优势,于是便衍生了一种思路,将核心的易于变更的业务封装在jar包里然后通过网络下载下来,再由 ...
- Android 动态加载 (一) 态加载机制 案例一
在目前的软硬件环境下,Native App与Web App在用户体验上有着明显的优势,但在实际项目中有些会因为业务的频繁变更而频繁的升级客户端,造成较差的用户体验,而这也恰恰是Web App的优势.本 ...
- 从高德 SDK 学习 Android 动态加载资源
前不久跑去折腾高德 SDK 中的 HUD 功能,相信用过该功能的用户都知道 HUD 界面上的导航转向图标是动态变化的.从高德官方导航 API 文档中 AMapNaviGuide 类的描述可知,导航转向 ...
- Android动态加载jar、apk的实现
前段时间到阿里巴巴参加支付宝技术分享沙龙,看到支付宝在Android使用插件化的技术,挺好奇的.正好这几天看到了农民伯伯的相关文章,因此简单整理了下,有什么错误希望大神指正. 核心类 1.1 ...
- android动态加载
转载自: http://www.cnblogs.com/over140/archive/2012/03/29/2423116.html http://www.cnblogs.com/over140/a ...
- [转载] Android动态加载Dex机制解析
本文转载自: http://blog.csdn.net/wy353208214/article/details/50859422 1.什么是类加载器? 类加载器(class loader)是 Java ...
- Android 动态加载 (二) 态加载机制 案例二
探秘腾讯Android手机游戏平台之不安装游戏APK直接启动法 重要说明 在实践的过程中大家都会发现资源引用的问题,这里重点声明两点: 1. 资源文件是不能直接inflate的,如果简单的话直接在程序 ...
随机推荐
- mac删除顽固图标
cd /Users/shelley/Library/Application\ Support/Dock cp 10CCA448-0975-41DE-B47A-8E89FD634227.db 10 ...
- 调查程序phpquestionnaire 2.2中文安装注意
最近找调查投票软件 找到limesurvey 和 phpquestionnaire,limesurvey 中文可以用,但是比较烦琐.phpquestionnaire有汉化过的包下载,但是安装完,发现中 ...
- [GitPython]使用python管理你的git库
你想使用python来自动管理一个git仓库的时候,GitPython是一个不错的选择. 简介: 先看看下面这段代码: from git import Repo repo = Repo("~ ...
- 利用Azure Redis Cache构建百万量级缓存读写
Redis是一个非常流行的基于内存的,低延迟,高吞吐量的key/value数据存储,被广泛用于数据库缓存,session的管理,热数据高速访问,甚至作为数据库方式提高应用程序可扩展性,吞吐量,和实施处 ...
- BZOJ 3550 Vacation
http://www.lydsy.com/JudgeOnline/problem.php?id=3550 题意:有3N个数,你需要选出一些数,首先保证任意长度为N的区间中选出的数的个数<=K个, ...
- bitmap 内存溢出OOM的解决办法分享
昨天遇到这个问题就是从一个输入流里调用BitmapFactory.decodeStream(this.getContentResolver().openInputStream(uri))得到一个bit ...
- 05_Elasticsearch 单模式下API的增删改查操作
05_Elasticsearch 单模式下API的增删改查操作 安装marvel 插件: zjtest7-redis:/usr/local/elasticsearch-2.3.4# bin/plugi ...
- softlayer virtual machine vhd磁盘镜像导入shell脚本
脚本
- dig命令(转载)
dig命令使用大全(linux上域名查询) 可以这样说,翻译本篇文档的过程就是我重新学习DNS的过程,dig命令可以帮助我们学习DNS的原理,配置,以及其查询过程.以前使用dig仅仅是查询一下A记录或 ...
- hdu 5427 A problem of sorting(字符排序)
Problem Description There are many people's name and birth in a list.Your task is to print the name ...