Android中的类装载器DexClassLoader

转发 : http://blog.csdn.net/com360/article/details/14125683

类装载器DexClassLoader的介绍

   

 在java中,有个概念叫做“类加载器”(ClassLoader),它的作用就是动态的装载Class文件。标准的java sdk中有一个

ClassLoader类,借助这个类可以装载想要的Class文件,每个ClassLoader对象在初始化时必须制定Class文件的路径。

    可能有人会问,在写程序的时候不是有import关键字可以引用制定的类吗?为何还要使用这个类加载器呢?

    原因其实是这样的,使用import关键字引用的类必须符合以下两个条件

  •    类文件必须在本地,当程序运行时需要次类时,这时类装载器会自动装载该类,程序员不需要关注此过程。
  •    编译的时候必须有这个类文件,否则编译不通过。

    如果想让程序在运行的时候动态调用怎么办呢?用import显示是不符合上面的两种要求的。此时ClassLoader就派上用场了。

    关于java的Classloader的装载机制请参考此链接 http://www.iteye.com/topic/83978,最好到网上自行搜索一下。

    http://www.artima.com/insidejvm/ed2/《Inside the Java Virtural Machine》

    对于android应用程序,本质上使用的是java开发,使用标准的java编译器编译出Class文件,和普通的java开发不同的

    地方是把class文件再重新打包成dex类型的文件,这种重新打包会对Class文件内部的各种函数表、变量表等进行优化,

    最终产生了dex文件。dex文件是一种经过android打包工具优化后的Class文件,因此加载这样特殊的Class文件就需要特殊的类装载器,

    所以android中提供了DexClassLoader类。

类装载器DexClassLoader类结构

继承关系:

    

A class loader that loads classes from .jar and .apk files containing a classes.dex entry.
This can be used to execute code not installed as part of an application.

This class loader requires an application-private, writable directory to cache optimized classes. Use Context.getDir(String, int) to create such a directory:

<span class="pln" style="color: rgb(0, 0, 0);">   </span><code style="line-height: 14px;"><span class="typ" style="color: rgb(102, 0, 102);">File</span><span class="pln" style="color: rgb(0, 0, 0);"> dexOutputDir </span><span class="pun" style="color: rgb(102, 102, 0);">=</span><span class="pln" style="color: rgb(0, 0, 0);"> context</span><span class="pun" style="color: rgb(102, 102, 0);">.</span><span class="pln" style="color: rgb(0, 0, 0);">getDir</span><span class="pun" style="color: rgb(102, 102, 0);">(</span><span class="str" style="color: rgb(136, 0, 0);">"dex"</span><span class="pun" style="color: rgb(102, 102, 0);">,</span><span class="pln" style="color: rgb(0, 0, 0);"> </span><span class="lit" style="color: rgb(0, 102, 102);">0</span><span class="pun" style="color: rgb(102, 102, 0);">);</span><span class="pln" style="color: rgb(0, 0, 0);">
 </span></code>

Do not cache optimized classes on external storage. External storage does not provide access controls necessary to protect your application from code injection attacks.

翻译:这个类加载器用来从.jar和.apk类型的文件内部加载classes.dex文件。通过这种方式可以用来执行非安装的程序代码,作为程序的一部分进行运行。

    这个装载类需要一个程序私有的,可写的文件目录去存放优化后的classes文件。通过Contexct.getDir(String, int)来创建

这个目录:

     File dexOutputDir = context.getDir("dex", 0);

不要把优化优化后的classes文件存放到外部存储设备上,防代码注入攻击。

这个类只有一个构造函数:

public DexClassLoader (String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent)

Added in API level 3

Creates a DexClassLoader that finds interpreted and native code. Interpreted classes are found in a set of DEX files contained
in Jar or APK files.

创建一个DexClassLoader用来找出指定的类和本地代码(c/c++代码)。用来解释执行在DEX文件中的class文件。

路径的分隔符使用通过System的属性 path.separator 获得 :.

String separeater = System.getProperty("path.separtor");

Parameters
dexPath 需要装载的APK或者Jar文件的路径。包含多个路径用File.pathSeparator间隔开,在Android上默认是 ":" 
optimizedDirectory 优化后的dex文件存放目录,不能为null
libraryPath 目标类中使用的C/C++库的列表,每个目录用File.pathSeparator间隔开; 可以为 null
parent 该类装载器的父装载器,一般用当前执行类的装载器

