1.把class文件打包成dex文件。
在android-sdk/build-tool下有个dx脚本工具,可以将class文件打包成dex文件。
dx --dex --no-strict --output <输出dex路径> <class文件路径>
2.将dex文件放入手机中的某个路径下。
3.使用DexClassLoader加载dex文件中的类。
Activity代码:
package com.champion.loaddexdemo;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import junit.framework.Assert;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import dalvik.system.DexClassLoader;
public class MainActivity extends AppCompatActivity {
int storageRequestCode = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(PackageManager.PERMISSION_DENIED == checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)){
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, storageRequestCode);
}
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//本例中是将out.dex放在sdcard根目录下
File dexFile = new File(Environment.getExternalStorageDirectory(), "out.dex");
if(!dexFile.exists()){
System.out.println("dexFile not exists");
return;
}
File odexDir = getDir("odex", Context.MODE_PRIVATE);
if(!odexDir.exists()){
System.out.println("odexDir not exists");
odexDir.mkdir();
}
//新建一个DexClassLoader,以dex文件的路径为参数,传入一个放置odex文件的文件夹路径
DexClassLoader dexClassLoader = new DexClassLoader(dexFile.getAbsolutePath(),
odexDir.getAbsolutePath(), null, getClassLoader());
try {
//使用dexClassLoader进行加载dex文件中的类
Class clazz = dexClassLoader.loadClass("com.champion.loaddexdemo.dynanmicLoadedTest");
Object object = clazz.newInstance();
//调用类中的方法
Method method = clazz.getMethod("load");
method.invoke(object);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
});
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode == storageRequestCode){
System.out.println("request code success!!!!!");
}
}
}
被加载的测试类代码:
package com.champion.loaddexdemo;
public class dynanmicLoadedTest {
static {
System.out.println("static load success!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
}
public void load(){
System.out.println("load+++++++++++++++++++++++++++++++++");
}
}
高版本JDK导致的问题:-Djava.ext.dirs=C:\Users\zhangjb\AppData\Local\Android\Sdk\build-tools\28.0.0\lib is not supported
原因:JDK大于9,新增了--class-path,不支持原来的-Djava.ext.dirs属性
解决方法:打开dx.bat,将-Djava.ext.dirs替换为--class-path
高版本Android导致的问题:java.io.IOException: No original dex files found for dex location (arm64) /sdcard/lib.dex
原因:不知道,Android有意限制不能在不属于应用的外部存储中吧
解决方法:把dex文件或者apk放到应用内部存储空间,如应用cache ,通过getExternalCacheDir获取