Android Ant打包

  • 时间:
  • 来源:互联网
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/chennai1101/article/details/103344782

1. 编译环境的配置

android和java的编译环境和ant工具的安装是必不可少的环节。

  • 配置文件ant.properties

    为了在不同的环境下能够顺利地进行编译,需要进行额外的配置,在项目目录下创建配置文件ant.properties。

    首先是android编译工具的选择。我们预留了sdk.dir这个变量是为了不同环境的编译,而exe{exe}和{bat}同样也是如此。也要用java.dir这个变量。

    # android platform
    sdk.platform=${sdk.dir}/platforms/android-19
    sdk.framework.jar=${sdk.platform}/android.jar
    sdk.framework.aidl=${sdk.platform}/framework.aidl
    
    # android build tools aapt/aidl/zipalign
    sdk.build.tools=${sdk.dir}/build-tools/19.1.0
    sdk.build.tools.aapt=${sdk.build.tools}/aapt${exe}
    sdk.build.tools.aidl=${sdk.build.tools}/aidl${exe}
    sdk.build.tools.zipalign=${sdk.build.tools}/zipalign${exe}
    sdk.build.tools.dx=${sdk.build.tools}/dx${bat}
    
    sdk.tool.lib=${sdk.dir}/tools/lib
    java.tool.jarsigner=${java.dir}/bin/jarsigner${exe}
    

    其次是编译过程中目录和过程文件

    # workspace directory
    asset.dir=assets
    src.dir=src
    gen.dir=gen
    res.dir=res
    bin.dir=bin
    lib.dir=libs
    proguard.home=${sdk.dir}/tools/proguard
    proguard.dir=proguard
    proguard.mapping=${proguard.dir}/mapping.txt
    bin.classes.dir=${bin.dir}/classes
    bin.classes.dex=${bin.dir}/classes.dex
    package.resource=${bin.dir}/resources.ap_
    project.unsigned.apk=${bin.dir}/unsigned.apk
    project.signed.apk=${bin.dir}/signed.apk
    

    最后是keystore文件

    # keystore
    key.keystore=demo.keystore
    key.keystore.storepass=123456
    key.keystore.keypass=123456
    key.keystore.alias=demo
    
  • 配置文件proguard-project.txt,主要是自定义混淆文件

    -dontpreverify              #混淆时是否做预校验
    -optimizationpasses 5       #指定代码的压缩级别 
    -dontoptimize               #不优化输入的类文件
    -dontusemixedcaseclassnames #混淆时不会产生形形色色的类名
    -repackageclasses           #把执行后的类重新放在某一个目录下,后跟一个目录名
    -allowaccessmodification    #优化时允许访问并修改有修饰符的类和类的成员
    
    -verbose                               #混淆时是否记录日志
    -dontskipnonpubliclibraryclasses       #指定不去忽略非公共的库类
    -dontskipnonpubliclibraryclassmembers  #指定不去忽略包可见的库类的成员
    
    -optimizations !code/simplification/arithmetic,!field/*,!class/merging/*   # 混淆时所采用的算法
    
    -keep public class * extends android.app.Activity
    -keep public class * extends android.app.Application
    -keep public class * extends android.app.Service
    -keep public class * extends android.content.BroadcastReceiver
    -keep public class * extends android.content.ContentProvider
    -keep public class * extends android.app.backup.BackupAgentHelper
    -keep public class * extends android.preference.Preference
    -keep public class com.android.vending.licensing.ILicensingService
    
    -libraryjars libs/android-support-v4.jar
    -keep class android.support.v4.** { *; }  
    -keep interface android.support.v4.app.** { *; }
    
    #某些构造方法不能去混淆
    -keep class * extends android.view.View {
        public <init>(android.content.Context);
        public <init>(android.content.Context, android.util.AttributeSet);
        public <init>(android.content.Context, android.util.AttributeSet, int);  
    }
    

2. build.xml文件

  • 初始化环境

    定义android、java目录,导入配置文件,清空bin/gen/proguard目录

    <property environment="env" />
    
    <condition property="exe" value=".exe" else="">
        <os family="windows" />
    </condition>
    <condition property="bat" value=".bat" else="">
        <os family="windows" />
    </condition>
    
    <condition property="sdk.dir" value="${env.ANDROID_HOME}">
        <isset property="env.ANDROID_HOME" />
    </condition>
    <fail
        message="sdk.dir is missing."
        unless="sdk.dir" />
    
    <condition property="java.dir" value="${env.JAVA_HOME}">
        <isset property="env.JAVA_HOME" />
    </condition>
    
    <loadproperties srcFile="ant.properties" />
    <loadproperties srcFile="project.properties" />
    
    <target name="init">
        <echo>${bin.dir}</echo>
        <echo>${gen.dir}</echo>
        <echo>${proguard.dir}</echo>
    
        <delete dir="${bin.dir}" />
        <delete dir="${gen.dir}" />
        <delete dir="${proguard.dir}" />
    
        <mkdir dir="${bin.dir}" />
        <mkdir dir="${gen.dir}" />
        <mkdir dir="${proguard.dir}" />
    </target>
    
  • 生成R.java和aidl文件

    <target name="gen-R" depends="init">
        <echo> === gen-R begin == </echo>
        <exec executable="${sdk.build.tools.aapt}" failοnerrοr="true">  
            <arg value="package" /> 
            <arg value="-f" /> 	<!-- force overwrite of existing files -->
            <arg value="-m" /> 	<!-- make package directories under location specified by -J -->  
            <arg value="-J" />  <!-- specify where to output R.java resource constant definitions -->
            <arg value="${gen.dir}" />  
            <arg value="-S" />  <!-- directory in which to find resources. Multiple directories will be scann -->
            <arg value="${res.dir}" />  
            <arg value="-I" />  <!-- add an existing package to base include set -->
            <arg value="${sdk.framework.jar}" />
            <arg value="-M" />  <!-- specify full path to AndroidManifest.xml to include in zip -->
            <arg value="AndroidManifest.xml" />  
            <arg value="--auto-add-overlay" /> <!-- 这个重要,覆盖资源,不然报错-->
        </exec>
        <echo> === gen-R end == </echo>
    </target>
    
    <target name="aidl" depends="init">
        <echo> === aidl begin == </echo>		
        <apply executable="${sdk.build.tools.aidl}" failοnerrοr="true">  
            <arg value="-p${sdk.framework.aidl}" />  <!--  file created by preprocess to import. -->
            <arg value="-I${src.dir}" />  	<!-- search path for import statements. -->
            <arg value="-o${gen.dir}" /> 	<!-- base output folder for generated files -->
            <fileset dir="${src.dir}">
                <include name="**/*.aidl" />  
            </fileset>  
        </apply>
        <echo> === aidl end == </echo>
    </target>
    
  • 编译Java文件

    <target name="compile" depends="gen-R,aidl">
        <echo> === compile begin == </echo>
    
        <delete dir="${bin.classes.dir}" />
        <mkdir dir="${bin.classes.dir}" />
    
        <javac encoding="UTF-8" destdir="${bin.classes.dir}"
            srcdir="${src.dir}:${gen.dir}"
            bootclasspath="${sdk.framework.jar}" 
            includeantruntime="false"
            target="1.6" source="1.6"> 
            <compilerarg line="-encoding UTF-8 " />
            <classpath>
                <fileset dir="${lib.dir}" includes="*.jar" />
            </classpath>
        </javac>
    
        <echo> === compile end == </echo>
    </target>
    
  • 混淆代码,这步可以省略

    <target name="optimize" depends="compile">
        <jar basedir="${bin.classes.dir}" destfile="temp.jar" />
        <java fork="true" jar="${proguard.home}/lib/proguard.jar" failοnerrοr="true">
            <jvmarg value="-Dmaximum.inlined.code.length=32" />
    
            <arg value="-injars temp.jar" />
            <arg value="-outjars optimized.jar" />            
            <arg value="-printmapping ${proguard.mapping}"/>
            <arg value="-libraryjars ${sdk.framework.jar}" />            
            <arg value="-dontpreverify" />
            <arg value="-dontoptimize" />
            <arg value="-dontusemixedcaseclassnames" />
    
            <arg value="-allowaccessmodification" />
            <arg value="@proguard-project.txt"/>  
        </java>
    
        <delete file="temp.jar" />
        <delete dir="${bin.classes.dir}" />
        <mkdir dir="${bin.classes.dir}" />
    
        <unzip dest="${bin.classes.dir}" src="optimized.jar" />
        <delete file="optimized.jar" />
    </target>
    
  • 生成dex文件

    <target name="dex" depends="optimize">
         <echo> === dex begin == </echo>				
         <exec executable="${sdk.build.tools.dx}" failοnerrοr="true">  
            <arg value="--dex" />  
            <arg value="--output=${bin.classes.dex}" /> <!-- 输出文件 -->    
            <arg value="${bin.classes.dir}" />
            <arg value="${lib.dir}" />
        </exec>
        <echo> === dex end == </echo>
    </target>
    
  • resource文件打包

    <target name="package-assets-res-manifest">
        <echo> === package-assets-res-manifest begin == </echo>
        <exec executable="${sdk.build.tools.aapt}" failοnerrοr="true">
            <arg value="package" /> 
            <arg value="-f" />  <!-- Adds the file to the application package. -->
            <arg value="-S" />	
            <arg value="${res.dir}" />
            <arg value="-A" />  
            <arg value="${asset.dir}" />  
            <arg value="-I" />
            <arg value="${sdk.framework.jar}" />
            <arg value="-M" />
            <arg value="AndroidManifest.xml" />
            <arg value="-F" />
            <arg value="${package.resource}" />
        </exec>
        <echo> === package-assets-res-manifest end == </echo>
    </target>
    
  • 生成未签名apk文件

    <target name="build" depends="dex,package-assets-res-manifest">
        <echo> === build start == </echo>
        <java classpath="${sdk.tool.lib}/sdklib.jar"
            classname="com.android.sdklib.build.ApkBuilderMain">
            <arg value="${project.unsigned.apk}" />
            <arg value="-v" /> <!-- Verbose. -->
            <arg value="-u" /> <!-- Creates an unsigned package. -->
            <arg value="-z" /> <!-- Adds the zip archive content of the application package. -->
            <arg value="${package.resource}" />
            <arg value="-f" />	<!-- Adds the file to the application package. -->
            <arg value="${bin.classes.dex}" />
            <arg value="-rf" />
            <arg value="${src.dir}" /> <!-- Adds the java resources found in that folder to the application package -->
            <arg value="-nf" />
            <arg value="${lib.dir}" />
            <arg value="-rj" /> <!-- Adds the java resources found in the jar file(s) to the application package. -->
            <arg value="${lib.dir}" />
        </java>
        <echo> === build end == </echo>
    </target>
    
  • 加签名和优化apk文件

    <target name="jarsigner" depends="build">
        <echo> === jarsigner start == </echo>
        <exec executable="${java.tool.jarsigner}" failοnerrοr="true">
            <arg value="-keystore" />
            <arg value="${key.keystore}" />
            <arg value="-storepass" />
            <arg value="${key.keystore.storepass}" />
            <arg value="-keypass" />
            <arg value="${key.keystore.keypass}" />
            <arg value="-digestalg" />
            <arg value="SHA1" /> 
            <arg value="-sigalg" /> 
            <arg value="MD5withRSA" />
            <arg value="-signedjar" />
            <arg value="${project.signed.apk}" />
            <arg value="${project.unsigned.apk}" />
            <arg value="${key.keystore.alias}" />
        </exec>
        <delete file="${project.unsigned.apk}" />
        <echo> === jarsigner end == </echo>
    </target>
    
    <tstamp>
        <format property="now" pattern="yyyyMMdd-HHmmss" offset="0" unit="hour"/>
    </tstamp>
    <target name="zipalign" depends="jarsigner">
        <echo> === zipalign start == </echo>
        <exec executable="${sdk.build.tools.zipalign}">
            <arg value="-v" />
            <arg value="4" />
            <arg value="${project.signed.apk}" />
            <arg value="${ant.project.name}-${version.name}-${apk.mark}-${now}.apk" />
        </exec>
        <delete file="${project.signed.apk}" />
        <echo> === zipalign end == </echo>
    </target>
    