类装载器DexClassLoader的具体使用

这个类的使用过程基本是这样:

  • 通过PacageMangager获得指定的apk的安装的目录,dex的解压缩目录,c/c++库的目录
  • 创建一个 DexClassLoader实例
  • 加载指定的类返回一个Class
  • 然后使用反射调用这个Class

下面是代码部分,代码参考自《Android内核剖析》(作者柯元旦,这本书不错,推荐阅读):

[html] view
plain
copy

  1. @SuppressLint("NewApi") private void useDexClassLoader(){  
  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.     //获得apk的目录或者jar的目录  
  13.     String apkPath = actInfo.applicationInfo.sourceDir;  
  14.     //dex解压后的目录,注意,这个用宿主程序的目录,android中只允许程序读取写自己  
  15.     //目录下的文件  
  16.     String dexOutputDir = getApplicationInfo().dataDir;  
  17.       
  18.     //native代码的目录  
  19.     String libPath = actInfo.applicationInfo.nativeLibraryDir;  
  20.     //创建类加载器,把dex加载到虚拟机中  
  21.     DexClassLoader calssLoader = new DexClassLoader(apkPath, dexOutputDir, libPath,  
  22.             this.getClass().getClassLoader());  
  23.       
  24.     //利用反射调用插件包内的类的方法  
  25.       
  26.     try {  
  27.         Class<?> clazz = calssLoader.loadClass(pacageName+".Plugin1");  
  28.           
  29.         Object obj = clazz.newInstance();  
  30.         Class[] param = new Class[2];  
  31.         param[0] = Integer.TYPE;  
  32.         param[1] = Integer.TYPE;  
  33.           
  34.         Method method = clazz.getMethod("function1", param);  
  35.           
  36.         Integer ret = (Integer)method.invoke(obj, 1,12);  
  37.           
  38.         Log.i("Host", "return result is " + ret);  
  39.           
  40.     } catch (ClassNotFoundException e) {  
  41.         e.printStackTrace();  
  42.     } catch (InstantiationException e) {  
  43.         e.printStackTrace();  
  44.     } catch (IllegalAccessException e) {  
  45.         e.printStackTrace();  
  46.     } catch (NoSuchMethodException e) {  
  47.         e.printStackTrace();  
  48.     } catch (IllegalArgumentException e) {  
  49.         e.printStackTrace();  
  50.     } catch (InvocationTargetException e) {  
  51.         e.printStackTrace();  
  52.     }  
  53.    }  

Plugin1.apk中的一个类:

[html] view
plain
copy

  1. package com.suchangli.plugin1;  
  2.   
  3. public class Plugin1 {  
  4.     public int function1(int a, int b){  
  5.           
  6.         return a+b;  
  7.     }  
  8. }  

Log输出的结果:

注意要在Plugin1中的清单文件的一个activity中添加一个如下的action,这个action必须是宿主和插件约定好的。

源代码:

通过以上代码就可以访问另一个apk中的代码了,一个比较麻烦的地方就是必须用反射才能调用方法,

有没不用反射也可以调用方法方式呢?当然有,通过接口。

时间: 2024-10-31 18:09:58

Android中的类装载器DexClassLoader的相关文章

Android开发中类加载器DexClassLoader的简单使用讲解_Android

简介"类装载器"(ClassLoader),顾名思义,就是用来动态装载class文件的.标准的Java SDK中有个ClassLoader类,借助此类可以装载需要的class文件,前提是ClassLoader类初始化必须制定class文件的路径. import关键字引用的类文件和ClassLoader动态加载类的区别: import引用类的两个特点: 1.必须存在于本地,当程序运行该类时,内部类装载器会自动装载该类. 2.编译时必须在现场,否则编译过程会因找不到引用文件而不能正常编译.

Android中利用动态加载实现手机淘宝的节日特效_Android

相信去年圣诞节打开过手机淘宝的童鞋都会对当时的特效记忆犹新吧:全屏飘雪,旁边还有个小雪人来控制八音盒背景音乐的播放,让人有种身临其境的感觉,甚至忍不住想狠狠购物了呢(误),大概就是下面这个样子滴: 嗯,确实很炫,那么我们一步步去分析是如何实现的: 一.实现下雪的 View 首先,最上面一层的全屏雪花极有可能是一个顶层的View,而这个View是通过动态加载去控制显示的(不更新淘宝也能看到这个效果).那么我们先得实现雪花效果的 View,人生苦短,拿来就用.打开 gank.io,搜索"雪花&quo

