Dalvik虚拟机如同其他Java虚拟机一样,在运行程序时首先需要将对应的类加载到内存中。而在Java标准的虚拟机中,类加载可以从class文件中读取,也可以是其他形式的二进制流,因此,我们常常利用这一点,在程序运行时手动加载Class,从而达到代码动态加载执行的目的,但是Dalvik虚拟机毕竟不算是标准的Java虚拟机。
DexClassLoader:可以加载jar/apk/dex,可以从SDK中加载未加载的apk、PathClassLOader:要传入系统中Apk的存放Path,所以只能加载已经安装的apk文件。与jvm不同的是Dalvik不能直接加载.dex文件,而是要通过从ClassLoader派生出的两个类 DexClassLoader和PathClassLoader来加载.dex文件。
写File --> new --> new Module --> Android Library,编辑gradle文件:
def SDK_BASENAME = "TestSdk";
def SDK_VERSION = "_V1.00.02_20180224";
def sdkDestinationPath = "build";
def zipFile = file('build/intermediates/bundles/default/classes.jar')
task deleteBuild(type: Delete) {
/*delete sdkDestinationPath + SDK_BASENAME + SDK_VERSION + ".jar"*/
delete 'build/libs/'
}
task makeJar(type: Jar) {
// 从哪里打包class文件
from zipTree(zipFile)
// 另外引用的jar
from (project.zipTree("libs/aaaa.jar"))
// 另外引用的jar
from (project.zipTree("libs/bbbbb.jar"))
baseName = SDK_BASENAME + SDK_VERSION
// 打包到jar后的目录,这里直接放在build文件夹下
destinationDir = file(sdkDestinationPath)
//去掉不需要打包的目录和文件
//exclude('text/', 'Dynamic.class', 'R.class', 'BuildConfig.class')
//去掉R$开头的文件
//exclude { it.name.startsWith('R$'); }
}
makeJar.dependsOn(deleteBuild, build)
然后使用Android Studio右侧的Gradle图形化工具,选择Your Moudle->Tasks->other->执行makejar即可。
此时会在build目录下生成我们的jar文件,但是要注意此时的jar文件虽然可以作为lib放进项目中进行依赖,但是并不能作为插件被动态加载,还需要将生成的jar文件转换成可以被Dalvik虚拟机识别的dex文件:
进入Android SDK目录
D:\Android\assdk\build-tools\28.0.3
执行
dx --dex --output=虚拟机能识别.jar AndroidStudio生成.jar
然后把“虚拟机能识别.jar”拷贝到内部存储目录下(手动或代码拷贝),在代码中即可使用该插件。
比如我拷贝到/system/plugin/OceanusPlugin.jar目录下,要加载的类为:com.sky.pluginimpl.Show,那么使用例子:
public class LoadSkyMarketPlugin {
private static String jarPath = "/system/plugin/OceanusPlugin.jar";
private final static String pluginClazz = "com.sky.pluginimpl.Show";
private static TCBaseShow mSkyShowApi = null;
private static final String TAG = "LoadSkyMarketPlugin";
public static TCBaseShow loadClass(Context context) {
try {
File optimizedDexOutputPath = new File(jarPath);
if (optimizedDexOutputPath.exists()) {
DexClassLoader cl = new DexClassLoader(
jarPath,
context.getDir("dex", 0).getAbsolutePath(),
null,
context.getClassLoader());
mSkyShowApi = (TCBaseShow) cl.loadClass(pluginClazz).newInstance();
}
} catch (Exception e) {
Debugger.d(TAG, "loadClass-->>" + e.getMessage());
return null;
}
if (mSkyShowApi != null) {
int value = mSkyShowApi.getImageShowApi().getAccurateColorControlBlue();
Debugger.d(TAG, "value=" + value);
}
return mSkyShowApi;
}
}