安卓里边可以用DexClassLoader实现动态加载dex文件,通过访问dex文件访问dex中封装的方法,如果dex文件本身还调用了native方法,也就间接实现了runtime调用native方法,这一流程主要包括:构建dex和so文件、在主工程添加动态调用代码、移除dex的module,将dex和so push到手机的指定路径

构建dex和so文件

首先在主工程里边新建一个名为testdepence的module,新建一个add类,在add类里边我们创建一个单例方法和一个native方法

public class Add {
private final static String TAG = "Add";
private static Add add = null;
static {
System.loadLibrary("anclivejni");
} public static Add getInstance(){
Log.d(TAG, "getInstance: ");
if (add == null){
add = new Add();
}
return add;
} public native void init(byte[] data); }

然后新建jni.cpp,实现init方法,这里我们就只是打印一个log


#define TAG "SXF"
#define LOG(...) __android_log_print(ANDROID_LOG_DEBUG,TAG,__VA_ARGS__)

extern "C" JNIEXPORT void JNICALL Java_com_example_testdepence_Add_init(JNIEnv
* env,
jobject thiz
,jbyteArray array) {
LOG("call init from native");
// TODO: implement init()
}

然后在gradle task里边选择 assembleRelease,运行,在testdepence module outputs/aar下会生成一个aar文件,把它的后缀改成zip,解压,得到classes.jar和so文件,然后用/your sdk dir/build-tools/plarform id下的dx工具将jar转换为dex文件,就ok了

## 在主工程添加动态调用代码

新建一个DynamicLoader类,添加使用DexClassLoader反射调用dex文件的代码

public class DynamicLoader {
private final static String TAG = "DanymicLoader";
private static Object handle;
/**
* 加载dex文件中的class,并调用其中的方法
* 这里由于是加载 jar文件,所以采用DexClassLoader
* 下面开始加载dex class
*/
private static Method getMethod(Context context,String methodName,Class<?>... methodArgs) {
File cacheFile = context.getCacheDir();
Log.d(TAG, "loadDexClass file path: " + cacheFile.getAbsolutePath());
String internalPath = cacheFile.getAbsolutePath() + File.separator + "classes.dex";
File desFile = new File(internalPath);
Method method = null;
if (desFile.exists()) {
DexClassLoader dexClassLoader = new DexClassLoader(internalPath//dex文件路径, cacheFile.getAbsolutePath()//dex文件解压路径, cacheFile.getAbsolutePath()//so的搜索路径, context.getClass().getClassLoader());
try {
Class<?> libClazz = dexClassLoader.loadClass("com.example.testdepence.Add");
Method getInstance = libClazz.getMethod("getInstance");
getInstance.setAccessible(true);
handle = getInstance.invoke(null);
if (handle ==null){
Log.d(TAG, "getInstance error handle is null !!! ");
}else {
Log.d(TAG, "getInstance success!!! ");
} method = libClazz.getMethod(methodName,methodArgs);
method.setAccessible(true); } catch (Exception e) {
e.printStackTrace();
Log.d(TAG, "getMethod error: " + e.getMessage());
return method;
}
}else{
Log.d(TAG, "aar not exist!!!");
}
return method;
} public static int dynamicInit(Context context,byte[] data){
Method initHandle = getMethod(context,"init",byte[].class);
if (initHandle !=null && handle != null && data != null){
try {
initHandle.invoke(handle,data);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
return -1;
}
}
return 0;
}
}

然后在activity里边调用之

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DynamicLoader.dynamicInit(this,new byte[1024]);
}

之后在setting.gradle里边将testdepence里这个module移除,编译app,准备运行

将dex和so push到手机的指定路径

按照“internalPath//dex文件路径, cacheFile.getAbsolutePath()//dex文件解压路径, cacheFile.getAbsolutePath()//so的搜索路径”,将dex和so push到手机对应的目录,然后就可以打开app运行啦。

源码见github:https://github.com/gangmiangongjue/Android-Dynamic-Plugin-demo

好用的话请点个星星~不好用欢迎提case,谢谢

