程序员人生 网站导航

Android 使用DexClassLoader来运行其他apk中的方法

栏目:互联网时间:2014-11-21 08:55:28

       Android中apk文件里的dex文件是对java编译出来的.class文件进行重新打包,固然在打包之前会利用自己的协议做1些数据处理,例如优化函数表和变量表。在java程序中是使用classloader来加载这些编译生成的.class文件,但是在android程序中是通过DexClassLoader来装载这些文件的.这里我们就能够通过DexClassLoader在程序A里面动态装载程序B中的类,并且来调用B程序中的方法.


     1.首先先建立1个普通的Android工程,在这个工程中定义1个叫做plugin的类,类中实现1个简单的方法,以下所示:

<span style="font-size:14px;">public class PluginClass { private static String TAG = PluginClass.class.getSimpleName(); public PluginClass(){ Log.i(TAG, "initialized"); } public void invoke(String s){ Log.i(TAG, s); } }</span>
      2.将这个Android工程运行到安卓装备当中去

      3.再重新建立1个Android工程,其中定义1个叫做host的类,在这个类中实现DexClassLoader动态加载第1个工程中的plugin类,以下所示:

<span style="font-size:14px;">public class HostClass { private static String TAG = HostClass.class.getSimpleName(); private Context mContext = null; public HostClass(Context contect){ mContext = contect; } public void useDexClassLoader(){ Intent intent = new Intent(); intent.setPackage("com.example.plugin"); PackageManager pm = mContext.getPackageManager(); final List<ResolveInfo> plugins = pm.queryIntentActivities(intent,0); if(plugins.size() <= 0){ Log.i(TAG, "resolve info size is:" + plugins.size()); return; } ResolveInfo resolveInfo = plugins.get(0); ActivityInfo activityInfo = resolveInfo.activityInfo; String div = System.getProperty("path.separator"); String packageName = activityInfo.packageName; String dexPath = activityInfo.applicationInfo.sourceDir; //目标类所在的apk或jar的路径,class loader会通过这个路径来加载目标类文件 String dexOutputDir = mContext.getApplicationInfo().dataDir; //由于dex文件是包括在apk或jar文件中的,所以在加载class之前就需要先将dex文件解压出来,dexOutputDir为解压路径 String libPath = activityInfo.applicationInfo.nativeLibraryDir; //目标类可能使用的c或c++的库文件的寄存路径 Log.i(TAG, "div:" + div + " " + "packageName:" + packageName + " " + "dexPath:" + dexPath + " " + "dexOutputDir:" + dexOutputDir + " " + "libPath:" + libPath); DexClassLoader dcLoader = new DexClassLoader(dexPath,dexOutputDir,libPath,this.getClass().getClassLoader()); try { Class<?> clazz = dcLoader.loadClass(packageName + ".PluginClass"); Object obj = clazz.newInstance(); Class[] param = new Class[1]; param[0] = String.class; Method action = clazz.getMethod("invoke", param); action.invoke(obj, "test this function"); } catch (ClassNotFoundException e) { Log.i(TAG, "ClassNotFoundException"); } catch (InstantiationException e) { Log.i(TAG, "InstantiationException"); } catch (IllegalAccessException e) { Log.i(TAG, "IllegalAccessException"); } catch (NoSuchMethodException e) { Log.i(TAG, "NoSuchMethodException"); } catch (IllegalArgumentException e) { Log.i(TAG, "IllegalArgumentException"); } catch (InvocationTargetException e) { Log.i(TAG, "InvocationTargetException"); } } }</span>
    4.运行第2个工程以后查看log就会发现host通过DexClassLoader加载了pluginclass类,并成功调用了plugin中的方法
<span style="font-size:14px;">I/HostClass( 8341): div:: packageName:com.example.plugin dexPath:/data/app/com.example.plugin⑴.apk dexOutputDir:/data/data/com.example.host libPath:/data/app-lib/com.example.plugin⑴ D/dalvikvm( 8341): DexOpt: --- BEGIN 'com.example.plugin⑴.apk' (bootstrap=0) --- D/dalvikvm( 8341): DexOpt: --- END 'com.example.plugin⑴.apk' (success) --- D/dalvikvm( 8341): DEX prep '/data/app/com.example.plugin⑴.apk': unzip in 39ms, rewrite 723ms I/PluginClass( 8341): initialized I/PluginClass( 8341): test this function D/libEGL ( 8341): loaded /system/lib/egl/libEGL_mali.so D/libEGL ( 8341): loaded /system/lib/egl/libGLESv1_CM_mali.so D/libEGL ( 8341): loaded /system/lib/egl/libGLESv2_mali.so D/OpenGLRenderer( 8341): Enabling debug mode 0 I/HostClass( 8341): div:: packageName:com.example.plugin dexPath:/data/app/com.example.plugin⑴.apk dexOutputDir:/data/data/com.example.host libPath:/data/app-lib/com.example.plugin⑴ I/PluginClass( 8341): initialized I/PluginClass( 8341): test this function</span>


------分隔线----------------------------
------分隔线----------------------------

最新技术推荐