zoukankan      html  css  js  c++  java
  • Android ANT脚本打包及混淆文件

    http://p.ymt360.com/w/app/wiki/tech/build_apk/

    简介

    Android支持使用ANT打包。
    通过ANT脚本,可以对文件进行编译、打包、安装、联合SVN自动拉取等。
    并且支持多种方式打包,如debug、release、批量打包等场景。
    eclipse项目是通过调用SDK提供的ANT脚本build.xml文件进行打包的。

    附件是AndroidSDK附带的打包脚本,超详细,可以参考学习下。build.xml
    (建议使用JDK1.6环境,在之前ANT使用过程中被1.7环境坑过)

    使用建议

    Android studio 使用gradle 进行编译打包,
    gradle是google推荐的打包方式,如果以后开发环境切换到Android studio 建议使用gradle

    如果是在eclipse开发环境可以使用ANT或者gradle

    YMT APP开发时 Android studio是测试版本阶段,gradle学习资料较少,基于目前的目录结构,采用ANT进行打包。

    命令介绍

    Android打包流程先介绍下:
    1.用aapt命令生成R.java文件
    2.用aidl命令生成相应java文件
    3.用javac命令编译java源文件生成class文件
    4.用dx.bat将class文件转换成classes.dex文件
    5.用aapt命令生成资源包文件resources.ap_
    6.用apkbuilder.bat打包资源和classes.dex文件,生成unsigned.apk
    7.用jarsinger命令对apk认证,生成signed.apk

    配合我们项目介绍在YMT项目中使用ANT的流程

    1.clean清除temp文件
    2.初始化各种temp目录
    3.用aapt命令 打包项目的资源文件 生成R.java文件
    4.生成buildconfig类 主要用于在项目中调用 BuildConfig.Debug判断是否DebugAPK的代码
    5.用aidl命令生成相应java文件
    6.用javac命令编译java源文件生成class文件
    7.将class文件生成jar文件
    8.对打包后的结果进行混淆
    9.用dx.bat将class文件转换成classes.dex文件
    10.用apkbuilder.bat打包资源和classes.dex文件,生成unsigned.apk
    11.用jarsinger命令对apk认证,生成signed.apk
    12.zipalign,对混淆的签名包做优化

    脚本分析

    我们详细介绍每一个步骤所使用到的命令:

    打包过程不在代码基础上进行操作,全部在副本里面进行操作。

    1.清除temp文件,删除之前复制代码(包括依赖库代码)到的temp文件夹

    <target name="clean" >
    
            <echo>
    			Start clean...
    
            </echo>
    
            <mkdir dir="${apk}" />
    
            <delete dir="${temp}" />
    
            <delete dir="${ymtBaseApp-temp}" />
    
            <delete dir="${pulltofresh-project-temp}" />
            
            <delete dir="${datetimepicker-library-temp}" />
            
            <delete dir="${c3kDemo-lib-temp}" />
    
            <echo>
    			Finished clean...
    
            </echo>
    
            <echo>
            </echo>
        </target>
    1. 创建temp文件夹,复制依赖库文件,项目文件到temp文件夹中(src,gen,lib等)
    <target name="init" >
    
            <echo>
    			Start init...
    
            </echo>
    
            <echo>
    			If not exist, then create the directories...
    
            </echo>
    
            <mkdir dir="${apk}" />
    
            <mkdir dir="${temp}" />
    
            <mkdir dir="${ymtBaseApp-temp}" />
    
            <mkdir dir="${pulltofresh-project-temp}" />
    
            <mkdir dir="${datetimepicker-library-temp}" />
            
            <mkdir dir="${c3kDemo-lib-temp}" />
            
            <mkdir dir="${classes}" />
    
            <mkdir dir="${classes-obfs}" />
    
            <mkdir dir="${gen}" />
    
            <mkdir dir="${lib}" />
    
            <echo>
    			Copy files to temp directory...
    
            </echo>
    
            <copy
                filtering="true"
                todir="${temp}" >
    
                <fileset dir="${project_path}" >
    
                    <exclude name="**/.svn/*" />
    
                    <exclude name="**/temp/" />
    
                    <exclude name="**/temp2/" />
    
                    <exclude name="**/bin/" />
    
                    <exclude name="**/gen/" />
                </fileset>
            </copy>
    
            <echo>
    			Copy files of xxx android library project to temp2 directory...
    
            </echo>
    
            <copy
                filtering="true"
                todir="${ymtBaseApp-temp}" >
    
                <fileset dir="${ymtBaseApp}" >
    
                    <exclude name="**/.svn/*" />
    
                    <exclude name="**/bin/" />
    
                    <exclude name="**/gen/" />
                </fileset>
            </copy>
            
            <copy
                filtering="true"
                todir="${pulltofresh-project-temp}" >
    
                <fileset dir="${pulltofresh-project}" >
    
                    <exclude name="**/.svn/*" />
    
                    <exclude name="**/bin/" />
    
                    <exclude name="**/gen/" />
                </fileset>
            </copy>
    
            <copy
                filtering="true"
                todir="${c3kDemo-lib-temp}" >
    
                <fileset dir="${c3kDemo-lib}" >
    
                    <exclude name="**/.svn/*" />
    
                    <exclude name="**/bin/" />
    
                    <exclude name="**/gen/" />
                </fileset>
            </copy>
    
            <copy
                filtering="true"
                todir="${datetimepicker-library-temp}" >
    
                <fileset dir="${datetimepicker-lib}" >
    
                    <exclude name="**/.svn/*" />
    
                    <exclude name="**/bin/" />
    
                    <exclude name="**/gen/" />
                </fileset>
            </copy>
            
            <!-- copy All lib to lib folder -->
            <copy
                filtering="true"
                todir="${lib}" >
    
                <fileset dir="${ymtBaseApp}/libs" />
                
                <fileset dir="${c3kDemo-lib}/libs" />
                
                <fileset dir="${datetimepicker-lib}/libs" />
    
            </copy>
    
            <echo>
    				Finish init...
    
            </echo>
        </target>
    1. aapt(Android Asset Packaging Tool)命令,根据资源文件生成R.java文件

    参数说明:
    -f 强制覆盖已存在的文件。
    -m 在-J指定的位置下自动生成相应的包的目录。
    -J 指定R.java文件生成的目录。
    -S 指定资源目录。
    -M 指定清单文件。
    -I 引入类库。
    注意,我们当前所在的位置是ant项目根目录,所以必要时需要输入很多关于命令的路径,以下示例也是一样。

    <!-- 打包项目的资源文件 -->
    
        <target name="generate" >
    
            <echo>
    			Package res and assets...
    
            </echo>
    
            <exec
                executable="${aapt}"
                failonerror="true" >
    
                <arg value="package" />
    
                <arg value="-f" />
    
                <arg value="-m" />
    
                <arg value="-J" />
    
                <arg value="${gen}" />
    
                <arg value="-M" />
    
                <arg value="${temp}/AndroidManifest.xml" />
    
                <arg value="-S" />
    
                <arg value="${res}" />
    
                <arg value="-S" />
    
                <arg value="${ymtBaseApp-temp}/res" />
    
                <arg value="-S" />
    
                <arg value="${pulltofresh-project-temp}/res" />
    
                <arg value="-S" />
    
                <arg value="${datetimepicker-library-temp}/res" />
    
                <arg value="-S" />
    
                <arg value="${c3kDemo-lib-temp}/res" />
    
                <arg value="--extra-packages" />
    
                <arg value="com.ymt360.app:com.handmark.pulltorefresh.library:com.fourmob.datetimepicker:com.example.client" />
                
                <arg value="-A" />
    
                <arg value="${assets}" />
    
                <arg value="-I" />
    
                <arg value="${androidjar}" />
    
                <arg value="-F" />
    
                <arg value="${temp}/${file_name}.ap_" />
    
                <arg value="--auto-add-overlay" />
            </exec>
        </target>

    4.生成buildconfig类和依赖库的buildconfig类 很重要,关系到测试代码是否能在正式版本关闭。
    引入ant-tasks.jar 目的是为使用buildconfig命令

    if (BuildConfig.DEBUG) {
          do something;
    }
    <target name="buildconfig" >
    
            <echo level="info" >
    			Handling BuildConfig class...
    
            </echo>
    
            <!-- jar file from where the tasks are loaded -->
    
            <path id="android.antlibs" >
    
                <pathelement path="${android_home}/tools/lib/ant-tasks.jar" />
            </path>
    
            <!-- Custom tasks -->
    
            <taskdef
                classpathref="android.antlibs"
                resource="anttasks.properties" />
    
            <buildconfig
                buildType="${build.is.packaging.debug}"
                genFolder="${gen}"
                package="${project.app.package}"
                previousBuildType="${build.last.is.packaging.debug}" />
    
            <buildconfig
                buildType="${build.is.packaging.debug}"
                genFolder="${c3kDemo-lib-temp}/gen"
                package="com.example.client"
                previousBuildType="${build.last.is.packaging.debug}" />
        </target>
    1. aidl(Android Interface Definition Language)命令,根据.aidl定义文件生成java文件
    <target name="aidl" >
    
            <echo>
    Start compile aidl files to java classes...
    
            </echo>
    
            <apply
                executable="${aidl}"
                failonerror="true" >
    
                <arg value="-p${android_framework}" />
    
                <arg value="-I${src}" />
    
                <arg value="-o${gen}" />
    
                <fileset dir="${src}" >
    
                    <include name="**/*.aidl" />
                </fileset>
            </apply>
        </target>
    1. 编译项目和依赖包的.java文件 JDK版本使用的是1.6版本

    javac命令

    <!-- 编译项目的.java文件 -->
    
        <target name="compile" >
    
            <echo>
    			Start compile source code...
    
            </echo>
    
            <echo>
    			The debug param is default to true, for the exception upload feature required it...
    
            </echo>
    
            <javac
                bootclasspath="${androidjar}"
                debug="true"
                destdir="${classes}"
                encoding="${encoding}"
                extdirs=""
                target="1.6" >
    
                <src path="${pulltofresh-project-temp}/src" />
                
                <src path="${c3kDemo-lib-temp}/src" />
    
                <src path="${datetimepicker-library-temp}/src" />
    
                <src path="${ymtBaseApp-temp}/src" />
    
                <src path="${src}" />
    
                <src path="${gen}" />
    
                <src path="${c3kDemo-lib-temp}/gen" />
    
                <classpath>
    
                    <fileset
                        dir="${lib}"
                        includes="*.jar" />
                    
                </classpath>
            </javac>
        </target>
    1. 将class文件打包为jar
        <target
            name="package"
            if="${notObfuscated}" >
    
            <echo>
    Packing compile results...
    
            </echo>
    
            <jar
                basedir="${classes}"
                destfile="temp.jar" />
    
            <echo>
    Copy jar to test directory...
    
            </echo>
    
            <copy
                file="temp.jar"
                todir="${autotest}" />
        </target>
    1. 对打包后的结果进行混淆 并输出mapping文件

    注意:混淆参数需要根据项目实际情况进行调整

    <target
            name="obfuscate"
            if="${obfuscated}" >
    
            <echo>
    Obfuscating package...
    
            </echo>
    
            <java
                failonerror="true"
                fork="true"
                jar="${proguard_home}/lib/proguard.jar" >
    
                <jvmarg value="-Dmaximum.inlined.code.length=32" />
    
                <arg value="-injars temp.jar" />
    
                <arg value="-outjars obfuscated.jar" />
    
                <arg value="-libraryjars ${androidjar}" />
    
                <!-- 当混淆参数很多时,建议写在独立的proguard.cfg文件中,然后以下面方式来引用 -->
    
                <arg value="@${basedir}/proguard-project.txt" />
    
                <arg value="@${ymtBaseApp-temp}/proguard-project.txt" />
    
                <arg value="@${datetimepicker-library-temp}/proguard-project.txt" />
                
                <arg value="@${c3kDemo-lib-temp}/proguard-project.txt" />
    
                <arg value="-dontpreverify" />
    
                <arg value="-dontoptimize" />
    
                <arg value="-dontusemixedcaseclassnames" />
    
                <arg value="-repackageclasses &apos;&apos;" />
    
                <arg value="-allowaccessmodification" />
    
                <arg value="-verbose" />
                <!-- 打印混淆过程产生的中间信息,其中mapping用于反向解析异常信息 -->
                <!-- arg value="-dump ${apk}/dump.txt"/ -->
                <!-- arg value="-printusage ${apk}/usage.txt"/ -->
    
                <arg value="-printmapping ${apk}/mapping.txt" />
                <!-- arg value="-printseeds ${apk}/seeds.txt"/ -->
    
            </java>
    
            <delete file="temp.jar" />
    
            <unzip
                dest="${classes-obfs}"
                src="obfuscated.jar" />
    
            <delete file="obfuscated.jar" />
            
            <delete file="${project_path}/proguard/mapping.txt" />
            
            <copy
                file="${apk}/mapping.txt"
                todir="${project_path}/proguard" />
        </target>

    9.用dx.bat将class文件转换成classes.dex文件

    <target
            name="dex-obfs"
            if="${obfuscated}" >
    
            <echo>
    Coverting dex-obfs obfuscated class files to dex file...
    
            </echo>
    
            <apply
                executable="${dx}"
                failonerror="true"
                parallel="true" >
    
                <arg value="--dex" />
    
                <arg value="--output=${dex-obfs}" />
    
                <arg path="${classes-obfs}" />
    
                <fileset
                    dir="${lib}"
                    includes="*.jar" />
    
                </apply>
        </target>

    10.apkbuilder命令,根据classes.dex文件和resources.ap_生成为签证的apk包

    A command line tool to package an Android application from various sources.
    Usage: apkbuilder <out archive> [-v][-u][-storetype STORE_TYPE] [-z inputzip]
                [-f inputfile] [-rf input-folder] [-rj -input-path]
    参数说明:
    -u     Creates an unsigned package.
    -z     Followed by the path to a zip archive. Adds the content of the application package.
    -f      Followed by the path to a file. Adds the file to the application package.
    -rf     Followed by the path to a source folder. Adds the java resources found in that folder to the application package, while keeping their path relative to the source folder.
    -nf    Followed by the root folder containing native libraries to include in the application package.

    新版本的SDK中apkbuilder.bat移除 需要在
    sdkuild-toolsandroid-4.4 目录中添加apkbuilder.bat 附下载 apkbuilder.bat

    apkbuilder.bat中需要修改下面3处的环境的地址为自己电脑对应地址
    set java_exe=C:Program FilesJavajdk1.6.0_23injava.exe
    call "C:Program Filesadt-bundle-windows-x86_64-20131030sdk oolslibfind_java.bat"
    set jarpath=C:Program Filesadt-bundle-windows-x86_64-20131030sdk oolslib\%jarfile%

    <target
            name="release-obfs"
            if="${obfuscated}" >
    
            <echo>
    Build unsigned and obfuscated apk file from dex and resouse...
    
            </echo>
    
            <exec
                executable="${apkbuilder}"
                failonerror="true" >
    
                <arg value="${temp}/${file_name}_obfs.apk" />
    
                <arg value="-u" />
    
                <arg value="-z" />
    
                <arg value="${temp}/${file_name}.ap_" />
    
                <arg value="-f" />
    
                <arg value="${dex-obfs}" />
    
                <arg value="-rj" />
    
                <arg value="${lib}" />
                
                <arg value="-nf" />
    
                <arg value="${lib}" />
                
            </exec>
        </target>

    11.jarsigner命令,对上面生成的apk包进行签证

    <target
            name="sign-obfs"
            if="${obfuscated}" >
    
            <echo>
    Begin sign obfuscated package...
    
            </echo>
    
            <exec
                executable="${signer}"
                failonerror="true" >
    
                <arg value="-verbose" />
    
                <arg value="-keystore" />
    
                <arg value="${keystore}" />
    
                <arg value="-storepass" />
    
                <arg value="${store_pass}" />
    
                <arg value="-keypass" />
    
                <arg value="${key_pass}" />
    
                <arg value="-signedjar" />
    
                <arg value="${temp}/${file_name}_obfs_signed.apk" />
    
                <arg value="${temp}/${file_name}_obfs.apk" />
    
                <arg value="${key_name}" />
            </exec>
        </target>

    12.zipalign,对混淆的签名包做优化

        <target
            name="zipalign-obfs"
            if="${obfuscated}" >
    
            <echo>
    Start zipalign obfuscated package...
    
            </echo>
    
            <exec
                executable="${zipalign}"
                failonerror="true" >
    
                <arg value="-v" />
    
                <arg value="4" />
    
                <arg value="${temp}/${file_name}_obfs_signed.apk" />
    
                <arg value="${apk}/${nameprefix}_.apk" />
            </exec>
    
            <echo>
    End zipalign...
    
            </echo>
        </target>

    目录结构

    build_deploy.xml 入口执行文件
    build_option.xml 配置文件(目录配置等,根据不同环境,配置修改)
    build_common.xml 步骤执行文件(一般执行步骤不变不需要修改)
    proguard-project.txt 混淆配置文件

    输出APK目录位置

    <property
            name="apk"
            value="${project_path}/../${nameprefix}_apk" />

    APK 文件名

    <property
         name="nameprefix"
         value="ymt_mass_v4.0.0" />

    使用示例

    如果需要添加删除依赖包 需要修改如下步骤
    1.clean步骤删除对应文件
    2.init 步骤创建对应文件
    3.generate 步骤添加下图的代码 --extra-packages中用:冒号分开


    4.buildconfig中修改对应代码


    5.compile步骤中添加对应代码 如果java代码中需要用到R文件 需要指定对应的gen 如<src path="${c3kDemo-lib-temp}/gen" />


    6.混淆文件 建议写在独立的proguard.cfg文件中,然后以下面方式来引用

    参考资料

    参考资料:http://blog.csdn.net/liuhe688/article/details/6679879 等

    混淆文件

    新建Android项目后会自带一个混淆文件 按照里面的注释打开对应的混淆语句即可对工程进行混淆。
    eclipse打包 混淆文件开关位置在project.properties中proguard.config=proguard-project.txt语句 注释则不混淆。如果使用ANT打包 需要在对应的打包脚本中修改。

    添加类库
    -libraryjars libs/baidumapapi_v2_4_0.jar
    忽略警告
    -dontwarn org.apache.commons.httpclient.
    keep 代码不被混淆
    -keep class com.umeng.
    {*;}
    -keep public class * extends com.umeng.update.UmengDialogButtonListener
    -keep public class com.ymt360.app.mass.view.FlowLayout {

    public <fields>;
    public <methods>;

    }

    踩过的坑
    不要使用中文注释 会导致中文注释紧跟的下面一行被注释掉 不起作用,解决办法用英文注释。

    eclipse打包

    步骤
    1.注意 eclipse打包的时候要关闭自动编译勾选项,否则buildconfig文件会在打包前生成,导致BuildConfig.DEBUG为debug值。

    2.如图

    over

    欢迎完善

  • 相关阅读:
    201521123108 《Java程序设计》第八周学习总结
    201521123108 《Java程序设计》第7周学习总结
    201521123108 《Java程序设计》第6周学习总结
    201521123108 《Java程序设计》第5周学习总结
    201521123108 《Java程序设计》第4周学习总结
    201521123108《Java程序设计》第3周学习总结
    201521123107 《Java程序设计》第11周学习总结
    201521123107 《Java程序设计》第10周学习总结
    201521123107 《Java程序设计》第9周学习总结
    201521123107 《Java程序设计》第8周学习总结
  • 原文地址:https://www.cnblogs.com/sunzhuo1228/p/4411621.html
Copyright © 2011-2022 走看看