概述

面对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. android Service中多线程交互

    android 的service和activity是执行在UI主线程的. 在android线程中,仅仅有主线程即UI线程有自己的默认的消息队列.子线程须要创建自己的消息队列.并把消息发给队列,并循环起 ...

  2. CodeForces 7D Palindrome Degree 字符串hash

    题目链接:点击打开链接 #include<stdio.h> #include<iostream> #include<string.h> #include<se ...

  3. nginx报 File not found 错误

    原因可能非常多,但对于刚開始学习的人.大部分应该是/etc/nginx/conf.d/default.conf里面的php解析部分配置不正确. 解决的话就是把root定义.在server下加上,这样r ...

  4. 0x15 KMP

    这个算法本身就不难. poj1961 #include<cstdio> #include<iostream> #include<cstring> #include& ...

  5. 谷歌开源可视化工具Facets,将用于人+AI协作项目研究——无非就是一个用于特征工程探索的绘图工具集,pandas可以做的

    见:http://www.infoq.com/cn/news/2017/07/goole-sight-facets-ai https://github.com/PAIR-code/facets/blo ...

  6. 转:Java修改Excel单元格的数据及格式

    https://blog.csdn.net/aking21alinjuju/article/details/6001153?locationNum=2 继前两节的Java读取.写入Excel后,本期将 ...

  7. Oracle 位图索引

    内容简介: 1.位图索引 1.1位图索引使用注意事项; 1.2 使用位图索引; 1.3 位图索引对DML操作的影响; 2.位图连接索引 2.1 明确需求后使用位图索引; 2.1创建位图连接索引的注意事 ...

  8. js 智能识别收获地址

    项目地址https://github.com/wzc570738205/smart_parse 支持以下数据格式 马云,1351111111,北京市朝阳区姚家园3楼 马云1351111111北京市朝阳 ...

  9. js最简单的-点击小图放大

    js最简单的-点击小图放大 标签(空格分隔): js <html> <body> <img class="imgview" src="{$v ...

  10. 使用log4net记录日志到数据库(含自定义属性)

    日志输出自定义属性! 特来总结一下: 一.配置文件 使用log4写入数据库就不多说了,网上方法很多,自定义字段如下 <commandText value="INSERT INTO db ...