关于DexClassLoader

安卓的动态加载必备知识之一,DexClassLoader。
DexClassLoader当然也是一种ClassLoader,但本身属于顾名思义是用来加载Dex文件的,是安卓系统独有的一种类加载器。

基础概念

在此之前可以稍微回顾下ClassLoader的相关基础:

  • ClassLoader是用来加载class文件的,它负责将*.class加载为内在中的Class对象
  • 加载机制为“双亲委派”,即能交给父类加载器去加载的,绝不自行加载

再来看DexClassLoader:
dexclassloader
官方说明了DexClassLoader的定义:

  • 用于加载包含*.dex文件的jar包或apk文件
  • 要求一个应用私有可写的目录去缓存编译的class文件
  • 不允许加载外部存储空间的文件,以防注入攻击

那么很明显,我们普通项目中的jar包是不能直接用来加载的了。
在Java项目中,一般加载jar包会使用URLClassLoader,但安卓davlik不能使用,安卓只能使用继承自BaseDexClassLoader的两种ClassLoader—一种是PathClassLoader,用于加载系统中已经安装的apk;一种就是DexClassLoader,加载未安装的jar包或apk。

所以如果在安卓系统上想要动态加载jar包,DexClassLoader可能是唯一的选择。
DexClassLoader源码

使用方法

使用很简单,只需要清楚其构造方法的参数意义就可以。

DexClassLoader (String dexPath, 
                String optimizedDirectory, 
                String librarySearchPath, 
                ClassLoader parent)
参数含义
dexPath包含dex文件的jar包或apk文件路径
optimizedDirectory释放目录,可以理解为缓存目录,必须为应用私有目录,不能为空
librarySearchPathnative库的路径,可为空
parent父类加载器

那么使用起来就是这样:

	private void loadJar1(){
        String file = Environment.getExternalStorageDirectory() + "/jinxingateway/jar/codec.jar";
        String path = getDir("jar", MODE_PRIVATE).getAbsolutePath() + File.separator + "codec.jar";
		try {
			//复制到私有目录
            FileOperator.copy(file, path);

            DexClassLoader dcl = new DexClassLoader(path, getDir("jar", MODE_PRIVATE).getAbsolutePath(), null, getClassLoader());

            Class<?> factoryCls = dcl.loadClass("com.jinxin.codec.ProtocolCodecFactory");
            Class<?> extensionCls = dcl.loadClass("com.jinxin.codec.ICodecExtension");

			//省略其下利用反射的代码
		} catch (IOException e) {
            e.printStackTrace();
		} catch (ClassNotFoundException e) {
            e.printStackTrace();
		} catch (NoSuchMethodException e) {
            e.printStackTrace();
		} catch (InstantiationException e) {
            e.printStackTrace();
		} catch (IllegalAccessException e) {
            e.printStackTrace();
		} catch (InvocationTargetException e) {
            e.printStackTrace();
		}
	}

因为读写权限的敏感,所以jar包一般也会复制到应用私有路径中再行加载,加载后使用loadClass方法即可得到类,然后利用反射就可以得到类中的各种信息了。

这里的加载是不能使用Class.forName的,因为这样使用最终调用的就是java的ClassLoader而不是DexClassLoader了:

    public static Class<?> forName(String className)
                throws ClassNotFoundException {
        return forName(className, true, VMStack.getCallingClassLoader());
    }

扩展

DexClassLoader只能加载dex,那普通的jar包怎么办?
当然是转成dex了。
使用安卓sdk/build-tools目录下的dx工具,即可把普通的jar包转换为包含dex的jar包。在能运行dx.bat的情况下使用命令:

dx  --dex --output [输出文件] [输入文件]
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值