Android动态加载jar,dex,apk文件
来源:互联网 发布:单片机施密特触发输入 编辑:程序博客网 时间:2024/05/16 02:09
最近发现Android有一个发展方向,插件化,像360等等,他把功能索引放在主界面,当使用哪个功能就调用哪个jar,dex,或者apk,这种技术叫做动态加载,那么我们来看看这个dex实现了什么功能
插件化的原理实际是 Java ClassLoader 的原理,
Android 也有自己的 ClassLoader,分为 dalvik.system.DexClassLoader 和 dalvik.system.PathClassLoader,区别在于 PathClassLoader 不能直接从 zip 包中得到 dex,因此只支持直接操作 dex 文件或者已经安装过的 apk(因为安装过的 apk 在 cache 中存在缓存的 dex 文件)。而 DexClassLoader 可以加载外部的 apk、jar 或 dex文件,并且会在指定的 outpath 路径存放其 dex 文件。
那么我们来看代码,怎么动态加载一个dex
使用到的工具都比较常规:javac、dx、eclipse等其中dx工具最好是指明–no-strict,因为class文件的路径可能不匹配
加载好类后,通常我们可以通过Java反射机制来使用这个类但是这样效率相对不高,而且老用反射代码也比较复杂凌乱。更好的做法是定义一个interface,并将这个interface写进容器端。待加载的类,继承自这个interface,并且有一个参数为空的构造函数,以使我们能够通过Class的newInstance方法产生对象然后将对象强制转换为interface对象,于是就可以直接调用成员方法了,下面是具体的实现步骤了:
首先建一个项目 新建一个interface
IDynamicsLoader.java
package com.example.interf;public interface IDynamicsLoader { public String Helloworld();}
然后建一个实现类
DynamicsLoader .java
package com.example.interf;public class DynamicsLoader implements IDynamicsLoader { public DynamicsLoader() { } @Override public String Helloworld() { return "hellowrold"; }}
然后右键 导出-jar文件
民称为loader.jar
然后进入C:\android\adt-bundle-windows-x86_64-20131030\sdk\build-tools\android-4.4
把你导入的文件复制到这个路径下
执行
dx --dex --output=loader_dex.dex loader.jar
得到的文件
复制出来放在
然后导出IDynamicsLoader
注意只导出这个类
记得把其他的去掉
导出来的jar打开是这样子的
然后添加进需要动态加载这个dex的项目
因为我们要从外存中读
所以声明权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
然后调用
package com.example.ttest;import java.io.File;import com.example.interf.ILoader;import android.annotation.SuppressLint;import android.app.Activity;import android.content.Context;import android.content.ContextWrapper;import android.os.Bundle;import android.os.Environment;import android.widget.Toast;import dalvik.system.BaseDexClassLoader;import dalvik.system.DexClassLoader;@SuppressLint("NewApi")public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); test(); } private void loadJar() { final File optimizedDexOutputPath = new File(Environment .getExternalStorageDirectory().toString() + File.separator + "loader_dex.jar"); System.out.println(optimizedDexOutputPath.toString()); BaseDexClassLoader cl = new BaseDexClassLoader(Environment .getExternalStorageDirectory().toString(), optimizedDexOutputPath, optimizedDexOutputPath.getAbsolutePath(), getClassLoader()); Class libProviderClazz = null; try { // 载入JarLoader类, 并且通过反射构建JarLoader对象, 然后调用sayHi方法 libProviderClazz = cl.loadClass("com.example.interf.DynamicsLoader"); IDynamicsLoaderloader = (IDynamicsLoader) libProviderClazz.newInstance(); Toast.makeText(MainActivity.this, loader.sayHi(), Toast.LENGTH_SHORT).show(); } catch (Exception exception) { // Handle exception gracefully here. exception.printStackTrace(); } } public void test() { final File optimizedDexOutputPath = new File(Environment .getExternalStorageDirectory().toString() + File.separator + "loader_dex.dex"); Context context = getApplicationContext(); File dexOutputDir = context.getDir("dex", 0); DexClassLoader cl = new DexClassLoader( optimizedDexOutputPath.getAbsolutePath(), dexOutputDir.getAbsolutePath(), null, getClassLoader()); //DexClassLoader cl = new DexClassLoader( // optimizedDexOutputPath.getAbsolutePath(), Environment // .getExternalStorageDirectory().toString(), null, //getClassLoader()); Class libProviderClazz = null; try { libProviderClazz = cl.loadClass("com.example.interf.JarLoader"); ILoader lib = (ILoader) libProviderClazz.newInstance(); Toast.makeText(MainActivity.this, lib.sayHi(), Toast.LENGTH_SHORT) .show(); } catch (ClassNotFoundException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (InstantiationException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } catch (IllegalAccessException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } }}
这样就完成了最简单的dex加载
注意几点
在android4.0以后
DexClassLoader localDexClassLoader = new DexClassLoader(dexpath, dexoutputpath, null, localClassLoader);
这句话会报
java.lang.IllegalArgumentException: Optimized data directory /storage/sdcard0 is not owned by the current user. Shared storage cannot protect your application from code injection attacks.
所以我上面改为
Context context = getApplicationContext(); File dexOutputDir = context.getDir("dex", 0); DexClassLoader cl = new DexClassLoader( optimizedDexOutputPath.getAbsolutePath(), dexOutputDir.getAbsolutePath(), null, getClassLoader());
还有会报
E/AndroidRuntime(9871): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.ttest/com.example.ttest.MainActivity}: java.lang.ClassCastException: com.example.interf.JarLoader cannot be cast to com.example.ttest.ILoader
这是因为你在上面导出包含IDynamicsLoader导出了多余的东西,就是我上面提到的那几个勾的事,记得不要直接把interface放在同目录下,用jar包引进来,由于classloader的特性,直接拿过来也是会报错的,大概好像就这么多
如果有哪里不懂得或者我说错的欢迎留言指正 我每天都会来看
- Android动态加载jar,dex,apk文件
- android 动态加载jar/dex/apk
- Android动态加载jar/dex/apk
- android 动态加载jar/dex文件
- DexClassLoader动态加载apk、jar、dex
- Android动态加载jar/dex
- Android动态加载jar/dex
- Android动态加载jar/dex
- Android动态加载jar/dex
- Android动态加载jar/dex
- Android动态加载jar/dex
- Android动态加载jar/dex
- Android动态加载jar/dex
- Android动态加载jar/dex
- Android动态加载jar/dex
- Android动态加载jar/dex
- Android动态加载jar/dex
- Android动态加载jar/dex
- 推荐算法:基于约束的推荐
- 坑
- hdu 2717 Catch That Cow (BFS)
- 8086汇编语言 在显示器上显示一个大写的字母A
- 经典SVM之SMO算法实现
- Android动态加载jar,dex,apk文件
- poj 1258 Agri-Net 基本&经典最小生成树
- leetcode 13 Roman to Integer(罗马数字转换为整数)
- java poi操作word浅谈
- 关于CUDA实现最值问题
- iOS之 深入探究copy与mutableCopy
- Windows Git+TortoiseGit简易使用教程
- NYOJ 106 背包问题(经典贪心)
- 四则运算、数字与等式(数字游戏)