android 基于dex的插件化开发的更多相关文章

  1. Android基于代理的插件化思路分析

    前言 正常的App开发流程基本上是这样的:开发功能-->测试--->上线,上线后发现有大bug,紧急修复---->发新版本---->用户更新----->bug修复.从发现 ...

  2. JavaScript插件化开发

    大熊君JavaScript插件化开发 一,开篇分析 Hi,大家好!大熊君又和大家见面了,还记得昨天的那篇文章吗------这个系列的开篇(第一季).主要讲述了以“jQuery的方式如何开发插件”, 那 ...

  3. Android 插件化开发(二):加载外部Dex文件

    在学习Java反射的技术后,我们可以开始更深一步的探究插件化开发了.首先先讲一下Android App的打包流程,然后我们通过一个简单的例子 —— 实现插件化加载外部Dex来完成初级的插件化开发的探索 ...

  4. Android插件化开发

    客户端开发给人的印象往往是小巧,快速奔跑.但随着产品的发展,目前产生了大量的门户型客户端.功能模块持续集成,开发人员迅速增长.不同的开发小组开发不同的功能模块,甚至还有其他客户端集成进入.能做到功能模 ...

  5. 《Android插件化开发指南》面世

    本书在京东购买地址:https://item.jd.com/31178047689.html 本书Q群:389329264 (一)这是一本什么书 如果只把本书当作纯粹介绍Android插件化技术的书籍 ...

  6. Android插件化开发---执行未安装apk中的Service

    欢迎各位增加我的Android开发群[257053751​] 假设你还不知道什么叫插件化开发.那么你应该先读一读之前写的这篇博客:Android插件化开发,初入殿堂 上一篇博客主要从总体角度分析了一下 ...

  7. 【我的Android进阶之旅】Android插件化开发学习资料

    1.目前开源的插件开发框架大致有哪些? 1. 任玉刚 的 dynamic-load-apk Github 地址:https://github.com/singwhatiwanna/dynamic-lo ...

  8. 详解Android插件化开发-资源访问

    动态加载技术(也叫插件化技术),当项目越来越庞大的时候,我们通过插件化开发不仅可以减轻应用的内存和CPU占用,还可以实现热插拔,即在不发布新版本的情况下更新某些模块.     通常我们把安卓资源文件制 ...

  9. Android 插件化开发(四):插件化实现方案

    在经过上面铺垫后,我们可以尝试整体实现一下插件化了.这里我们先介绍一下最简单的实现插件化的方案. 一.最简单的插件化实现方案 最简单的插件化实现方案,对四大组件都是适用的,技术面涉及如下: 1). 合 ...

随机推荐

  1. 三、MapReduce编程实例

    前文 一.CentOS7 hadoop3.3.1安装(单机分布式.伪分布式.分布式 二.JAVA API实现HDFS MapReduce编程实例 @ 目录 前文 MapReduce编程实例 前言 注意 ...

  2. [Net 6 AspNetCore Bug] 解决返回IAsyncEnumerable<T>类型时抛出的OperationCanceledException会被AspNetCore 框架吞掉的Bug

    记录一个我认为是Net6 Aspnetcore 框架的一个Bug Bug描述 在 Net6 的apsnecore项目中, 如果我们(满足以下所有条件) api的返回类型是IAsyncEnumerabl ...

  3. git使用大全

    创建四个分支: 查看分支:git branch查看仓库里面所有的分支 git branch -a刷新分支 git remote update origin --prune创建分支:git branch ...

  4. js数组常用添加方法有两种

        //头部     //this.list.unshift({name:this.itemName,date:new Date()});     //尾部         this.list.p ...

  5. CF708E Student's Camp

    麻麻我会做*3100的计数了,我出息了 考虑朴素DP我们怎么做呢. 设\(f_{i,l,r}\)为第\(i\)层选择\(l,r\)的依旧不倒的概率. \(q(l,r)\)表示经历了\(k\)天后,存活 ...

  6. Codeforces 286E - Ladies' Shop(FFT)

    Codeforces 题面传送门 & 洛谷题面传送门 好久没刷过 FFT/NTT 的题了,写篇题解罢( 首先考虑什么样的集合 \(T\) 符合条件.我们考察一个 \(x\in S\),根据题意 ...

  7. Codeforces 1303G - Sum of Prefix Sums(李超线段树+点分治)

    Codeforces 题面传送门 & 洛谷题面传送门 个人感觉这题称不上毒瘤. 首先看到选一条路径之类的字眼可以轻松想到点分治,也就是我们每次取原树的重心 \(r\) 并将路径分为经过重心和不 ...

  8. C++ and OO Num. Comp. Sci. Eng. - Part 3.

    2. Expressions and Statements 声明是将一个种类型的变量引入程序的语句. 作用域 作用域又一对花括号限定,在所有花括号之外的为全局作用域. 在作用域内声明的变量为局部变量. ...

  9. Linux中gz文件操作遇到的一些技巧和坑

    目录 不解压情况下获取gz超大文件的前/后几行? Perl读入gz文件操作? 不能直接通过wc -l 来统计gz文件的行数 前提是gz文件超大,如上百G,肯定不能直接解压来做. 不解压情况下获取gz超 ...

  10. 41-Climbing Stairs-leetcode

    Climbing Stairs My Submissions QuestionEditorial Solution Total Accepted: 106498 Total Submissions: ...