前言

   在目前的软硬件环境下,Native App与Web App在用户体验上有着明显的优势,但在实际项目中有些会因为业务的频繁变更而频繁的升级客户端,造成较差的用户体验,而这也恰恰是Web App的优势。本文对网上Android动态加载jar的资料进行梳理和实践在这里与大家一起分享,试图改善频繁升级这一弊病。

声明

  欢迎转载,但请保留文章原始出处:)

    博客园:http://www.cnblogs.com

    农民伯伯: http://over140.cnblogs.com

    Android中文翻译组:http://androidbox.sinaapp.com/

正文

  一、 基本概念和注意点

    1.1  首先需要了解一点:在Android中可以动态加载,但无法像Java中那样方便动态加载jar

      原因:Android的虚拟机(Dalvik VM)是不认识Java打出jar的byte code,需要通过dx工具来优化转换成Dalvik byte code才行。这一点在咱们Android项目打包的apk中可以看出:引入其他Jar的内容都被打包进了classes.dex。

      所以这条路不通,请大家注意。

    1.2  当前哪些API可用于动态加载

      1.2.1  DexClassLoader

        这个可以加载jar/apk/dex,也可以从SD卡中加载,也是本文的重点。

      1.2.3  PathClassLoader  

        只能加载已经安装到Android系统中的apk文件。

  二、 准备

    本文主要参考"四、参考文章"中第一篇文章,补充细节和实践过程。

    2.1  下载开源项目

      http://code.google.com/p/goodev-demo

      将项目导入工程,工程报错的话应该是少了gen文件夹,手动添加即可。注意这个例子是从网上下载优化好的jar(已经优化成dex然后再打包成的jar)到本地文件系统,然后再从本地文件系统加载并调用的。本文则直接改成从SD卡加载。

  三、实践

    3.1  编写接口和实现

      3.1.1  接口IDynamic

package com.dynamic;

public interface IDynamic {
    public String helloWorld();
}

      3.1.2  实现类DynamicTest


package com.dynamic;

public class DynamicTest implements IDynamic {

    @Override
    public String helloWorld() {
        return "Hello World!";
    }
}

    3.2  打包并转成dex

      3.2.1  选中工程,常规流程导出即可,如图:

      注意:在实践中发现,自己新建一个Java工程然后导出jar是无法使用的,这一点大家可以根据文章一来了解相关原因,也是本文的重点之一。这里打包导出为dynamic.jar

      (后期修复:打包请不要把接口文件打进来,参见文章末尾后续维护!)

      3.2.2  将打包好的jar拷贝到SDK安装目录android-sdk-windows\platform-tools下,DOS进入这个目录,执行命名:

dx --dex --output=test.jar dynamic.jar

    3.3  修改调用例子

      修改MainActivity,如下:


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        mToastButton = (Button) findViewById(R.id.toast_button);
        
        // Before the secondary dex file can be processed by the DexClassLoader,
        // it has to be first copied from asset resource to a storage location.
//        final File dexInternalStoragePath = new File(getDir("dex", Context.MODE_PRIVATE),SECONDARY_DEX_NAME);
//        if (!dexInternalStoragePath.exists()) {
//            mProgressDialog = ProgressDialog.show(this,
//                    getResources().getString(R.string.diag_title), 
//                    getResources().getString(R.string.diag_message), true, false);
//            // Perform the file copying in an AsyncTask.
//            // 从网络下载需要的dex文件
//            (new PrepareDexTask()).execute(dexInternalStoragePath);
//        } else {
//            mToastButton.setEnabled(true);
//        }
        
        mToastButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                // Internal storage where the DexClassLoader writes the optimized dex file to.
                //final File optimizedDexOutputPath = getDir("outdex", Context.MODE_PRIVATE);
                final File optimizedDexOutputPath = new File(Environment.getExternalStorageDirectory().toString()
                    + File.separator + "test.jar");
                // Initialize the class loader with the secondary dex file.
//                DexClassLoader cl = new DexClassLoader(dexInternalStoragePath.getAbsolutePath(),
//                        optimizedDexOutputPath.getAbsolutePath(),
//                        null,
//                        getClassLoader());
                DexClassLoader cl = new DexClassLoader(optimizedDexOutputPath.getAbsolutePath(),
                    Environment.getExternalStorageDirectory().toString(), null, getClassLoader());
                Class libProviderClazz = null;
                
                try {
                    // Load the library class from the class loader.
                    // 载入从网络上下载的类
//                    libProviderClazz = cl.loadClass("com.example.dex.lib.LibraryProvider");
                    libProviderClazz = cl.loadClass("com.dynamic.DynamicTest");
                    
                    // Cast the return object to the library interface so that the
                    // caller can directly invoke methods in the interface.
                    // Alternatively, the caller can invoke methods through reflection,
                    // which is more verbose and slow.
                    //LibraryInterface lib = (LibraryInterface) libProviderClazz.newInstance();
                    IDynamic lib = (IDynamic)libProviderClazz.newInstance();
                    
                    // Display the toast!
                    //lib.showAwesomeToast(view.getContext(), "hello 世界!");
                    Toast.makeText(MainActivity.this, lib.helloWorld(), Toast.LENGTH_SHORT).show();
                } catch (Exception exception) {
                    // Handle exception gracefully here.
                    exception.printStackTrace();
                }
            }
        });
    }

    3.4  执行结果

    

  四、参考文章

    [推荐]在Android中动态载入自定义类

    Android app中加载jar插件

    关于Android的ClassLoader探索

    Android App 如何动态加载类

  五、补充

    大家可以看看DexClassLoader的API文档,里面不提倡从SD卡加载,不安全。此外,我也正在组织翻译组尽快把这个命名空间下的几个类都翻译出来,以供大家参考。

    工程下载:这里,Dex文件下载:这里。大家可以直接把Dex文件拷贝到SD卡,然后运行例子。

  六、后期维护

    6.1  2011-12-1  修复本文错误

      感谢网友ppp250和liuzhaocn的反馈,基本按照评论2来修改:

      6.1.1  不需要在本工程里面导出jar,自己新建一个Java工程然后导出来也行。

      6.1.2  导出jar时不能带接口文件,否则会报以下错:

        java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation

      6.1.3  将jar优化时应该重新成jar(jar->dex->jar),如果如下命令:

      dx --dex --output=test.jar dynamic.jar

    6.2  2012-3-29  本文升级版:

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

      请大家参照最新的文章来做动态加载!

结束 

  除了翻译组的工作和自己本职的工作以外,很难抽时间出来分享一些开发心得,但正所谓挤挤总是有的,欢迎交流!

Android动态加载jar/dex的更多相关文章

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

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

  2. Android动态加载jar、apk的实现

    前段时间到阿里巴巴参加支付宝技术分享沙龙,看到支付宝在Android使用插件化的技术,挺好奇的.正好这几天看到了农民伯伯的相关文章,因此简单整理了下,有什么错误希望大神指正. 核心类 1.1     ...

  3. 深入浅出Android动态加载jar包技术

    在实际项目中,由于某些业务频繁变更而导致频繁升级客户端的弊病会造成较差的用户体验,而这也恰是Web App的优势,于是便衍生了一种思路,将核心的易于变更的业务封装在jar包里然后通过网络下载下来,再由 ...

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

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

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

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

  6. android动态加载

    转载自: http://www.cnblogs.com/over140/archive/2012/03/29/2423116.html http://www.cnblogs.com/over140/a ...

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

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

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

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

  9. Android动态加载技术初探

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

随机推荐

  1. samba服务简介

    1.1 Samba 概述Samba主要用于Windows和Linux之间的文件共享,也一样用于Linux和Linux之间的共享文件:不过对于Linux和Linux之间共享文件有更好的网络文件系统NFS ...

  2. Synopsys逻辑工艺库

    Synopsys逻辑工艺库(DC综合) 逻辑库包括仅与综合过程有关的信息且通过DC用于设计的综合和优化. 这一信息包括引脚到引脚的时序.面积.引脚类型和功耗以及其他DC需要的必须数据. 逻辑库是一个文 ...

  3. Oracle之事务

    一,oracle的事务: 是指对数据操作的一系列动作的统称.即:事务的任务便是使数据库从一种状态变换成为另一种状态,这不同于文件系统,它是数据库所特用的. 事务有四大特性(ACID): 1,原子性(a ...

  4. Unable to find manifest signing certificate in the certificate(Visual studio)

    今天打开之前做的项目,突然得到很奇怪的编译错误: Unable to find manifest signing certificate in the certificate 网上搜一下,有两个方法, ...

  5. Altium Designer极坐标布局方法

    1.键盘快捷组合 O+G,打开栅格管理器,点击左下角的“菜单”,在对话框中的选择“添加极坐标栅格”. 2.双击新添加的优先等级为1的栅格,在弹出的polar  grid editor 对话框中,对里边 ...

  6. 表单验证提交——submit与button

    之前做东西接触过表单验证提交,但是都是为了完成工作,做完就做完了,没有注过表单验证提交有几种方法,各方法都有啥区别.今天瞎折腾了一下,对他们研究了一下,如下是我个人的理解: submit: 从字面上看 ...

  7. win32 console application 如何修改图标?

    win32 console application ,不要看这名字高端大气上档次,让你摸不着头脑,其实他就是我们最先学习c语言那种黑色窗口的东西......话说他怎么修改图标呢?第一种方法是:右键-〉 ...

  8. dedecms文章的更新时间问题 每次更改文章时间变成最新的

    dedecms 每次更改文章,更新时间这里每次改了后再来看又变成当前最新时间的了. 解决方法: 查找后台目录的 templets/article_edit.htm 这个文件. 然后打开,查找如下代码: ...

  9. PyQt4环境搭建与使用

    初次使用python写图形界面的工具时,用了Tkinter.wxpython,都是需要手写界面布局的,看api看的头疼觉得这样写太费劲了,于是搜了下看看别人都是怎样写python图形界面的. 在论坛上 ...

  10. SMTP协议--在cmd下利用命令行发送邮件

    先简单介绍下smtp smtp使用命令和应答在客户与服务器之间传输报文.即客户发出一个命令,服务器返回一个应答.发送方与接收方进行一问一答的交互,由发送方控制这个对话. 在XP系统下点‘开始’-‘运行 ...