android基于类装载器DexClassloader设计“插件框架”

转载 2015年07月10日 10:47:47
插件相关介绍
    首先插件只是一个逻辑概念,而不是什么技术标准,主要包含如下几个意思:
  • 插件不能独立运行,必须运行一个宿主程序中,宿主程序去调用插件(ps:微信的游戏算不算插件?感觉算是一种)
  • 插件一般情况下可以独立安装,android中就可以设计一个apk
  • 宿主程序中可以管理插件,比如添加,删除,禁用等。
  • 宿主程序应该保证插件向下兼容,新的宿主程序应该兼容老的插件
   新浪微博的主题就是通过插件实现的切换。
   
由于ClassLoader具有动态装载程序的特点,因此可以使用此技术来一种插件框架。下面就是实现的细节。
使用DexClassLoader实现插件框架
大家了解高焕堂老师的EIT造型吗?如果不了解的话可以去网上搜一下,这种造型可以用来设计一个插件,一个框架,甚至一个平台。
高老师总结的确实精炼,容易理解,很多设计模式都是在这个EIT的之上或者变型生做的设计。
那么今天咱们用到EIT造型了吗?当然用到了,咱们直接上代码吧。
上一篇博客中是通过反射调用插件中的类的方法的,今天咱们要把接口作为联系主程序和插件程序的桥梁。
要实现住程序通过接口调用插件的程序,那么主程序和插件程序必须有相同的接口文件,也就是两个程序里都有接口的java类文件。
首先,在主程序里定义一个接口文件,然后原样的copy到插件程序中去,接口如下:
package com.suchangli.plugin;
public interface CommonInterface {
int function1(int a, int b);
}
包结构如下所示:
宿主程序:
插件程序
主程序的代码修改成使用接口
[java] view plaincopy
  1. @Override  
  2.     protected void onCreate(Bundle savedInstanceState) {  
  3.         super.onCreate(savedInstanceState);  
  4.         setContentView(R.layout.activity_main);  
  5.         useDexClassLoader2();  
  6.     }  
  7.     @SuppressLint("NewApi"private void useDexClassLoader2(){  
  8.         //创建一个意图,用来找到指定的apk  
  9.         Intent intent = new Intent("com.suchangli.android.plugin"null);  
  10.         //获得包管理器  
  11.         PackageManager pm = getPackageManager();  
  12.         List<ResolveInfo> resolveinfoes =  pm.queryIntentActivities(intent, 0);  
  13.         //获得指定的activity的信息  
  14.         ActivityInfo actInfo = resolveinfoes.get(0).activityInfo;  
  15.           
  16.         //获得包名  
  17.         String pacageName = actInfo.packageName;  
  18.         //获得apk的目录或者jar的目录  
  19.         String apkPath = actInfo.applicationInfo.sourceDir;  
  20.         //dex解压后的目录,注意,这个用宿主程序的目录,android中只允许程序读取写自己  
  21.         //目录下的文件  
  22.         String dexOutputDir = getApplicationInfo().dataDir;  
  23.           
  24.         //native代码的目录  
  25.         String libPath = actInfo.applicationInfo.nativeLibraryDir;  
  26.         //创建类加载器,把dex加载到虚拟机中  
  27.         DexClassLoader calssLoader = new DexClassLoader(apkPath, dexOutputDir, libPath,  
  28.                 this.getClass().getClassLoader());  
  29.           
  30.         //利用反射调用插件包内的类的方法  
  31.           
  32.         try {  
  33.             Class<?> clazz = calssLoader.loadClass(pacageName+".Plugin1");  
  34.               
  35.             CommonInterface obj = (CommonInterface)clazz.newInstance();  
  36.                
  37.               
  38.             int ret = obj.function1(113);  
  39.               
  40.             Log.i("Host""return result is " + ret);  
  41.               
  42.         } catch (ClassNotFoundException e) {  
  43.             e.printStackTrace();  
  44.         } catch (InstantiationException e) {  
  45.             e.printStackTrace();  
  46.         } catch (IllegalAccessException e) {  
  47.             e.printStackTrace();  
  48.         } catch (IllegalArgumentException e) {  
  49.             e.printStackTrace();  
  50.         }    
  51.     }  
也就这几句代码不同:
插件程序的类现接口:
[java] view plaincopy
  1. package com.suchangli.plugin1;  
  2.   
  3. import com.suchangli.plugin.CommonInterface;  
  4.   
  5. public class Plugin1 implements CommonInterface{  
  6.     public int function1(int a, int b){  
  7.           
  8.         return a+b;  
  9.     }  
  10. }  
直接安装两个程序,调用的时候会报这种错误:
copy过去报错,并且这种方式也不太现实,因为提供给插件开发者的时候肯定是以jar包的形式进行提供,而不是以原文件的形式提供,
更何况现在还报错。究其原因是什么呢?
其实是这样的,这个java文件被当做程序的一部分(本来就是一部分)(jar包是以外部jar的方式添加进去的,外部jar包会作为程序的一部分被最终的程序文件中,也会报同样的错误),从而使得在主程序和插件程序中存在包名相同但验证码不同的类文件。
导出jar包,这个大家应该都会,不会的到网上搜一下。
把jar包放进插件的libs文件加下
引用jar包
使用红色框的“Add Libary”,而不是蓝色框的“Add External JARs”.
如果还是不行就通过这种方式:
再重新安装一次插件,运行一次主程序,结果如下:
主程序如何搜索到插件的,是在插件程序的menifest.xml文件中,定义了一个activity,定义了一个action:
这样主程序就可以使用PacageManager类的queryIntentActivites()方法查询相关的插件程序列表了。
程序主题插件的实现
在主程序中添加如下一个方法:
[java] view plaincopy
  1. private void useDexClassloader3(){  
  2.         //创建一个意图,用来找到指定的apk  
  3.         Intent intent = new Intent("com.suchangli.android.plugin"null);  
  4.         //获得包管理器  
  5.         PackageManager pm = getPackageManager();  
  6.         List<ResolveInfo> resolveinfoes =  pm.queryIntentActivities(intent, 0);  
  7.         //获得指定的activity的信息  
  8.         ActivityInfo actInfo = resolveinfoes.get(0).activityInfo;  
  9.           
  10.         //获得包名  
  11.         String pacageName = actInfo.packageName;  
  12.            
  13.         try {  
  14.             Resources res = pm.getResourcesForApplication(pacageName);  
  15.               
  16.             int id = 0;  
  17.             id = res.getIdentifier("ic_launcher""drawable", pacageName);  
  18.             Log.i("""resId is " + id);  
  19.               
  20.               
  21.         } catch (NameNotFoundException e) {  
  22.             e.printStackTrace();  
  23.         }  
  24.     }  
从上面的代码可以看出,我们能获得插件程序的资源文件的id,那么资源文件就很容易获得了,使用插件的形式进行主题替换就会很容易实现了。
期待大家能在DexClassLoader的基础上开发出一个开源的插件框架,或者通用的程序主题替换程序架构。
如果想一块写这种开源框架的可以和我联系,我能帮忙的尽量帮忙。谢谢大家了。

android基于类装载器DexClassloader设计“插件框架”

@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInsta...
  • com360
  • com360
  • 2013年11月04日 16:44
  • 9331

android基于类装载器DexClassloader设计“插件框架”

转载:http://blog.csdn.net/com360/article/details/14127395 插件相关介绍     首先插件只是一个逻辑概念,而不是什...

Android中的类装载器DexClassLoader

转载: http://blog.csdn.net/com360/article/details/14125683 类装载器DexClassLoader的介绍      在java...

Android类装载器DexClassLoader的简单使用

转自:http://www.cnblogs.com/dividxiaoshuo-fighting/p/3682398.html?utm_source=tuicool 一、装载器简介 ...

类装载器DexClassLoader (android内核剖析)

在java环境中,有个概念叫做“类装载器”,其作用是动态装载Class文件。标准的java SDK中有一个ClassLoader类,借助它可以装载 想要的Class文件,每个Classoader对象在...
  • asd1031
  • asd1031
  • 2013年12月07日 21:18
  • 785

Android学习之DexClassLoader类装载器使用

参考 柯元旦:《Android内核剖析》第2.1.1/2.1.2 下载demo 在Java环境中,有个概念叫做“类装载器”(ClassLoader),其作用是动态装载Class文件。标准的Java...

Android 程序插件框架基于DexClassLoader

插件相关介绍     首先插件只是一个逻辑概念,而不是什么技术标准,主要包含如下几个意思: 插件不能独立运行,必须运行一个宿主程序中,宿主程序去调用插件(ps:微信的游戏算不算...

Android插件化探索(一)类加载器DexClassLoader

本文部分内容参考自《Android内核剖析》 基本概念 在Java环境中,有个概念叫做“类加载器”(ClassLoader),其作用是动态装载Class文件。标准的Java SDK中有一个C...

Android插件化探索(一)类加载器DexClassLoader

本文出自maplejaw的博客(http://blog.csdn.net/maplejaw_)  本文部分内容参考自《Android内核剖析》 基本概念 在Java环境中,有个概...

Android插件化探索(一)类加载器DexClassLoader

在Java环境中,有个概念叫做“类加载器”(ClassLoader),其作用是动态装载Class文件。标准的Java SDK中有一个ClassLoader类,借助它可以装载想要的Class文件,每个C...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:android基于类装载器DexClassloader设计“插件框架”
举报原因:
原因补充:

(最多只允许输入30个字)