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包的完整性验证和安全性验证。

时间: 2024-11-12 21:02:42

Android动态加载字节码的相关文章

Android动态加载Dex机制解析

1.什么是类加载器? 类加载器(class loader)是 Java?中的一个很重要的概念.类加载器负责加载 Java 类的字节代码到 Java 虚拟机中. Java 虚拟机使用 Java 类的方式如下:Java 源程序(.java 文件)在经过 Java 编译器编译之后就被转换成 Java 字节代码(.class 文件).类加载器负责读取 Java 字节代码,并转换成java.lang.Class类的一个实例.每个这样的实例用来表示一个 Java 类.通过此实例的 newInstance()

Android动态加载那些事儿

基础 1.Java 类加载器 类加载器(class loader)是 Java?中的一个很重要的概念.类加载器负责加载 Java 类的字节代码到 Java 虚拟机中.本文首先详细介绍了 Java 类加载器的基本概念,包括代理模式.加载类的具体过程和线程上下文类加载器等,接着介绍如何开发自己的类加载器,最后介绍了类加载器在 Web 容器和 OSGi?中的应用. 2.反射原理 Java 提供的反射機制允許您於執行時期動態載入類別.檢視類別資訊.生成物件或操作生成的物件,要舉反射機制的一個應用實例,就

Android动态加载框架DL的架构与基本原理解析

转载请注明出处,本文来自[ Mr.Simple的博客 ]. 我正在参加博客之星,点击这里投我一票吧,谢谢~ 前言 最近这一两年,Android App使用插件化技术开发的数量越来越大,其实还是业务地快速膨胀导致,需求越来越多,App越来越臃肿.虽然手机的内存空间不断地的增大,但是太大的安装包给用户也造成了心理压力.于是大家都会想到插件化的开发方式,把App做成一个平台,而不是一个独立的app.平台上可以集成各种各样的功能,功能模块也插件的形式添加进来,这些插件不需要安装,只需要用户按需下载到某个

android动态加载(二)

上一篇说了android中的动态加载,即在android工程中动态加载经过dx操作以后的jar文件和没有安装的apk文件,今天我们来看看怎么执行已经安装的apk中的类中的方法. 所以,我们会需要两个工程,一个是plugone,这个是我们暴露给外面的方法的一个android工程.另外一个我们暂且给他起名为useplugone吧. 先来看看plugone工程,我们在plugone工程中有这样一个类,用来暴露给调用者一个方法: package com.example.plugone; public c

实现Android 动态加载APK(Fragment or Activity实现)

尊重原创:http://blog.csdn.net/yuanzeyao/article/details/38565345 最近由于项目太大了,导致编译通不过(Android对一个应用中的方法个数貌似有限制),所以一直琢磨着能否将某些模块的APK不用安装,动态加载,通过在网上查找资料和网友的帮助,终于实现了APK的动态加载,网络上介绍APK动态加载的文章非常多,但是我觉得写得非常好的就是这位大牛的,我基本上就是使用他的这种方案,然后加入了自己的元素.这位大牛是通过Activity实现的,我稍作修改

Android动态加载jar/dex

http://www.cnblogs.com/over140/archive/2011/11/23/2259367.html 前言 在目前的软硬件环境下,Native App与Web App在用户体验上有着明显的优势,但在实际项目中有些会因为业务的频繁变更而频繁的升级客户端,造成较差的用户体验,而这也恰恰是Web App的优势.本文对网上Android动态加载jar的资料进行梳理和实践在这里与大家一起分享,试图改善频繁升级这一弊病. 声明 欢迎转载,但请保留文章原始出处:) 博客园:http:/

Android动态加载技术三个关键问题详解

编者按:InfoQ开设新栏目“品味书香”,精选技术书籍的精彩章节,以及分享看完书留下的思考和收获,欢迎大家关注.本文节选自任玉刚著<Android开发艺术探索>中的章节“Android的动态加载技术”,探讨了Android动态加载的三个关键问题. 动态加载技术(也叫插件化技术)在技术驱动型的公司中扮演着相当重要的角色,当项目越来越庞大的时候,需要通过插件化来减轻应用的内存和CPU占用,还可以实现热插拔,即在不发布新版本的情况下更新某些模块.动态加载是一项很复杂的技术,这里主要介绍动态加载技术中

Android动态加载代码技术

Android动态加载代码技术 在开发Android App的过程当中,可能希望实现插件式软件架构,将一部分代码以另外一个APK的形式单独发布,而在主程序中加载并执行这个APK中的代码. 实现这个任务的一般方法是: // 加载类cls Context pluginContext = mainContext.createPackageContext(PLUGIN_PKG, Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE)

Android动态加载ListView中的Item

我这周上网看到动态增加listview的每一项item的布局,今天抽空自己写了一个,方便自己日后使用,这个效果还是很不错的,用到了Adapter的notifyDataSetChanged()方法,当点击每一个Item的时候,就通知adapter更新getView,系统得到通知就相应的加载一遍布局,就达到了动态加载item布局的效果.希望给大家带来点启迪,有问题或想要代码的可以留言,欢迎大家留言谈论listview的一些知识,以求共同进步,转载请标明出处: http://blog.csdn.net