概述

面对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动态加载字节码的更多相关文章

  1. Java安全之动态加载字节码

    Java字节码 简单说,Java字节码就是.class后缀的文件,里面存放Java虚拟机执行的指令. 由于Java是一门跨平台的编译型语言,所以可以适用于不同平台,不同CPU的计算机,开发者只需要将自 ...

  2. Android 动态加载 (二) 态加载机制 案例二

    探秘腾讯Android手机游戏平台之不安装游戏APK直接启动法 重要说明 在实践的过程中大家都会发现资源引用的问题,这里重点声明两点: 1. 资源文件是不能直接inflate的,如果简单的话直接在程序 ...

  3. [转载] Android动态加载Dex机制解析

    本文转载自: http://blog.csdn.net/wy353208214/article/details/50859422 1.什么是类加载器? 类加载器(class loader)是 Java ...

  4. Android 动态加载 (一) 态加载机制 案例一

    在目前的软硬件环境下,Native App与Web App在用户体验上有着明显的优势,但在实际项目中有些会因为业务的频繁变更而频繁的升级客户端,造成较差的用户体验,而这也恰恰是Web App的优势.本 ...

  5. Android动态加载技术初探

    一.前言: 现在,已经有实力强大的公司用这个技术开发应用了,比如淘宝,大众点评,百度地图等,之所以采用这个技术,实际上,就是方便更新功能,当然,前提是新旧功能的接口一致,不然会报Not Found等错 ...

  6. Android应用开发提高系列(4)——Android动态加载(上)——加载未安装APK中的类

    前言 近期做换肤功能,由于换肤程度较高,受限于平台本身,实现起来较复杂,暂时搁置了该功能,但也积累了一些经验,将分两篇文章来写这部分的内容,欢迎交流! 关键字:Android动态加载 声明 欢迎转载, ...

  7. Android动态加载jar/dex

    前言 在目前的软硬件环境下,Native App与Web App在用户体验上有着明显的优势,但在实际项目中有些会因为业务的频繁变更而频繁的升级客户端,造成较差的用户体验,而这也恰恰是Web App的优 ...

  8. Android动态加载代码技术

    Android动态加载代码技术 在开发Android App的过程当中,可能希望实现插件式软件架构,将一部分代码以另外一个APK的形式单独发布,而在主程序中加载并执行这个APK中的代码. 实现这个任务 ...

  9. 【Android】Android动态加载Jar、APK的实现

    本文介绍Android中动态加载Jar.APK的实现.而主要用到的就是DexClassLoader这个类.大家都知道Android和普通的Java虚拟机有差别,它只能加载经过处理的dex文件.而加载这 ...

随机推荐

  1. rabbitMQ学习笔记(六) topic类型消息。

    上一节中使用了消息路由,消费者可以选择性的接收消息. 但是这样还是不够灵活. 比如某个消费者要订阅娱乐新闻消息 . 包括新浪.网易.腾讯的娱乐新闻.那么消费者就需要绑定三次,分别绑定这三个网站的消息类 ...

  2. eclips 手机 offline

    [退出eclipse] [进入eclipse的工作区间] [删除 .metadata文件夹,确保 .metadata文件夹得隐藏文件也要删除] [重启eclipse,并重新导入你的工程]

  3. Oracle 常见的33个等待事件

    一. 等待事件的相关知识: 1.1 等待事件主要可以分为两类,即空闲(IDLE)等待事件和非空闲(NON-IDLE)等待事件. 1). 空闲等待事件指Oracle正等待某种工作,在诊断和优化数据库的时 ...

  4. HTML5-1、标签

    本文只是自己学习HTML5时的一些笔记.希望自己能够学好HTML5. 如果有感兴趣的同学.可以互相学习. 我觉得HTML5在未来的开发中站主导地位. 下面开始学习HTML5. 还是从HTML5标签开始 ...

  5. 9-21 调试javaweb 数据库连接感想

    如何找bug 一步步调试 数据库链接写一个简单的 test 数据库操作 sql语句 写一个类 测试一下 不要忽略细节 最后页面的显示 html "/head"少一个"/& ...

  6. [转]C#事件-使用事件需要的步骤

    事件是C#中另一高级概念,使用方法和委托相关.奥运会参加百米的田径运动员听到枪声,比赛立即进行.其中枪声是事件,而运动员比赛就是这个事件发生后的动作.不参加该项比赛的人对枪声没有反应. 从程序员的角度 ...

  7. 高并发之后端优化(PHP)

    页面静态化 使用模板引擎 可以使用Smarty的缓存机制生成静态HTML缓存文件 $smarty->cachedir=$ROOT·"/cache"://缓存目录 $smart ...

  8. Unity3D项目

    Input.mousePosition //鼠标点击的位置 0 左键  1右键  2滚轮 Input.GetMouseButton(0) //当鼠标左键处于按下状态的时候返回True Input.Ge ...

  9. Microsoft Edge 首个 Chromium 内核版释出

    翻译功能释出 navigator.userAgent"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, ...

  10. CDR查找替换对象操作详解

    您可以使用CorelDRAW软件中提供的查找和替换向导,在绘图中定位和编辑对象.这在设计绘图中经常用到,查找和替换中为用户提供多种搜索方法,其中包括包含对象类型及其相关属性.填充和轮廓属性.应用于对象 ...