Android动态加载字节码
概述
面对App业务逻辑的频繁变更,如果每一次改变都对App进行一次升级,会降低App的用户体验,那么App进行模块化升级(这里与增量升级是不同的)是很好的解决方案,让用户在完全无感觉的情况下改变App中的业务逻辑。要实现这种模块化升级,动态加载字节码(jar/dex)就是实现这个需求的理论基础。
Android系统加载字节码
Android的虚拟机(Dalvik VM)无法识别普通jar包中的字节码,所以需要通过字节码转换工具将jar转换成dex,jar包中的所有字节码都会打进classes.dex,这样的字节码才能被Dalvik虚拟机识别。
实例讲解
源码下载,需要准备两个工程,一个Android工程(AndroidPractice),Android工程中去加载字节码。宁外一个普通的java工程(DexModule),下面看看工程结构。需要注意的是IDynamicLoad这个接口在两个工程中都需要,且包名一致。
字节码加载工程结构
DexModule工程讲解
DexModule这个工程中只有两个类,一个是接口IDynamicLoad,这个接口就是文章开始提到的模块升级的关键,只需要提前约定好接口,将接口发布给调用方,具体的实现对调用方完全是透明的,这样就能做到随意的更改接口的实现,宁一个是该接口的实现类DynamicLoad。实现非常简单就是返回一个字符串。
package com.vjson.module;
public interface IDynamicLoad {
public String dexLoad();
}
<span style="font-weight: normal;">package com.vjson.module;
public class DynamicLoad implements IDynamicLoad {
@Override
public String dexLoad() {
return "dexload practice";
}
}</span>
导出jar包
在导出jar包的时候一定要注意,不要导出IDynamicLoad这个接口文件,因为Android工程中已经有一个接口文件,不然加载字节码的时候会导致字节码冲突。
导出jar包
字节码转换
用前面提到的字节码转换工具,将jar转换为Dalvik VM认识的dex。d2j-jar2dex.sh这个命令的-o参数指定输出文件。
d2j-jar2dex.sh -o module.jar dynamicLoad.jar
然后将生成的module.jar放到手机的sdcard里面。
adb push module.jar /mnt/sdcard/
加载dex
加载字节码需要用到DexClassLoader这个类,它负责从jar包中提取(解压缩的一个过程)classes.dex,并且将字节码加载到内存,接下来就通过loadClass方法加载需要的类,看下面的详细代码,注意高亮的行。
package com.vjson.practice; import java.io.File; import android.annotation.TargetApi;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast; import com.vjson.dynamicload.R;
import com.vjson.module.IDynamicLoad; import dalvik.system.DexClassLoader; public class MainActivity extends Activity {
private Button mBtn;
private IDynamicLoad mDynamicLoad; @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
public static final IDynamicLoad loadByteCode() {
File jarFile = new File(Environment.getExternalStorageDirectory().toString() + File.separator + "module.jar");
File optmizedPath = BaseApplication.sInstance.getDir("dex", MODE_PRIVATE);
DexClassLoader loader = new DexClassLoader(jarFile.getAbsolutePath(),
optmizedPath.getAbsolutePath(), null,
BaseApplication.sInstance.getClassLoader());
IDynamicLoad dynaicLoad = null; try {
Class<?> clazz = loader.loadClass("com.vjson.module.DynamicLoad");
dynaicLoad = (IDynamicLoad) clazz.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} return dynaicLoad;
} @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); mDynamicLoad = loadByteCode();
mBtn = (Button) findViewById(R.id.btn);
mBtn.setOnClickListener(new OnClickListener() { @Override
public void onClick(View v) {
String str = mDynamicLoad.dexLoad(); Toast.makeText(getApplicationContext(), str, Toast.LENGTH_SHORT).show();
}
});
}
}
注意代码的26行,通过context的getDir(“dex”, MODE_PRIVATE)方法获取应用程序的私有目录,这是由于从Android4.1.2开始由于安全原因,防止代码注入攻击,必须将字节码放到私有目录下面也就是data/data/应用程序包名/。从jar包中提前出来的classes.dex就放在这个目录下面。
总结
本文主要介绍了,Android中的字节码加载技术,为接下来的文章Android模块化升级提供一个理论基础,其实最精髓的地方就是定义接口,通过接口调用端和实现端进行通信。在模块化升级中将会讲解jar包的完整性验证和安全性验证。
Android动态加载字节码的更多相关文章
- Java安全之动态加载字节码
Java字节码 简单说,Java字节码就是.class后缀的文件,里面存放Java虚拟机执行的指令. 由于Java是一门跨平台的编译型语言,所以可以适用于不同平台,不同CPU的计算机,开发者只需要将自 ...
- Android 动态加载 (二) 态加载机制 案例二
探秘腾讯Android手机游戏平台之不安装游戏APK直接启动法 重要说明 在实践的过程中大家都会发现资源引用的问题,这里重点声明两点: 1. 资源文件是不能直接inflate的,如果简单的话直接在程序 ...
- [转载] Android动态加载Dex机制解析
本文转载自: http://blog.csdn.net/wy353208214/article/details/50859422 1.什么是类加载器? 类加载器(class loader)是 Java ...
- Android 动态加载 (一) 态加载机制 案例一
在目前的软硬件环境下,Native App与Web App在用户体验上有着明显的优势,但在实际项目中有些会因为业务的频繁变更而频繁的升级客户端,造成较差的用户体验,而这也恰恰是Web App的优势.本 ...
- Android动态加载技术初探
一.前言: 现在,已经有实力强大的公司用这个技术开发应用了,比如淘宝,大众点评,百度地图等,之所以采用这个技术,实际上,就是方便更新功能,当然,前提是新旧功能的接口一致,不然会报Not Found等错 ...
- Android应用开发提高系列(4)——Android动态加载(上)——加载未安装APK中的类
前言 近期做换肤功能,由于换肤程度较高,受限于平台本身,实现起来较复杂,暂时搁置了该功能,但也积累了一些经验,将分两篇文章来写这部分的内容,欢迎交流! 关键字:Android动态加载 声明 欢迎转载, ...
- Android动态加载jar/dex
前言 在目前的软硬件环境下,Native App与Web App在用户体验上有着明显的优势,但在实际项目中有些会因为业务的频繁变更而频繁的升级客户端,造成较差的用户体验,而这也恰恰是Web App的优 ...
- Android动态加载代码技术
Android动态加载代码技术 在开发Android App的过程当中,可能希望实现插件式软件架构,将一部分代码以另外一个APK的形式单独发布,而在主程序中加载并执行这个APK中的代码. 实现这个任务 ...
- 【Android】Android动态加载Jar、APK的实现
本文介绍Android中动态加载Jar.APK的实现.而主要用到的就是DexClassLoader这个类.大家都知道Android和普通的Java虚拟机有差别,它只能加载经过处理的dex文件.而加载这 ...
随机推荐
- Hadoop集群(第12期)_HBase简介及安装
HBase简介 HBase是Apache Hadoop的数据库,能够对大型数据提供随机.实时的读写访问,是Google的BigTable的开源实现.HBase的目标是存储并处理大型的数据,更具体地说仅 ...
- Grand Central Dispatch(GCD)详解
概述 GCD是苹果异步执行任务技术,将应用程序中的线程管理的代码在系统级中实现.开发者只需要定义想要执行的任务并追加到适当的Dispatch Queue中,GCD就能生成必要的线程并计划执行任务.由于 ...
- [Angular] Getting to Know the @Attribute Decorator in Angular
So when you using input binding in Angular, it will always check for update. If you want to improve ...
- insmod: error inserting 'hello.ko': -1 Invalid module format
在学习编写linux驱动程序的时候,一般都是从写一个helloworld的模块開始. 可是在编译完毕后,进行模块载入的时候,有时会出现例如以下错误: insmod: error inserting ' ...
- PHP生成二维码的2种方式
二维码的用处俺也就不说了,看一下用PHP生成的二维码吧. 利用谷歌提供的API 生成二维码,如今非常多国外站点都提供了这类API 看下代码吧<=======================> ...
- ASP.NET六大巨头——内置对象(1)
ASP.NET提供了六个内置对象:Request.Response.Application.Session.Server和Cookie.这些对象收集当前应用程序请求.用户信息.响应浏览器信息,来完毕页 ...
- JNI DETECTED ERROR IN APPLICATION: input is not valid Modified UTF-8: illegal start byte 0xfe
JNI DETECTED ERROR IN APPLICATION: input is not valid Modified UTF-8: illegal start byte 0xfe 在使用Jni ...
- zzulioj--1637--Happy Thanksgiving Day - WoW yjj!(水)
1637: Happy Thanksgiving Day - WoW yjj! Time Limit: 1 Sec Memory Limit: 128 MB Submit: 104 Solved: ...
- Python 下的 return 关键字
def make_sum(a, b): return ('+', a, b) >> make_sum(1, 2) ('+', 1, 2) 显示地返回一个元组(tuple),当然 retur ...
- 42.写入XML
#include <QtGui> #include <QtXml> #include <iostream> //创建一个树结构 void populateTree( ...