Android动态加载jar/dex

摘要:
本文对网上Android动态加载jar的资料进行梳理和实践在这里与大家一起分享,试图改善频繁升级这一弊病。这一点在咱们Android项目打包的apk中可以看出:引入其他Jar的内容都被打包进了classes.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

packagecom.dynamic;
publicinterfaceIDynamic{
publicStringhelloWorld();
}

3.1.2  实现类DynamicTest

复制代码
packagecom.dynamic;
publicclassDynamicTestimplementsIDynamic{
@Override
publicStringhelloWorld(){
return"HelloWorld!";
}
}
复制代码

3.2  打包并转成dex

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

Android动态加载jar/dex第3张

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

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

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

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

3.3  修改调用例子

修改MainActivity,如下:

复制代码
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mToastButton=(Button)findViewById(R.id.toast_button);
//BeforethesecondarydexfilecanbeprocessedbytheDexClassLoader,
//ithastobefirstcopiedfromassetresourcetoastoragelocation.
//finalFiledexInternalStoragePath=newFile(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);
////PerformthefilecopyinginanAsyncTask.
////从网络下载需要的dex文件
//(newPrepareDexTask()).execute(dexInternalStoragePath);
//}else{
//mToastButton.setEnabled(true);
//}
mToastButton.setOnClickListener(newView.OnClickListener(){
publicvoidonClick(Viewview){
//InternalstoragewheretheDexClassLoaderwritestheoptimizeddexfileto.
//finalFileoptimizedDexOutputPath=getDir("outdex",Context.MODE_PRIVATE);
finalFileoptimizedDexOutputPath=newFile(Environment.getExternalStorageDirectory().toString()
+File.separator+"test.jar");
//Initializetheclassloaderwiththesecondarydexfile.
//DexClassLoadercl=newDexClassLoader(dexInternalStoragePath.getAbsolutePath(),
//optimizedDexOutputPath.getAbsolutePath(),
//null,
//getClassLoader());
DexClassLoadercl=newDexClassLoader(optimizedDexOutputPath.getAbsolutePath(),
Environment.getExternalStorageDirectory().toString(),null,getClassLoader());
ClasslibProviderClazz=null;
try{
//Loadthelibraryclassfromtheclassloader.
//载入从网络上下载的类
//libProviderClazz=cl.loadClass("com.example.dex.lib.LibraryProvider");
libProviderClazz=cl.loadClass("com.dynamic.DynamicTest");
//Castthereturnobjecttothelibraryinterfacesothatthe
//callercandirectlyinvokemethodsintheinterface.
//Alternatively,thecallercaninvokemethodsthroughreflection,
//whichismoreverboseandslow.
//LibraryInterfacelib=(LibraryInterface)libProviderClazz.newInstance();
IDynamiclib=(IDynamic)libProviderClazz.newInstance();
//Displaythetoast!
//lib.showAwesomeToast(view.getContext(),"hello世界!");
Toast.makeText(MainActivity.this,lib.helloWorld(),Toast.LENGTH_SHORT).show();
}catch(Exceptionexception){
//Handleexceptiongracefullyhere.
exception.printStackTrace();
}
}
});
}
复制代码

3.4  执行结果

Android动态加载jar/dex第6张

四、参考文章

[推荐]在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.jardynamic.jar

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

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

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

结束

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

免责声明:文章转载自《Android动态加载jar/dex》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇JS来推断文本框内容改变事件【转】Jmeter如何把响应数据的结果保存到本地的一个文件下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

安卓中的线程

 1. Android进程    在了解Android线程之前得先了解一下Android的进程。当一个程序第一次启动的时候,Android会启动一个LINUX进程和一个主线程。默认的情况下,所有该程序的组件都将在该进程和线程中运行。同时,Android会为每个应用程序分配一个单独的LINUX用户。Android会尽量保留一个正在运行进程,只在内存资源出现...

安卓学习(一)

---恢复内容开始--- res目录 src目录 AdroidManifest.xml是Android项目必须的 其他目录文件都是可选的 ----res 目录春发给android项目的各种资源文件,比如layout存放界面布局文件 values目录下存放各种xml格式的资源文件 ,例如 字符串资源文件:Strings.xml 颜色资源文件:colors....

Android下OpenCV的环境搭建

目录(?)[-] 前言 系统环境 相关工具 Android ADT环境搭建 Android SDK环境变量的配置 Android NDK的安装与配置 OpenCV for Android 环境搭建 基于SDK的OpenCV开发 基于NDK的OpenCV开发 Android上层程序的编写 来自CODE的代码片 activity_mainxml...

ShortcutBadgerDemo【安卓应用角标(badge)实现方案】

 版权声明:本文为HaiyuKing原创文章,转载请注明出处! 概述 本文主要使用的开源库是 leolin310148/ShortcutBadger,但是在其基础上做了一些修改。 什么是应用角标? 1、角标,英文名badge,即桌面上显示未读消息的小数字,原ios功能,Android原生并没有该功能。(原生的Android系统,是不支持应用角标的) 应用角...

Android框架式编程之BufferKnife

BufferKnife作为框架式编程的重要组成部分,使用BufferKnife能够极大的精简View层面的代码量,并为MVP/MVC方式提供辅助。 一、配置 compile 'com.jakewharton:butterknife:(insert latest version)' annotationProcessor 'com.jakewharton:...

Android 开 发 资 源 分 享

一、精编教程贴 1、安卓模拟器BlueStacks安装使用教程 http://www.apkbus.com/android-64318-1-1.html 2、Mkey libgdx游戏引擎教程 http://www.apkbus.com/android-57355-1-1.html 3、java基础 与 android学习指南——实例教程 http://w...