天天看點

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檔案。這裡需要強調的是,Dex和Jar一樣是一個歸檔檔案,裡面仍然是Java代碼對應的位元組碼檔案。當Android系統啟動一個應用的時候,有一步是對Dex進行優化,這個過程有一個專門的工具來處理,叫DexOpt。DexOpt的執行過程是在第一次加載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();

    }

    @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檔案的靜态變量

至此,問題解決。

繼續閱讀