场景:
手机内安装两个应用A和B,B通过DexClassLoader调用A中的方法
原理:
1.通过Intent查询系统注册的A应用的Activity信息
2.从得到的Activity信息中得到A应用的包名,apk或jar存放路径等信息
3.通过得到A应用的信息构造DexClassLoader对象
4.得到的DexClassLoader对象是和应用A关联起来的,然后去通过DexClassLoader对象加载你需要使用的类。
5.通过反射调用A应用的里面的方法。
A应用实现:
创A工程,包名为com.cn.plugin,在com.cn.plugin目录下创建一个类
package com.cn.plugin;
import android.util.Log;
public class PluginClass {
public PluginClass() {
Log.i("Plugin", "PluginClass client initialized");
}
public int function1(int a, int b) {
return a + b;
}
}
然后给A的一个Activity配置一个Action,这里直接个MainActivty设置一个Action
给应用A的MainActivity指定了一个Action为”com.cn.plugin.client”至此,应用A的工作做完了,安装应用A。
新建工程B,在B中调用下面函数
public void useDexClassLoader() {
Intent intent = new Intent("com.cn.plugin.client", null);
PackageManager pm = getPackageManager();
//通过Intent查询ResolveInfo
final List plugins = pm.queryIntentActivities(intent, 0);
//取出第一个ResolveInfo,因为这只是一个Demo,所以直接取第一个就是我们所要的A中MainActivity信息
ResolveInfo rInfo = plugins.get(0);
//得到A应用的Activity信息
ActivityInfo aInfo = rInfo.activityInfo;
//通过ActivityInfo得到构造DexClassLoader对象的参数信息
String packageName = aInfo.packageName;
String dexPath = aInfo.applicationInfo.sourceDir;
String dexOutputDir = getApplicationInfo().dataDir;
String libPath = aInfo.applicationInfo.nativeLibraryDir;
Log.d("TAG", "packageName is : " + packageName + "\n" + "dexPath is : "
+ dexPath + "\ndexOutputDir is : " + dexOutputDir
+ "\nlibPath is : " + libPath);
//构造ClassLoader对象
DexClassLoader classLoader = new DexClassLoader(dexPath, dexOutputDir,
libPath, getClass().getClassLoader());
try {
//通过全路径名加载PluginClass类
Class> clazz = classLoader
.loadClass(packageName + ".PluginClass");
//构造PluginClass对象
Object obj = clazz.newInstance();
Class>[] params = new Class[2];
params[0] = Integer.TYPE;
params[1] = Integer.TYPE;
//反射调用function1方法
Method action = clazz.getMethod("function1", params);
Integer ret = (Integer) action.invoke(obj, 12, 34);
Log.i("Host", "return value is " + ret);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
安装B应用,在调用的地方查看打印如下:
12-30 23:53:08.077: D/TAG(19891): packageName is : com.cn.plugin
12-30 23:53:08.077: D/TAG(19891): dexPath is : /data/app/com.cn.plugin-1/base.apk
12-30 23:53:08.077: D/TAG(19891): dexOutputDir is : /data/user/0/com.cn.host
12-30 23:53:08.077: D/TAG(19891): libPath is : /data/app/com.cn.plugin-1/lib/arm64
12-30 23:53:08.083: W/System(19891): ClassLoader referenced unknown path: /data/app/com.cn.plugin-1/lib/arm64
12-30 23:53:08.084: I/Plugin(19891): PluginClass client initialized
12-30 23:53:08.084: I/Host(19891): return value is 46
成功的通过B应用调用A应用的方法完成了两个数的相加。