1. 程式人生 > >eclipse解決超過65535的問題???

eclipse解決超過65535的問題???

        專案開發到一定程度遇到了dex超過65536的問題,也就是方法數量超過65536個了,編譯不過去,生成不了apk檔案,百度了很多文章關於這bug的解決辦法,按照步驟實現了都沒有效果,不知道怎麼解決,有沒有在eclipse解決超過65535的問題的大神?請求支援。

以下是我參考的文章:

1、

http://www.lephones.net/2014/11/27/multi-dex-app/

2、

http://blog.csdn.net/calvin_zhou/article/details/50554184

3、

http://m.blog.csdn.net/article/details?id=51385240

4、

http://transcoder.baidu.com/from=844b/bd_page_type=1/ssid=0/uid=0/pu=usm%400%2Csz%401320_2001%2Cta%40iphone_1_9.3_3_601/baiduid=A6AF733EDAC649263B154A1E0D516E3E/w=0_10_eclipse+65536/t=iphone/l=3/tcref=www_iphone&lid=4206176381798708912&order=2&fm=alop&tj=www_normal_2_0_10_title&vit=osres&m=8&srd=1&cltj=cloud_title&asres=1&title=eclipse%E4%B8%8B%E4%BD%BF%E7%94%A8MultiDex%E8%A7%A3%E5%86%B365536%E9%99%90%E5%88%B6&dict=30&sec=14742&di=2b6eb361973edbd7&bdenc=1&tch=124.433.29.300.1.261&tch=124.84.77.295.2.648&nsrc=IlPT2AEptyoA_yixCFOxXnANedT62v3IEQGG_yFZ0z3xokmyxP4kHREsRDb6NnTLJ5DhxWeCvB9FuXCh2m9skNYWgK&eqid=3a5f57224bbff6001000000157bfe5a6&wd=&clk_info=%7B%22srcid%22%3A%22www_normal%22%2C%22tplname%22%3A%22www_normal%22%2C%22t%22%3A1472194042805%2C%22xpath%22%3A%22div-a-h3%22%7D

但是跟著步驟解決在dos命令視窗還是出現了問題,分包不成功。有沒有親手操作過的可以推薦篇文章或者賜教步驟麼?

後面經過大神的不吝賜教,總結以下步驟:

 eclipse下android專案解決方法數超過65536方案

java.lang.IllegalArgumentException: method ID not in [0,0xffff]: 65536, 應用中的Dex 檔案方法數超過了最大值65536的上限,簡單來說,應用爆棚了.

        那麼讓我們看一下為什麼會引起這種錯誤:

        在Android系統中,一個App的所有程式碼都在一個Dex檔案裡面。Dex是一個類似Jar的儲存了許多Java

編譯位元組碼的歸檔檔案。因為Android系統使用Dalvik虛擬機器,所以需要把使用Java Compiler編譯之後的class檔案轉換成Dalvik能夠執行的class檔案。這裡需要強調的是,DexJar一樣是一個歸檔檔案,裡面仍然是Java程式碼對應的位元組碼檔案。當Android系統啟動一個應用的時候,有一步是對Dex進行優化,這個過程有一個專門的工具來處理,叫DexOptDexOpt的執行過程是在第一次載入Dex檔案的時候執行的。這個過程會生成一個ODEX檔案,即Optimised Dex。執行ODex的效率會比直接執行Dex檔案的效率要高很多。但是在早期的Android系統中,DexOpt有一個問題,也就是這篇文章想要說明並解決的問題。DexOpt會把每一個類的方法id檢索起來,存在一個連結串列結構裡面。但是這個連結串列的長度是用一個short型別來儲存的,導致了方法id的數目不能夠超過65536個。當一個專案足夠大的時候,顯然這個方法數的上限是不夠的。儘管在新版本的Android系統中,DexOpt修復了這個問題,但是我們仍然需要對低版本的Android系統做相容.

由於之前一直是在eclipse上開發的Android專案,所以優先考慮通過動態載入dex的方式解決該問題,而沒有采用將專案遷移到AndroidStudio上的方案。

該方案的本質是將可以分包的jar打包為一個apk檔案,放在assets資料夾下,在應用初始化時載入此apk檔案

下面講一下具體的操作步驟:

1、將可以分到第二個包的jar檔案利用ant合併為一個jar包,如libs.jar。對ant不熟悉的同學也可以採用手動方式合併jar檔案,將要合併的jar檔案解壓到同一目錄下,然後將該目錄壓縮成libs.zip,再重新命名為libs.jar

2、使用Android SDK提供的dx工具將libs.jar轉換為dex檔案,命名為classes.dex。

dx工具可以在Android SDK下找到,如\SDK\build-tools\23.0.1\dx.bat

開啟命令列工具,進入到dx.bat所在的目錄下,執行命令 如:dx --dex --output=D:\test\classes.dex D:\test\libs.jar

D:\test\classes.dex為打包生成的dex檔案的目標路徑,D:\test\libs.jar為jar檔案的路徑

3、將上一步打包生成的classes.dex新增為壓縮檔案libs.zip, 然後重新命名為libs.apk

4、將libs.apk放入專案的assets資料夾下

5.將步驟1中的被分出的jar包從專案libs資料夾下刪除,將合併後的jar包依照外部jar的方式引入專案,android.jar就是採用了此種依賴方式

        專案--右鍵--Build Path --Configure Build Path --- Libraries ---AddExternal JARs

6、在專案的Application中新增下面的方法

public class App extends Application {

    @Override

    public void onCreate() {

        super.onCreate();

        dexTool();

    }

    /**

     * Copy the following code and calldexTool() after super.onCreate() in

     * Application.onCreate()

     * <p>

     * This method hacks the defaultPathClassLoader and load the secondary dex

     * file as it's parent.

     */

    @SuppressLint("NewApi")

    private void dexTool() {

        File dexDir = newFile(getFilesDir(), "dlibs");

        dexDir.mkdir();

        File dexFile = newFile(dexDir, "libs.apk");

        File dexOpt = newFile(dexDir, "opt");

        dexOpt.mkdir();

        try {

           InputStream ins = getAssets().open("libs.apk");

           if (dexFile.length() != ins.available()) {

               FileOutputStream fos = new FileOutputStream(dexFile);

               byte[] buf = new byte[4096];

               int l;

               while ((l = ins.read(buf)) != -1) {

                   fos.write(buf, 0, l);

               }

               fos.close();

           }

           ins.close();

        } catch (Exception e) {

           throw new RuntimeException(e);

        }

        ClassLoader cl =getClassLoader();

        ApplicationInfo ai =getApplicationInfo();

        String nativeLibraryDir= null;

        if(Build.VERSION.SDK_INT > 8) {

           nativeLibraryDir = ai.nativeLibraryDir;

        } else {

           nativeLibraryDir = "/data/data/" + ai.packageName +"/lib/";

        }

        DexClassLoader dcl = newDexClassLoader(dexFile.getAbsolutePath(),

               dexOpt.getAbsolutePath(), nativeLibraryDir, cl.getParent());

        try {

           Field f = ClassLoader.class.getDeclaredField("parent");

           f.setAccessible(true);

           f.set(cl, dcl);

        } catch (Exception e) {

           throw new RuntimeException(e);

        }

    }

}

        注:Application 中的靜態全域性變數會比MutiDex的 instal()方法優先載入,所以建議避免在 Application類中使用引用classes.dex檔案的靜態變數

至此,問題解決。