`

Android动态加载jar/dex

 
阅读更多

Android动态加载jar/dex

前言

   在目前的软硬件环境下,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  修复本文错误

      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,基于android studio+android开发艺术其他demo

    Android动态加载jar/dex+android开发艺术其他demo,基于android studio,示例代码,需要的可看

    安卓插件机制相关-android动态加载插件dex后的jar以方便功能扩展.rar

    android 动态加载插件(dex后的jar)以方便功能扩展.rar,太多无法一一验证是否可用,程序如果跑不起来需要自调,部分代码功能进行参考学习。

    Android 中动态加载.jar的实现步骤

    首先第一个是 jar 文件的制作,Java 里面直接把 .class 文件打包到 .jar 文件里面就可以了,但是 Android 的 Dalvik VM 是不认 Java ...要动态加载其它类,可以用的 Class Loader 有: DexClassLoader,PathClassLoader

    Android代码-应用模块化和懒加载在 Instagram 中的实现

    Before this library can be used a module needs to be compiled to a separate jar/dex or apk file. Right now, the library supports java libraries and android libraries which don't rely on android ...

    jar动态加载测试包

    jar动态加载测试包,for Android开发系列之动态添加dex。

    dex2jar,apk反编译

    很好用的一个apk反编译软件,本人屡试不爽,不过用配置dex2jar的路径,首先解压dex2jar.zip,然后将解压后的dex2jar拷贝到c盘的根目录下,然后在配置dex2jar的环境变量,就是把dex2jar的路径加入到path路径中,然后再...

    loaddex:android 动态加载dex

    工作原理:首先把需要动态加载的部分导出jar,然后用sdk中的命令把jar编译成dex的jar,在代码中用classloader来加载编译好的jar就可以了,在原始包中如果要调用dex中的方法,需要用反射的方式调用,而dex中的方法则...

    下载服务端dex文件,动态加载dex文件源码

    从服务端下载dex文件并保存到app私有目录,将保存的dex文件动态加载执行

    DexClassloader:这个一个demo,用来实现加载class文件,如果在实际项目中可以实现,动态修改代码的业务逻辑

    DexClassloader 这个一个demo,用来实现加载class文件,如果在实际项目中可以...2: DexClassloader: Android 用来加载 jar/apk/dex 文件 3: URLClassloader: 可以加载java的jar包,但是Dalvik 虚拟机不支持这种加载方式

    Android开发艺术探索

    13.3 Android的动态加载技术 / 463 13.4 反编译初步 / 469 13.4.1 使用dex2jar和jd—gui反编译apk / 470 13.4.2 使用apktool对apk进行二次打包 / 470 第14章 JNI和NDK编程 / 473 14.1 JNI的开发流程 / ...

    auto.js 百度对象存储 bos 的dex文件

    使用的jar为 bce-android-sdk-1.0.14.jar 用loadDex加载 dex和jar 都在压缩包 runtime.loadDex(files.getSdcardPath() + "/classes.dex"); importClass(com.baidubce.services.bos.BosClientConfiguration); ...

    Android-Method-Swizzling

    Android方法混乱 Android Studio从位于/build/outputs/aar/.aar下的模块生成aar文件 从aar提取jar文件:使用存档管理器时打开aar,而aar文件包含classes.jar文件。... 现在可以动态加载该dex文件。

    apk加壳和动态加载技术

    动态加载技术 该技术在Java中是一个比较成熟的技术,而Android中该技术还没有被大家充分利用起来。该技术思想主要分为以下几步: 1.将核心代码编译成dex文件的Jar包 2. 对jar包进行加密处理 3.在程序主入口利用NDK...

    Dex_Plugin_Project.zip

    Android动态加载Dex文件,将一个类转为jar包的形式,通过android sdk自带的dx.jar工具转换jar包为包含dex文件的Jar文件,然后用DexClassLoader去加载 详情看我博客 ...

    android开发艺术探索高清完整版PDF

    / 441 12.3.2 优化列表的卡顿现象 / 446 第13章 综合技术 / 448 13.1 使用Crash Handler来获取应用的crash信息 / 449 13.2 使用multidex来解决方法数越界 / 455 13.3 Android的动态加载技术 / 463 13.4 反编译...

    计算Android中APK或DEX方法数量工具

    电脑需要java环境,如果dex-method-counts.jar工具放在D盘,直接使用命令java -jar D:\dex-method-counts.jar D:\test.apk,如果需要计算类的field数量 添加“--count-fields”参数,如java -jar D:\dex-method-...

    字节码查看器:一个Java 8+ Jar和Android APK逆向工程套件(反编译器,编辑器,调试器等)

    APK / DEX支持-使用Dex2Jar和Jar2Dex,可以轻松加载和保存APK! Java反编译器-它利用FernFlower,Procyon,CFR和JD进行反编译。 字节码反编译器-CFIDE的修改版本。 十六进制查看器-由JHexPane提供支持。 每个反...

    Android_RAT

    此项目生成的部分需要添加的代码,例如myService中动态加载包含RA逻辑的jar并执行,注册屏幕监听事件。 生成方式 电报编译打包 gradlew makeJar //生成jar dx --dex --output ratdex.jar rat.jar //转换jar java -...

Global site tag (gtag.js) - Google Analytics