ant脚本使用multidex解决65536问题

现在的android项目应该大多都用gradle构建了吧,但是仍然有很多老项目使用的ant工具,这里并不推荐使用ant构建,因为最新的android sdk tools里边已经去掉了ant相关的lib包。不管gradle也好,ant也好,其实编译打包apk的过程基本都是一样的。

我遇到的这个项目,经历了两次方案的调整。

方案一:

最开始并没用dx的multidex参数,而是将所有的第三方jar包(应用启动时用的除外)打到从包中去,从包可以是多个,剩下的源码打到主包中,也就是分别调用dx打出dex包。

<macrodef name="dex-helper">
        <element name="external-libs" optional="yes" />
        <attribute name="nolocals" default="false" />
        <sequential>
            <!-- sets the primary input for dex. If a pre-dex task sets it to
                 something else this has no effect -->
            <property name="out.dex.input.absolute.dir" value="${out.classes.absolute.dir}" />

            <!-- set the secondary dx input: the project (and library) jar files
                 If a pre-dex task sets it to something else this has no effect -->
            <if>
                <condition>
                    <isreference refid="out.dex.jar.input.ref" />
                </condition>
                <else>
                    <path id="out.dex.jar.input.ref">
                        <path refid="project.all.jars.path" />
                    </path>
                </else>
            </if>
            <echo>Converting external libraries into ${assets}/${dex}...</echo>
	    <delete file="${asset.absolute.dir}\plug.jar"/>
	    <delete file="${asset.absolute.dir}\plug2.jar"/>
	    <if condition="${proguard.enabled}">
            	<then>
            	    <separete 
            	        inputjar="${out.dex.input.absolute.dir}"
            	        mapping="${obfuscate.absolute.dir}/mapping.txt"
            	        alljarpath="project.all.jars.path"
			plugjarconfig="${plug.jar.config}"
			plugjarconfig2="${plug.jar.config2}"
			plugjarpath="project.plug.path"
			plugjarpath2="project.plug.path2"
			projectjarpath="project.core.path"/>
            	    <path id="project.dex.core.path">
                        <path refid="project.core.path" />
                    </path>
                </then>
            	<else>
            		<filterlib 
				alljarpath="project.all.jars.path"
			   	plugjarconfig="${plug.jar.config}"
			   	plugjarconfig2="${plug.jar.config2}"
			    	plugjarpath="project.plug.path"
			    	plugjarpath2="project.plug.path2"
			    	projectjarpath="project.core.path"/>
                     	<path id="project.dex.core.path">
                         <path path="${out.dex.input.absolute.dir}"/>
	              		 <path refid="project.core.path" />
                   	 </path>
                </else>
	   </if>

            <dex executable="${dx}"
                    output="${asset.absolute.dir}\plug.jar"
                  	dexedlibs="${out.dexed.absolute.dir}"
                    nolocals="@{nolocals}"
                    forceJumbo="${dex.force.jumbo}"
                    disableDexMerger="${dex.disable.merger}"
                    verbose="${verbose}">
                <path refid="project.plug.path" />
            </dex>
            <dex executable="${dx}"
                    output="${asset.absolute.dir}\plug2.jar"
                  	dexedlibs="${out.dexed.absolute.dir}"
                    nolocals="@{nolocals}"
                    forceJumbo="${dex.force.jumbo}"
                    disableDexMerger="${dex.disable.merger}"
                    verbose="${verbose}">
                <path refid="project.plug.path2" />
            </dex>
            <delete file="${asset.absolute.dir}\plug.jar.d"/>
            <delete file="${asset.absolute.dir}\plug2.jar.d"/>
	    <checksum file="${asset.absolute.dir}\plug.jar" forceOverwrite="yes"/>
	    <checksum file="${asset.absolute.dir}\plug2.jar" forceOverwrite="yes"/>
	    <dex executable="${dx}"
                    output="${intermediate.dex.file}"
                    dexedlibs="${out.dexed.absolute.dir}"
                    nolocals="@{nolocals}"
                    forceJumbo="${dex.force.jumbo}"
                    disableDexMerger="${dex.disable.merger}"
                    verbose="${verbose}">
	              <path refid="project.dex.core.path" />
                <external-libs />
            </dex>
            
        </sequential>
    </macrodef>

