公司的游戏要开始定期发布安卓版本,各种渠道sdk版本有十个左右,将来也有增长的趋势,觉得用eclipse打包的话效率太低,就研究了下使用ant自动打包签名apk。
其实eclipse打包无非也是使用android sdk以及jdk的一些命令,具体如下几个步骤:
1. 生成应用的R.java
2. 编译所有java文件为class文件
3. 打包class文件和jar包为class.dex
4. 打包assets和res资源为压缩包
5. 组合class.dex和资源压缩包生成未签名的apk
6. 签名apk
7. 字节对齐(优化,可以不需要)
每个步骤对应的命令和ant脚本如下:
1. 生成应用的R.java
<exec executable="${aapt}" failοnerrοr="true">
<arg value="package" />
<arg value="-m" />
<arg value="-J" />
<arg value="${outdir-r}" />
<arg value="-M" />
<arg value="AndroidManifest.xml" />
<arg value="-S" />
<arg value="${resource-dir}" />
<arg value="-I" />
<arg value="${android-jar}" />
</exec>
2. 编译所有java文件为class文件
<echo>Compiling aidl files into Java classes...</echo>
<apply executable="${aidl}" failοnerrοr="true">
<arg value="-p${android-framework}" />
<arg value="-I${srcdir}" />
<fileset dir="${srcdir}">
<include name="**/*.aidl" />
</fileset>
</apply>
<!-- Compile this project's .java files into .class files. -->
<javac encoding="UTF-8" target="1.5" source="1.5" includeAntRuntime="false" extdirs="" srcdir="." destdir="${outdir-classes}" bootclasspath="${android-jar}"> <classpath>
<fileset dir="${external-libs}" includes="*.jar" />
</classpath>
</javac>
代码中或者res/string/values.xml中有中文的话,javac的encoding命令最好制定UTF-8
3. 打包class文件和jar包为class.dex
<apply executable="${dx}" failοnerrοr="true" parallel="true">
<arg value="--dex" />
<arg value="--output=${intermediate-dex-ospath}" />
<arg path="${outdir-classes-ospath}" />
<fileset dir="${external-libs}" includes="*.jar" />
</apply>
4. 打包assets和res资源为压缩包
<exec executable="${aapt}" failοnerrοr="true">
<arg value="package" />
<arg value="-f" />
<arg value="-M" />
<arg value="AndroidManifest.xml" />
<arg value="-S" />
<arg value="${resource-dir}" />
<arg value="-A" />
<arg value="${asset-dir}" />
<arg value="-I" />
<arg value="${android-jar}" />
<arg value="-F" />
<arg value="${resources-package}" />
</exec>
5. 组合class.dex和资源压缩包生成未签名的apk
<exec executable="${apk-builder}" failοnerrοr="true">
<arg value="${out-unsigned-package-ospath}" />
<arg value="-u" />
<arg value="-z" />
<arg value="${resources-package-ospath}" />
<arg value="-f" />
<arg value="${intermediate-dex-ospath}" />
<arg value="-rf" />
<arg value="${srcdir-ospath}" />
<arg value="-nf" />
<arg value="${external-libs-ospath}" />
</exec>
如果有c++生成的.so文件,需要-nf文件制定.so文件路径
6. 签名apk
<exec executable="${jarsigner}" failοnerrοr="true">
<arg value="-digestalg" />
<arg value="SHA1" />
<arg value="-sigalg" />
<arg value="MD5withRSA" />
<arg value="-keystore" />
<arg value="android.keystore"/>
<arg value="-storepass" />
<arg value="${local.key.store.password}" />
<arg value="-signedjar" />
<arg value="${out-signed-package-ospath}" />
<arg value="${out-unsigned-package-ospath}" />
<arg value="${local.key.alias}" />
</exec>
如果用的是jdk1.6可以不需要-digestalg SHA1 -sigalgMD5withRSA参数,因为默认就是这种。
jdk1.7以上必须加上-digestalg SHA1 -sigalg MD5withRSA参数,不然签名会失败
7. 字节对齐(优化,可以不需要)
<exec executable="${zipalign}" failοnerrοr="true">
<arg value="-f" />
<arg value="4" />
<arg value="${out-signed-package-ospath}" />
<arg value="${zipalign-package-ospath}" />
</exec>
有引用外部android project的打包方式略有不同,外部lib project如果只需要引用jar包的话,可以直接引用对应jar包就行了,没啥太大区别。如果外部lib project的res目录下有资源的话,需要稍作修改,具体修改的几个步骤如下:
1. 生成应用的R.java
<exec executable="${aapt}" failοnerrοr="true">
<arg value="package" />
<arg value="-m" />
<arg value="--auto-add-overlay" />
<arg value="-J" />
<arg value="${outdir-r}" />
<arg value="-M" />
<arg value="AndroidManifest.xml" />
<arg value="-S" />
<arg value="${resource-dir}" />
<arg value="-S" />
<arg value="${extrasdk.dir}/${resource-dir}" />
<arg value="-I" />
<arg value="${android-jar}" />
</exec>
<exec executable="${aapt}" failοnerrοr="true">
<arg value="package" />
<arg value="-m" />
<arg value="--auto-add-overlay" />
<arg value="-J" />
<arg value="${outdir-r}" />
<arg value="-M" />
<arg value="${extrasdk.dir}/AndroidManifest.xml" />
<arg value="-S" />
<arg value="${resource-dir}" />
<arg value="-S" />
<arg value="${extrasdk.dir}/${resource-dir}" />
<arg value="-I" />
<arg value="${android-jar}" />
</exec>
2. 编译所有java文件为class文件
<echo>Compiling aidl files into Java classes...</echo>
<apply executable="${aidl}" failοnerrοr="true">
<arg value="-p${android-framework}" />
<arg value="-I${srcdir}" />
<fileset dir="${srcdir}">
<include name="**/*.aidl" />
</fileset>
</apply>
<!-- Compile this project's .java files into .class files. -->
<javac encoding="UTF-8" target="1.5" source="1.5" includeAntRuntime="false" extdirs="" srcdir="." destdir="${outdir-classes}" bootclasspath="${android-jar}"> <classpath>
<fileset dir="${external-libs}" includes="*.jar" />
<fileset dir="${extrasdk.dir}/libs" includes="*.jar" />
</classpath>
</javac>
3. 打包class文件和jar包为class.dex
<apply executable="${dx}" failοnerrοr="true" parallel="true">
<arg value="--dex" />
<arg value="--output=${intermediate-dex-ospath}" />
<arg path="${outdir-classes-ospath}" />
<fileset dir="${external-libs}" includes="*.jar" />
<fileset dir="${extrasdk.dir}/libs" includes="*.jar" />
</apply>
4. 打包assets和res资源为压缩包
<exec executable="${aapt}" failοnerrοr="true">
<arg value="package" />
<arg value="-f" />
<arg value="--auto-add-overlay" />
<arg value="-M" />
<arg value="AndroidManifest.xml" />
<arg value="-S" />
<arg value="${resource-dir}" />
<arg value="-S" />
<arg value="${extrasdk.dir}/${resource-dir}" />
<arg value="-A" />
<arg value="${asset-dir}" />
<arg value="-I" />
<arg value="${android-jar}" />
<arg value="-F" />
<arg value="${resources-package}" />
</exec>
其他步骤一致,基本思路就是打包资源时需要打包进外链工程的res下资源,编译时引用外链工程的jar包。外链工程assets下面如果有资源的话需要手动拷贝至项目工程assets下。
一些会遇到问题和解决方式:
1. 签名不成功,如果用的是jdk1.7及以上的话, jarsigner签名时需要带上-digestalg SHA1 -sigalg MD5withRSA参数,默认jdk1.7使用的加密方式不是这种,会签名后导致apk运行不成功。
2. 为了打包脚本在各个机器上都能运行成功,相关工具路径可以从windows环境变量获取,这样不用手动修改各个机器的工具路径,方便打包。
3. jar包中有assets资源或者res资源的,需要手动拷贝至项目目录,不然脚本打包无法将这些资源打包进最终apk。