简介
DexClassLoader 是Android系统中特有的类加载器,其父类为ClassLoader,插件开发主要就是利用了DexClassLoader来实现动态加载类,以便实现动态切换各种功能。
实践
首先一般开发是提供Service的通用接口。此处为CommonService.java ,可导出jar以方便为其他人使用【PluginService.jar】。
public interface CommonService {
/**
* say Hello
*/
public void sayHello();
/**
* get sum
*
* @param a
* @param b
* @return
*/
public int add(int a, int b);
}
2.新建一个Application,实现上述接口,可为普通java jar包插件(只是业务),也可以为apk应用插件(主题,资源等)。
public class ServiceImpl implements CommonService {
@Override
public void sayHello() {
// TODO Auto-generated method stub
Log.e("ServiceImpl", "sayHello");
}
@Override
public int add(int a, int b) {
// TODO Auto-generated method stub
return a+b;
}
}
并修改应用程序配置文件中如下
<activity
android:name="xx.xx.plugin.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<action android:name="xx.xx.plugin_1.ACTION" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
3.在自己的主程序中导入PluginService.jar
/**
* 定义一个插件的Action
*/
public static final String PLUGIN_1_ACTION = "xx.xx.plugin_1.ACTION";
protected void onPluginLoading() {
// 创建一个查找apk意图
Intent intent = new Intent(PLUGIN_1_ACTION, null);
// 获得应用程序包名
PackageManager pm = getPackageManager();
List<ResolveInfo> resolveinfoes = pm.queryIntentActivities(intent, 0);
ActivityInfo actInfo = resolveinfoes.get(0).activityInfo;
String pacageName = actInfo.packageName;
// 获得apk的目录或者jar的文件Path
String apkPath = actInfo.applicationInfo.sourceDir;
//解压后的目录 一般在/data/data/XXXX 自己的私有程序包内
String dexOutputDir = getApplicationInfo().dataDir;
// native代码的目录
String libPath = actInfo.applicationInfo.nativeLibraryDir;
// 创建dex类加载器
DexClassLoader classLoader = new DexClassLoader(apkPath, dexOutputDir,
libPath, getClassLoader());
// 利用反射调用插件包内的类的方法
try {
String className = pacageName+".ServiceImpl";
Class<?> clazz = Class.forName(className, true, classLoader);
// Class<?> clazz = classLoader.loadClass(className);
CommonService obj = (CommonService) clazz.newInstance();
obj.sayHello();
Log.e("Host", "return result is " + obj.add(1, 13));
} catch (Exception e) {
e.printStackTrace();
}
}
先安装apk插件或copy jar文件到制定目录,然后再运行主程序,结果如下:
注意事项:
1.如果出现 ERROR/AndroidRuntime(12705): java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation.一般是因为存在重复的类文件导致的,因为一般主程序直接引用jar包,系统会自动导出该依赖包,所以可以检查插件apk中是否重复导出了PluginService.jar
2.如果运行主程序出现找不到接口,可以查看是否正确导入依赖包PluginService.jar
差不多就是这个样子了,