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动态加载代码技术的更多相关文章

  1. Android 插件技术:动态加载dex技术初探

    1.Android动态加载dex技术初探 http://blog.csdn.net/u013478336/article/details/50734108 Android使用Dalvik虚拟机加载可执 ...

  2. Android动态加载技术初探

    一.前言: 现在,已经有实力强大的公司用这个技术开发应用了,比如淘宝,大众点评,百度地图等,之所以采用这个技术,实际上,就是方便更新功能,当然,前提是新旧功能的接口一致,不然会报Not Found等错 ...

  3. 深入浅出Android动态加载jar包技术

    在实际项目中,由于某些业务频繁变更而导致频繁升级客户端的弊病会造成较差的用户体验,而这也恰是Web App的优势,于是便衍生了一种思路,将核心的易于变更的业务封装在jar包里然后通过网络下载下来,再由 ...

  4. Android 动态加载 (一) 态加载机制 案例一

    在目前的软硬件环境下,Native App与Web App在用户体验上有着明显的优势,但在实际项目中有些会因为业务的频繁变更而频繁的升级客户端,造成较差的用户体验,而这也恰恰是Web App的优势.本 ...

  5. 从高德 SDK 学习 Android 动态加载资源

    前不久跑去折腾高德 SDK 中的 HUD 功能,相信用过该功能的用户都知道 HUD 界面上的导航转向图标是动态变化的.从高德官方导航 API 文档中 AMapNaviGuide 类的描述可知,导航转向 ...

  6. Android动态加载jar、apk的实现

    前段时间到阿里巴巴参加支付宝技术分享沙龙,看到支付宝在Android使用插件化的技术,挺好奇的.正好这几天看到了农民伯伯的相关文章,因此简单整理了下,有什么错误希望大神指正. 核心类 1.1     ...

  7. android动态加载

    转载自: http://www.cnblogs.com/over140/archive/2012/03/29/2423116.html http://www.cnblogs.com/over140/a ...

  8. [转载] Android动态加载Dex机制解析

    本文转载自: http://blog.csdn.net/wy353208214/article/details/50859422 1.什么是类加载器? 类加载器(class loader)是 Java ...

  9. Android 动态加载 (二) 态加载机制 案例二

    探秘腾讯Android手机游戏平台之不安装游戏APK直接启动法 重要说明 在实践的过程中大家都会发现资源引用的问题,这里重点声明两点: 1. 资源文件是不能直接inflate的,如果简单的话直接在程序 ...

随机推荐

  1. php代码-1

  2. linux 文件类命令笔记

    看一下linux的教程,不错,由于只看鸟哥有点空洞,于就是找了个视频教程,边看边学 对比了几个教程,http://edu.51cto.com/course/course_id-32.html这个教程相 ...

  3. 配置Kestrel 网址Urls

    配置Kestrel 网址Urls ASP.NET Core中如何配置Kestrel Urls呢,大家可能都知道使用UseUrls() 方法来配置. 今天给介绍全面的ASP.NET Core 配置 Ur ...

  4. 深入理解Azure自动扩展集VMSS(3)

    在实际使用过程当中,使用VMSS有一些最佳实践的建议和限制,便于你在做自动扩展设计的时候进行考虑: 关于VMSS 如果你使用的是系统镜像,一个扩展集中虚拟机数量不能超过100 无论是在ASM还是ARM ...

  5. LODS LODSB LODSW LODSD 例子【载入串指令】

    http://qwop.iteye.com/blog/1958761 // lodsb.cpp : Defines the entry point for the console applicatio ...

  6. Ueditor开发经验

    Ueditor是百度开发的一款免费使用的富文本编辑器. 先前就一直使用Ueditor,觉得功能挺多的,而且还给出了详细的文档,供二次开发. 但Ueditor已经出新的版本(和先前版本很不相同),网上很 ...

  7. oracle starup报错

    今天在linux里面安装Oracle的时候出现一个报错,忽略报错安装之后,数据库启动的时候报错: 从网上找到的解决方法: 创建实例后,进入sqlplus启动报错: sqlplus / as sysdb ...

  8. EF 一对一,一对多,多对多 Flunt API 配置

       一对一 就拿后台用户权限相关的实体来说明吧,用户表,用户详细表,是一对一的关系: /// <summary> /// 用户信息类 /// </summary> publi ...

  9. QT5.1.0,QT4.8.0以及VC2010、VC2012的测试对比

    QT5.1.0,QT4.8.0以及VC2010.VC2012的交叉测试对比. 测试1: 用VC2012静态编译了QT5.1.0. 编译速度很慢,生成完成后,用VC2012+QT5.1.0进行程序生成, ...

  10. cf448A Rewards

    A. Rewards time limit per test 1 second memory limit per test 256 megabytes input standard input out ...