參考連接: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(); } } }); }