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文件.而加载这 ...
随机推荐
- SqlCommand.DeriveParameters failed
错误信息例如以下: SqlCommand.DeriveParameters failed because the SqlCommand.CommandText property value is an ...
- spark transform系列__sortByKey
该函数主要功能:通过指定的排序规则与进行排序操作的分区个数,对当前的RDD中的数据集按KEY进行排序,并生成一个SHUFFLEdrdd的实例,这个过程会运行shuffle操作,在运行排序操作前,sor ...
- angularjs1-3,$apply,$watch
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...
- php5.5安装笔记
这次没想到本来很简单的php编译,没想到遇到那么多问题.再此记录一下. 1.php5.5编译安装主要有一个难点,就是GD库的问题,因为php5.5的GD库必须是2.1以上的版本哦 原来都是用的gd2. ...
- Beta冲刺提交—星期五
课程链接: https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass2 作业要求链接: https://edu.cnblogs.com/ ...
- ROS-Gazebo-turtlebot3仿真
前言:Gazebo是一款强大的3D仿真器,支持机器人开发所需的机器人.传感器和环境模型,并且通过搭载的物理引擎可以得到逼真的仿真结果.即便Gazebo是一款开源仿真器,却具有高水准的仿真性能,因此在机 ...
- Git不需重复输入账号和密码的方法
1. 打开 TortoiseGit 附带工具 Puttygen(PuTTY Key Generator) C:\Program Files\TortoiseGit\bin\puttygen.exe. ...
- redis的windows版本下载地址及windows的客户端工具
源码:https://github.com/MSOpenTech/redis 安装包:https://github.com/MSOpenTech/redis/releases 客户端工具:https: ...
- SignalR——聊天室的实现
秒懂——SignalR ASP.NET SignalR 是为 ASP.NET 开发人员提供的一个库,可以简化开发人员将实时 Web 功能添加到应用程序的过程.实时 Web 功能是指这样一种功能:当所连 ...
- mysql安装出现 conflicts with mysql*的解决办法
rpm -ivh Percona-Server-client-56-5.6.16-rel64.0.el6.x86_64.rpm --nodeps --force error: Failed depen ...