参考连接:java
Dex65536
android
解决Android单个dex文件不能超过65536个方法问题git
Android dex分包方案github
1、 基本概念和注意点
windows
1.1 首先须要了解一点:在Android中能够动态加载,但没法像Java中那样方便动态加载jar网络
缘由:Android的虚拟机(Dalvik VM)是不认识Java打出jar的byte code,须要经过dx工具来优化转换成Dalvik byte code才行。这一点在我们Android项目打包的apk中能够看出:引入其余Jar的内容都被打包进了classes.dex。
ide
因此这条路不通,请你们注意。工具
1.2 当前哪些API可用于动态加载优化
1.2.1 DexClassLoaderthis
这个能够加载jar/apk/dex,也能够从SD卡中加载,也是本文的重点。
1.2.3 PathClassLoader
只能加载已经安装到Android系统中的apk文件。
2、 准备
本文主要参考"4、参考文章"中第一篇文章,补充细节和实践过程。
2.1 下载开源项目
http://code.google.com/p/goodev-demo
将项目导入工程,工程报错的话应该是少了gen文件夹,手动添加便可。注意这个例子是从网上下载优化好的jar(已经优化成dex而后再打包成的jar)到本地文件系统,而后再从本地文件系统加载并调用的。本文则直接改为从SD卡加载。
3、实践
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"); //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(); } } }); }