3. 多渠道打包

在AndroidManifest.xml文件中会有以下配置,来表明使用哪种渠道

<meta-data android:value="xx" android:name="UMENG_CHANNEL"/>

在打包时,可以替代value的值。设置变量channel.extension。

<property name="channel.extension" value="demo" />

在init中加入以下内容,

<replaceregexp flags="g" byline="true" encoding="UTF-8">
    <regexp pattern="android:value="(.*)" android:name="UMENG_CHANNEL"" />  
    <substitution expression="android:value="${channel.extension}" android:name="UMENG_CHANNEL"" />  
    <fileset dir="" includes="AndroidManifest.xml" />
</replaceregexp>

多渠道,使用foreach功能,需要添加ant-contrib.jar文件。

<condition property="ant.home" value="${env.ANT_HOME}">
    <isset property="env.ANT_HOME" />
</condition>
<property name="ant-contrib.jar" >
    <classpath>
        <pathelement location="${ant.home}/lib/ant-contrib-0.6.jar"/>
    </classpath>
</property>
<taskdef resource="net/sf/antcontrib/antcontrib.properties" classpath="${ant-contrib.jar}" />

<target name="channel">
    <propertyregex override="true" property="channel.extension" input="${channel.name}" regexp="(.*)" select="\1" />
    <antcall target="zipalign" />
</target>

<target name="multi.channel">
    <foreach list="TX,XM" target="channel" param="channel.name" delimiter="," />
</target>

参考文档: http://www.cnblogs.com/wujd/archive/2012/01/10/wujiandong-android-1.html
参考文档: http://blog.csdn.net/catoop/article/details/7614275

本文链接http://element-ui.cn/news/show-476.html