其中separete和filterlib是两个自定义的task,作用都是从project.all.jars.path中过滤出事先定义好的第三方jar包的path,区别是separete是在代码经过混淆后执行,将混淆后的代码生成plug.jar,可以看到调用了三次dex。

代码中加载从包的方法:

	PathClassLoader pathClassLoader = (PathClassLoader) app.getClassLoader();
	DexClassLoader dexClassLoader = new DexClassLoader(libPath, app.getDir("dex", 0).getAbsolutePath(), libPath, app.getClassLoader());
	InjectResult result = null;
	try {
		Object dexElements = combineArray(getDexElements(getPathList(pathClassLoader)), getDexElements(getPathList(dexClassLoader)));
		Object pathList = getPathList(pathClassLoader);
		setField(pathList, pathList.getClass(), "dexElements", dexElements);
	} catch (IllegalArgumentException e) {
		result = makeInjectResult(false, e);
		e.printStackTrace();
	}

DexClassLoader加载从包dex,然后将pathClassLoader与dexClassLoader中的DexPathList的dexElements属性值合并,再放到pathClassLoader中的DexPathList中。最开始方案一是满足需求的,但随着主包越来越大,终于还是65536了,这种只分出去第三方jar包的做法还是不太灵活,于是有了方案二。

方案二:

使用dx的multidex参数,指定maindexlist清单文件,在这个清单文件中的类会打到主包中,清单文件的生成可以使用build-tools下的mainDexClasses脚本生成。

 <macrodef name="dex-helper" >
		<element name="external-libs" optional="yes" />
        <attribute name="nolocals" default="false" />
        <sequential>
            <!-- sets the primary input for dex. If a pre-dex task sets it to
                 something else this has no effect -->
            <property name="out.dex.input.absolute.dir" value="${out.classes.absolute.dir}" />
			 <if>
                <condition>
                    <isreference refid="out.dex.jar.input.ref" />
                </condition>
                <else>
                    <path id="out.dex.jar.input.ref">
                        <path refid="project.all.jars.path" />
                    </path>
                </else>
            </if>
            <echo message="start dx ${maindexlist.dir}"/>
            <multidex executable="${dx}"
                    output="${out.dir}"
                    dexedlibs="${out.dexed.absolute.dir}"
                    nolocals="@{nolocals}"
                    forceJumbo="${dex.force.jumbo}"
                    disableDexMerger="${dex.disable.merger}"
                    multidex="true"
                    mainDexList="${maindexlist.dir}"
                    verbose="${verbose}">
	            <path path="${out.dex.input.absolute.dir}"/>  
                <path refid="out.dex.jar.input.ref" />  
                <external-libs />
            </multidex>
        </sequential>
    </macrodef>
<target name="-maindexlist" depends="-set-release-mode, -compile, -post-compile, -obfuscate">
        <property name="out.dex.input.absolute.dir" value="${out.classes.absolute.dir}" />

        <!-- set the secondary dx input: the project (and library) jar files
             If a pre-dex task sets it to something else this has no effect -->
        <if>
            <condition>
                <isreference refid="out.dex.jar.input.ref" />
            </condition>
            <else>
                <path id="out.dex.jar.input.ref">
                    <path refid="project.all.jars.path" />
                </path>
            </else>
        </if>
        <maindexlist output="build/maindexlist-proguard.txt"
                mainDexList="build/maindexlist.txt"
                mappingFile="${out.absolute.dir}/proguard/mapping.txt" >
            <path path="${out.dex.input.absolute.dir}"/>
            <path refid="out.dex.jar.input.ref" />
        </maindexlist>
    </target>

m ultidex和maindexlist也是两个自定义task,multidex其实就是调用的dx --dex --multi-dex --main-dex-list=maindexlist.txt  --minimal-main-dex --output bin --input-list,maindexlist task的作用是生成混淆后的主包清单文件。应用启动时代码原理和方案一差不多,也可以直接使用官方的android-surpport-multidex.jar包

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值