android 类加载器 DexClassLoader的用法,以及引出的插件架构
1、android 类加载器(DexClassLoader的用法),调用其他apk的类中的方法:
方式一:
然后在Host中利用下面的方式调用
PackageManager pm = getPackageManager(); List<ResolveInfo> resolveInfos = pm.queryIntentActivities(new Intent("com.haili.Plugin.client") , 0); ResolveInfo resolveInfo = resolveInfos.get(0); ActivityInfo activityInfo =resolveInfo.activityInfo; String packageName = activityInfo.packageName; String dexPath = activityInfo.applicationInfo.sourceDir; // 目标类所在的apk或jar所在的路径,加载器将在此目录寻找目标类 String dexOutputDir = getApplicationInfo().dataDir; // dex包含在apk或者jar文件中,因此在装载目标类的时候需要先解压,此路径就是解压的路径 String libPath = activityInfo.applicationInfo.nativeLibraryDir; // 目标使用的一些C、C++库的路径 DexClassLoader dexClassLoader = new DexClassLoader(dexPath , dexOutputDir , libPath ,this.getClass().getClassLoader()); //利用java反射原理的方式来调用 try { Class clazz = dexClassLoader.loadClass(packageName+"."+ "Plugin"); Object object = clazz.newInstance(); Method method = clazz.getMethod("function" , Integer.TYPE ,Integer.TYPE); int addResult = (int) method.invoke(object ,12 ,34); }catch (Exception e) { }
方式二:利用插件的方式来实现:
1 、在host中定义comm的接口如下;然后生成外部jar包,然后必须以Library的方式添加到Plugin中,若以“外部jar方式”添加,jar会作为程序的一部分打包到最终文件中,导致Plugin和Host中有2份Comm(包名和类名相同),导致冲突,发生:Class ref in pre-verified class resolved to unexpected implementation错误。
public interface Comm { public int function(int a , int b); }
2、将Plugin的class的代码修改如下:
public class Plugin implements Comm { ... public int function(int a ,int b) { return a + b ; } }
3 、 在Host调用的时候
PackageManager pm = getPackageManager(); List<ResolveInfo> resolveInfos = pm.queryIntentActivities(new Intent("com.haili.Plugin.client") , 0); ResolveInfo resolveInfo = resolveInfos.get(0); ActivityInfo activityInfo =resolveInfo.activityInfo; String packageName = activityInfo.packageName; String dexPath = activityInfo.applicationInfo.sourceDir; // 目标类所在的apk或jar所在的路径,加载器将在此目录寻找目标类 String dexOutputDir = getApplicationInfo().dataDir; // dex包含在apk或者jar文件中,因此在装载目标类的时候需要先解压,此路径就是解压的路径 String libPath = activityInfo.applicationInfo.nativeLibraryDir; // 目标使用的一些C、C++库的路径 DexClassLoader dexClassLoader = new DexClassLoader(dexPath , dexOutputDir , libPath ,this.getClass().getClassLoader()); //利用插件的方式调用 try { Class clazz = dexClassLoader.loadClass(packageName+"."+ "Plugin"); Comm comm = (Comm)clazz.newInstance(); int addResult = comm.function(12 , 34); }catch (Exception exception) { }
二、插件架构
所谓插件,就是由宿主车内光线调用插件,如浏览器的插件,浏览器就是Host,调用的插件Plugin:
由上面利用插件架构的方式实现可以得出插件的基本概率和特点:
主要结构:
1、在Host中定义相关接口Comm,生成jar包以library的方式导入到Plugin中。
2、Plugin中要实现插件功能相关的类中实现接口Comm.
3、在Host 中用上面的方法加载plugin的类,并调用Plugin中实现的方法。
Note:为了知晓有哪些插件,Host中可以为每一个插件定义一个特定的action字段,每个插件定义一个activity,并在插件Plugin中AndroidMainfest.xml清单文件定义一个空的activity,action设置为Host中插件的字段:这样Host就可以根据字段查询相应的插件从而查找相应的类和方法。
插件和宿主的兼容性,插件的res/values/string中一般都会定义一些版本号以及一些名称信息,在Host中可以通过下面方法获取: