黑马程序员技术交流社区

标题: Android动态加载jar/dex [打印本页]

作者: 407827531    时间: 2013-12-16 09:34
标题: Android动态加载jar/dex
本帖最后由 407827531 于 2013-12-16 09:35 编辑

前言

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

  1. @Override
  2.     public void onCreate(Bundle savedInstanceState) {
  3.         super.onCreate(savedInstanceState);
  4.         setContentView(R.layout.main);
  5.         mToastButton = (Button) findViewById(R.id.toast_button);
  6.          

  7.          
  8.         mToastButton.setOnClickListener(new View.OnClickListener() {
  9.             public void onClick(View view) {

  10.                 final File optimizedDexOutputPath = new File(Environment.getExternalStorageDirectory().toString()
  11.                     + File.separator + "test.jar");
  12.                 // Initialize the class loader with the secondary dex file.
  13. //                DexClassLoader cl = new DexClassLoader(dexInternalStoragePath.getAbsolutePath(),
  14. //                        optimizedDexOutputPath.getAbsolutePath(),
  15. //                        null,
  16. //                        getClassLoader());
  17.                 DexClassLoader cl = new DexClassLoader(optimizedDexOutputPath.getAbsolutePath(),
  18.                     Environment.getExternalStorageDirectory().toString(), null, getClassLoader());
  19.                 Class libProviderClazz = null;
  20.                  
  21.                 try {
  22.                     // Load the library class from the class loader.
  23.                     // 载入从网络上下载的类
  24. //                    libProviderClazz = cl.loadClass("com.example.dex.lib.LibraryProvider");
  25.                     libProviderClazz = cl.loadClass("com.dynamic.DynamicTest");
  26.                      
  27.                     // Cast the return object to the library interface so that the
  28.                     // caller can directly invoke methods in the interface.
  29.                     // Alternatively, the caller can invoke methods through reflection,
  30.                     // which is more verbose and slow.
  31.                     //LibraryInterface lib = (LibraryInterface) libProviderClazz.newInstance();
  32.                     IDynamic lib = (IDynamic)libProviderClazz.newInstance();
  33.                      
  34.                     // Display the toast!
  35.                     //lib.showAwesomeToast(view.getContext(), "hello 世界!");
  36.                     Toast.makeText(MainActivity.this, lib.helloWorld(), Toast.LENGTH_SHORT).show();
  37.                 } catch (Exception exception) {
  38.                     // Handle exception gracefully here.
  39.                     exception.printStackTrace();
  40.                 }
  41.             }
  42.         });
  43.     }
复制代码


    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.4  执行结果

    









欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2