博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[转]Android动态加载jar/dex
阅读量:5936 次
发布时间:2019-06-19

本文共 4601 字,大约阅读时间需要 15 分钟。

本文转自:

 

前言

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

 

声明

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

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

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

    Android中文翻译组:

 

正文

  一、 基本概念和注意点

    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  下载开源项目

      

      将项目导入工程,工程报错的话应该是少了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  执行结果

     

 

  四、参考文章

    

    

    

    

 

  五、补充

    大家可以看看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  本文升级版:

      

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

 

结束

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

 

你可能感兴趣的文章
ApacheCN 翻译活动进度公告 2019.2.18
查看>>
分布式memcached服务器代理magent安装配置(CentOS6.6)
查看>>
Create Volume 操作(Part III) - 每天5分钟玩转 OpenStack(52)
查看>>
KSImageNamed-Xcode-master
查看>>
tomcat 8.0虚拟机配置文档
查看>>
轻松实现基于Heartbeat的高可用web服务集群
查看>>
pxc群集搭建
查看>>
JS中加载cssText延时
查看>>
常用的脚本编程知识点
查看>>
XILINX_zynq_详解(6)
查看>>
计算机网络术语总结4
查看>>
新手小白 python之路 Day3 (string 常用方法)
查看>>
HTML5 Geolocation API工作原理[转载]
查看>>
soapUI的简单使用(webservice接口功能测试)
查看>>
框架 Hibernate
查看>>
python-while循环
查看>>
【微信小程序】再次授权地理位置getLocation+openSetting使用
查看>>
手机端上传图片及java后台接收和ajaxForm提交
查看>>
HDU 5030 Rabbit's String
查看>>
【MSDN 目录】C#编程指南、C#教程、ASP.NET参考、ASP.NET 4、.NET Framework类库
查看>>