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中可以通过下面方法获取:

  

原文地址:https://www.cnblogs.com/bokeofzp/p/6667637.html