天天看点

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文件的静态变量

至此,问题解决。