什么时候需要用到动态加载jar包呢?
- 减少apk本身大小,某些界面才需要用jar里的功能
- jar中的功能可以独立开发,不要依赖其它的东西,能适用各个项目
- 和第三方公司合作,人家不提供项目源码给你,但又要开发他们使用的某些应用场景
实现步骤:
1. 编写jar的代码
新建一个service module,编写以下代码
public interface AbstractAction {
/**
* 开始
* @param c
*/
void start(Context c);
/**
* 停止
*/
void stop();
}
public class MainAction implements AbstractAction {
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public void start(Context c) {
TaskManager.getInstance().start(c);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
@Override
public void stop() {
TaskManager.getInstance().stop();
}
}
public class TaskManager {
private volatile static TaskManager instance = null;
private boolean isRun = true;
private TaskManager() {
}
public static TaskManager getInstance() {
if (instance == null) {
synchronized (TaskManager.class) {
if (instance == null) {
instance = new TaskManager();
}
}
}
return instance;
}
/**
* 初始化
*
* @param context
*/
public void start(Context context) {
// 做自己想做的事
new Thread() {
@Override
public void run() {
while (isRun)
Log.i("xian", " 执行任务中... ");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
}
public void stop() {
isRun = false;
}
}
2. 将代码打包并jar转换为 android 可以使用的jar(dex)包
由于android不能直接像java程序那样直接引用jar包, 需要转换dex才行
1. 在module中的 build.gradle 文件中,加入以下代码,生成jar包。输出路径为
task makeJar(type: Copy) {
//删除已经存在的 jar
delete 'build/libs/test-java.jar'
//设置拷贝的文件
from('build/intermediates/aar_main_jar/release/')
//打进jar包后的文件目录
into('build/libs/')
include('classes.jar')
//重命名
rename ('classes.jar', 'test-java.jar')
}
makeJar.dependsOn(build)
2.执行makeJar Task, 一种是点击 task makeJar(tyoe.Copy)前面的绿色小三角运行,另外一种可以打开gardle,然后找到 service --> other --> makeJar 运行
3.运行完后,就会在 serice/ --> build --> lib下生成 test-java.jar
4. 使用android sdk --> build-tools --> 30.0.2(任意一个版本) --> dx 配置为环境变量 (如果觉得此操作麻烦,可以使用步骤5的方法)
windows 的电脑, 右击 我的电脑 --> 属性 --> 高级系统设置 --> path --> 添加 dx的路径 --> 保存
5. 如果不想配置环境变量,可以win+R --> cmd 打开控制台, 输入 D:\Android\Sdk\build-tools\30.0.2(我的sdk存放的路径),然后 D: 回车, 切换到D盘路径,如下图:
![在这里插入图片描述](https://img-blog.csdnimg.cn/d5d4b1c6797741d18c1453389be2caa5.png
6.将步骤3生成好的test-java.jar 包,拷贝到桌面,如果配置了环境变量可以直接使用dx命令,没有配置的话,就进入 sdk目录中的dx所在的目录,执行dx命令。 执行完命令后,就可以生成Android 可以调用的 test.jar 了
dx --dex --output=C:\Users\dell\Desktop\test.jar C:\Users\dell\Desktop\test-java.jar
3. 动态调用jar包
将成功后 test.jar 拷贝到手机的目录中,然后在项目中调用jar ,如果看到执行任务中… 就证明调用成功。
/**
* 使用dexClassLoader 动态加载test.jar,然后通过反射调用方法即可
*
* @param view
*/
fun loadJar(view: View) {
if (!PermissionUtils.checkPermission(this)) {
Toast.makeText(this,"没有文件读写权限",Toast.LENGTH_LONG).show()
//跳转到设置权限界面
PermissionUtils.requestAppUsagePermission(this);
return
}
val pluginPath = File(getExternalFilesDir(null)?.absolutePath + "/test.jar")
Log.i("xian","jar 包存放路径: ${pluginPath}")
val dataFile: String = codeCacheDir.absolutePath
try {
val classLoader =
DexClassLoader(pluginPath.absolutePath, dataFile, null, javaClass.classLoader)
val mainActionClass = classLoader.loadClass("com.xian.service.main.MainAction");
val mainAction = mainActionClass.newInstance()
//开始执行
mainActionClass.getDeclaredMethod("start", Context::class.java)
.invoke(mainAction, this)
}catch (e:Throwable){
// 路径记得放对 ,否则会报 ClassLoader referenced unknown path
e.printStackTrace()
}
}
注意: 1. 申请读写权限 2.test.jar的存放路径