Android中的动态加载机制的学习研究_Android

在目前的软硬件环境下,Native App与Web App在用户体验上有着明显的优势,但在实际项目中有些会因为业务的频繁变更而频繁的升级客户端,造成较差的用户体验,而这也恰恰是Web App的优势.本文对网上Android动态加载jar的资料进行梳理和实践在这里与大家一起分享,试图改善频繁升级这一弊病. Android应用开发在一般情况下,常规的开发方式和代码架构就能满足我们的普通需求.但是有些特殊问题,常常引发我们进一步的沉思.我们从沉思中产生顿悟,从而产生新的技术形式. 如何开发一个可以自定

详解Android中实现热更新的原理_Android

这篇文章就来介绍一下Android中实现热更新的原理. 一.ClassLoader 我们知道Java在运行时加载对应的类是通过ClassLoader来实现的,ClassLoader本身是一个抽象来,Android中使用PathClassLoader类作为Android的默认的类加载器,PathClassLoader其实实现的就是简单的从文件系统中加载类文件.PathClassLoade本身继承自BaseDexClassLoader,BaseDexClassLoader重写了findClass方法

Android中利用动态加载实现手机淘宝的节日特效

相信去年圣诞节打开过手机淘宝的童鞋都会对当时的特效记忆犹新吧:全屏飘雪,旁边还有个小雪人来控制八音盒背景音乐的播放,让人有种身临其境的感觉,甚至忍不住想狠狠购物了呢(误),大概就是下面这个样子滴: 嗯,确实很炫,那么我们一步步去分析是如何实现的: 一.实现下雪的 View 首先,最上面一层的全屏雪花极有可能是一个顶层的View,而这个View是通过动态加载去控制显示的(不更新淘宝也能看到这个效果).那么我们先得实现雪花效果的 View,人生苦短,拿来就用.打开 gank.io,搜索"雪花&quo

详解Android中实现热更新的原理

这篇文章就来介绍一下Android中实现热更新的原理. 一.ClassLoader 我们知道Java在运行时加载对应的类是通过ClassLoader来实现的,ClassLoader本身是一个抽象来,Android中使用PathClassLoader类作为Android的默认的类加载器,PathClassLoader其实实现的就是简单的从文件系统中加载类文件.PathClassLoade本身继承自BaseDexClassLoader,BaseDexClassLoader重写了findClass方法

Android中的动态加载机制的学习研究

在目前的软硬件环境下,Native App与Web App在用户体验上有着明显的优势,但在实际项目中有些会因为业务的频繁变更而频繁的升级客户端,造成较差的用户体验,而这也恰恰是Web App的优势.本文对网上Android动态加载jar的资料进行梳理和实践在这里与大家一起分享,试图改善频繁升级这一弊病. Android应用开发在一般情况下,常规的开发方式和代码架构就能满足我们的普通需求.但是有些特殊问题,常常引发我们进一步的沉思.我们从沉思中产生顿悟,从而产生新的技术形式. 如何开发一个可以自定

异常处理:android中添加按钮事件,出现NullPointerException

问题描述 异常处理:android中添加按钮事件,出现NullPointerException 解决方案 在maincsactivity的oncreate的72行找,有没有对象为null 解决方案二: 对象为空,要么你的按钮对象还没初始化,要么点击代码里有空对象,你调试一下便知 解决方案三: 空指针异常,没什么难找的,Debug一下即可很快找到: 解决方案四: 空指针异常,按钮对象没有初始化 解决方案五: 可能你声明了一个View,但是你没有findViewById,或者findViewById

android-关于webp图片格式在Android中的应用

问题描述 关于webp图片格式在Android中的应用 我现在在做一个类似壁纸的应用,app获取服务端图片展示,有一半图片是webp格式.我们提供下载和分享功能.但是webp图片下载到手机本地不能打开,同时分享webp图片都会出错.求助,该怎么解决.是要把服务端的图片格式都转换为jpg或者png吗?有代码能实现转换吗 解决方案 Android优化-webp图片格式 解决方案二: 你的参考答案在哪啊? 解决方案三: app端的图片格式一般都是**Jpg**和**png**的. 没有用webp的.