android工程利用ant,antenna和proguard预编译混淆打包的方法

闲来无事,开博第一篇,讲一下混淆打包的心得(高手请绕道)。
先申明:以下方案使用于windows系统,linux下要稍作调整,我不累述。
不废话,直接开始


一、准备工作
1、jdk1.6(这个最保险,之前用过8有问题,不知道现在如何)。
2、wtk2.5.2,我用这个,比较保险(预编译用,下载地址:http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-javame-419430.html#sun_java_wireless_toolkit-2.5.2_01b-oth-JPR)
3、proguard4.5,已经更新了好几个版本了,不过好用就不换了(下载地址:http://proguard.sourceforge.net/)。
4、ant工具,一般eclipse中自带(若没有,下载地址:http://ant.apache.org/bindownload.cgi,为了方便记得配置环境变量)。
5、antenna,女神你懂得~~,(下载地址:http://sourceforge.net/projects/antenna/)。


以上地址如果无法下载请自己上度娘


二、配置工作
新建build.env文件 (表示环境配置,我电脑配置如下,各位对号入座就行)。


# build environment, setup according to your computer
jdk.home=C:/Java/jdk1.6.0_10
jdk.bin=${jdk.home}/bin
wtk.home=C:/JavaME_SDK_CLDC/WTK2
android.sdk.home=C:/android_sdk/sdk
android.tools=${android.sdk.home}/tools
android.build-tools=${android.sdk.home}/build-tools/android-4.4.2
android.platform-tools=${android.sdk.home}/platform-tools
android.platform.home=${android.sdk.home}/platforms/${target}
android.version=2.0
proguard.home=D:/proguard4.5
proguard.jar=${proguard.home}/lib/proguard.jar
antenna.lib=d:/antenna-bin-1.2.1-beta.jar

特别提示一下
android.platform.home=${android.sdk.home}/platforms/${target}
以上配置中的target为android的api版本,比如android2.1为android-7,android4.3为android-18

新建build.property文件 (和工程相关的配置,各不相同,按照自己的工程目录配置)
# project properties
build.src.main=src/main
build.src.test=src/test/java
build.src.encoding=UTF-8
build.version.name=1.0.0.0

新建config-default.properties文件 (代码中需要预编译变量常量的默认值)
# default build config, can be overrided by defining new build target in build.xml
sdk.debug.level=none
sdk.channelid=tecent
sdk.author=vailen
sdk.jarname.main=CsdnSdk${build.version.name}.jar

project.properties
这个文件应该是创建android工程的时候自动生成的,内如如下:
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "ant.properties", and override values to adapt the script to your
# project structure.


# Project target.
target=android-7


该配置中的target就是之前build.env文件中${target}的取值。


三、脚本编写

新建build.xml文件,编写ant相关代码,这边贴出我电脑上的例子

<?xml version="1.0" encoding="UTF-8"?>
<project name="your project name" basedir="../">
<target name="prj.define" description="系统变量定义">
<echo message="Project Define variables" />
<property name="build-dir" value="build" />

<!-- load build config -->
<property file="project.properties" />
<property file="${build-dir}/build.env" />
<property file="${build-dir}/build.properties" />
<property file="${build-dir}/config-default.properties" />


<echo>building ver:${build.version.name},timestamp:${build.version.timestamp}</echo>

<!-- load antenna task def -->
<taskdef resource="antenna.properties">
<classpath location="${antenna.lib}" />
</taskdef>

<!-- Android Environment -->
<property name="android-jar" value="${android.platform.home}/android.jar" />
<property name="android-framework" value="${android.platform.home}/framework.aidl" />

<property name="library-jar" value="libs" />

<!-- project directory definitions -->
<property name="resource-dir" value="res" />
<property name="asset-dir" value="assets" />
<property name="external-libs" value="libs" />
<property name="outdir" value="${build-dir}/output" />
<property name="outdir-src" value="${outdir}/src" />
<property name="outdir-preprocess" value="${outdir}/preprocess" />
<property name="outdir-classes" value="${outdir}/classes" />
<property name="outdir-classes-optimized" value="${outdir}/optimized-classes" />
<property name="outdir-main" value="${outdir}/main" />

<property name="outfile-proguardmap" value="${outdir}/CsdnSdk${build.version.name}_proguard.map" />

<condition property="srcdir-ospath" value="${basedir}\${outdir-src}" else="${basedir}/${outdir-src}">
<os family="windows" />
</condition>
<condition property="external-libs-ospath" value="${basedir}\${external-libs}" else="${basedir}/${external-libs}">
<os family="windows" />
</condition>
<condition property="outdir-classes-ospath" value="${basedir}\${outdir-classes}" else="${basedir}/${outdir-classes}">
<os family="windows" />
</condition>

<!-- Tools -->
<condition property="aapt" value="${android.build-tools}/aapt.exe" else="${android.build-tools}/aapt">
<os family="windows" />
</condition>
<condition property="zipalign" value="${android.tools}/zipalign.exe" else="${android.tools}/zipalign">
<os family="windows" />
</condition>
<condition property="jarsigner" value="${jdk.bin}/jarsigner.exe" else="${jdk.bin}/jarsigner">
<os family="windows" />
</condition>
<condition property="aidl" value="${android.build-tools}/aidl.exe" else="${android.build-tools}/aidl">
<os family="windows" />
</condition>
<condition property="adb" value="${android.platform-tools}/adb.exe" else="${android.platform-tools}/adb">
<os family="windows" />
</condition>
<condition property="dx" value="${android.build-tools}/dx.bat" else="${android.build-tools}/dx">
<os family="windows" />
</condition>
<condition property="apk-builder" value="${android.tools}/apkbuilder.bat" else="${android.tools}/apkbuilder">
<os family="windows" />
</condition>
</target>

<target name="clean" depends="prj.define">
<echo message="Clean directories" />
<delete dir="${outdir-src}" />
<delete dir="${outdir-preprocess}" />
<delete dir="${outdir-classes}" />
<delete dir="${outdir-classes-optimized}" />
<delete dir="${outdir-main}" />
</target>


<target name="dirs" depends="clean">
<echo message="Create directories" />
<mkdir dir="${outdir}" />
<mkdir dir="${outdir-src}" />
<mkdir dir="${outdir-preprocess}" />
<mkdir dir="${outdir-classes}" />
<mkdir dir="${outdir-classes-optimized}" />
<mkdir dir="${outdir-main}" />
</target>


<target name="copysrc-main" depends="dirs">
<echo message="Copying main source code" />
<copy todir="${outdir-src}">
<fileset dir="${build.src.main}">
<include name="**" />
</fileset>
</copy>
</target>


<target name="preprocess" depends="dirs">
<echo message="Preprocessing..." />
<wtkpreprocess srcdir="${outdir-src}" destdir="${outdir-preprocess}" debuglevel="${sdk.debug.level}" encoding="${build.src.encoding}" printsymbols="true" symbols=" SDK_VERSION='${build.version.name}',SDK_CHANNEL_ID='${sdk.channelid}',SDK_AUHTOR='${sdk.author}'" verbose="false">
<symbols_file name="${outdir}/ant.symbols" />
</wtkpreprocess>

<!-- copy all aidl files -->
<copy todir="${outdir-preprocess}">
<fileset dir="${outdir-src}">
<include name="**/*.aidl" />
</fileset>
</copy >
</target>

<!-- Generate java classes from .aidl files. -->
<target name="aidl" depends="preprocess">
<echo>Compiling aidl files into Java classes...</echo>
<apply executable="${aidl}" failοnerrοr="true">
<arg value="-p${android-framework}" />
<arg value="-I${outdir-preprocess}" />
<fileset dir="${outdir-preprocess}">
<include name="**/*.aidl" />
</fileset>
</apply>
</target>

<!-- Compile this project's .java files into .class files. -->
<target name="compile" depends="preprocess, aidl">
<javac encoding="${build.src.encoding}" target="1.6" debug="true" extdirs="" srcdir="${outdir-preprocess}" destdir="${outdir-classes}" bootclasspath="${android-jar}" includeantruntime="on">
<compilerarg value="-Xlint:unchecked" />
<classpath>
<fileset dir="${external-libs}" includes="*.jar" />
</classpath>
</javac>
</target>

<!-- Optimize and Obfuscate the code -->
<target name="optimize" depends="compile">
<echo>Proguarding the code...</echo>
<jar basedir="${outdir-classes}" destfile="temp.jar" />
<java jar="${proguard.jar}" fork="true" failοnerrοr="true">
<jvmarg value="-Dmaximum.inlined.code.length=32" />
<arg value="-injars temp.jar" />
<!-- 如果你需要把第三方包download.jar打包进来,可以通过injars来实现-->
<arg value="-injars ${library-jar}/download.jar" />
<arg value="-outjars optimized.jar" />
<arg value="-libraryjars ${android-jar}" />
<arg value="-dontoptimize" />
<arg value="-dontusemixedcaseclassnames" />
<!--<arg value="-repackageclasses" />-->
<arg value="-allowaccessmodification" />

<!-- 需要的不混淆类 -->
<arg value="-keeppackagenames com.csdn" />

<!-- 主包相关 -->
<arg value="-keeppackagenames com.csdn.sdk" />
<arg value="-keep public class com.csdn.sdk.* { public *;}" />
<arg value="-keep public interface com.csdn.sdk.aidl.* { public *;}" />

<!-- android相关控件不能混淆啊,好吧,被你打败了android-->
<arg value="-keep public class * extends android.app.Activity"/>
        <arg value="-keep public class * extends android.app.Application"/>
        <arg value="-keep public class * extends android.app.Service" />
<arg value="-keep public class * extends android.content.ContentProvider"/>
<arg value="-keep public class * extends android.view.View"/>
<arg value="-keep public class * extends android.preference.Preference"/>   
        <arg value="-keep public class * extends android.content.BroadcastReceiver" />
        <arg value="-keep public class * extends android.os.IInterface" />

<arg value="-optimizationpasses 5" />
<!-- <arg value="-verbose" /> -->
<arg value="-dontskipnonpubliclibraryclasses" />
<arg value="-dontskipnonpubliclibraryclassmembers" />
<arg value="-dontpreverify" />
<arg value="-printmapping ${outfile-proguardmap}" />
</java>

<mkdir dir="${outdir-classes-optimized}/${asset-dir}" />
<copy todir="${outdir-classes-optimized}/${asset-dir}">
<fileset dir="assets">
<include name="*.cfg" />
</fileset>
</copy>
<delete file="temp.jar" />
<unzip src="optimized.jar" dest="${outdir-classes-optimized}" />
<delete file="optimized.jar" />
</target>

<!-- make jar package -->
<target name="jar" depends="copysrc-main,optimize">
<copy todir="${outdir-main}">
<fileset dir="${outdir-classes-optimized}">
<include name="**/*.class" />
<include name="**/*.cfg" />
</fileset>
</copy>

<echo>Making ${sdk.jarname.main}...</echo>
<jar destfile="${outdir}/${sdk.jarname.main}" basedir="${outdir-main}" />
</target>

<target name="build-all-release" depends="jar">
<echo>core and extension are built</echo>
</target>

<target name="open-build-release" depends="" description="现网正式发布版本">
<antcall target="build-all-release">
</antcall>
</target>

<target name="open-build-debug" depends="" description="带log日志版本">
<antcall target="build-all-release">
<param name="sdk.debug.level" value="debug" />
<param name="sdk.channelid" value="wandoujia" />
<param name="sdk.author" value="lilei" />
</antcall>
</target>
</project>


好吧,我承认我写多了,但是我真是懒得去最简化,有些执行通不过,无关的东西请删除,勉强看吧!各位sorry~~~

ant脚本我就不多说了,上文中所有关于csdn相关的包名或者文件名都是我随便写写的,各自替换就行。
build.xml中有很多个任务,两种性质的,一种是定义,一种是执行
prj.define任务定义了所有依赖的环境,需要定义的变量。
剩下的所有任务都是执行一定命令。

执行命令过程中,最终分解为预编译,混淆,打包三步,分别对应preprocess、optimize和jar三个任务,下面分别解释一下。
1、预编译
下面是一个我定义的Consts.java文件:

public class Consts{
// #expand public static final String sdk_conf_channelid = "%SDK_CHANNEL_ID%";
public static final String sdk_conf_channelid = "tencent";

// #expand public static final String sdk_author = "%SDK_AUHTOR%";
public static final String sdk_author = "vailen";

public static boolean isDebug() {
boolean isDebug = false;
// #debug
isDebug = true;

return isDebug;
}
}


找了半天,找不到Antenna官网文档,好久没关注,可能已经更新换代了。
以下地址勉强替代一下,汗~~!!
http://wenku.baidu.com/link?url=-MIph4LN_Sp0ZWO_4eoMaj0wotmawLlKCOfn8WDnPKw2Ind8JJ9uE1j9uZM96Fe0vcrd-ocA1ng2gN9feq8Wvdi1br7YOavbAFDr5d3Ow-O

预编译的语法就参考以上网址中的注释
// #debug
isDebug = true;

以上两句代码,如果是debug模式编译,"isDebug = true;"这一行会保留,否则两行会消失。debug模式下调用Consts.isDebug()就会返回true;否则返回false。
// #expand LINE WITH MACROS 相当于宏定义

举例说明,执行ant open-build-debug命令后
预编译产生的Consts.java中
// #expand public static final String sdk_conf_channelid = "%SDK_CHANNEL_ID%";
public static final String sdk_conf_channelid = "tencent";
将被替换为
// #expand public static final String sdk_conf_channelid = "%SDK_CHANNEL_ID%";
public static final String sdk_conf_channelid = "wandoujia";

当然
// #expand public static final String sdk_author = "%SDK_AUHTOR%";
public static final String sdk_author = "vailen";
就被替换为
// #expand public static final String sdk_author = "%SDK_AUHTOR%";
public static final String sdk_author = "lilei";

(呜呜~~我木有抢hanmeimei,lilei你为啥要抢我的著作权~~~开个玩笑!)

除了上面两个常用的预编译命令外,还有块注释,条件编译等多个命令,各位参考上面地址慢慢磨一下。

2、混淆
地球人都知道,有种手段叫做反编译,它会轻易得窃取你的胜利果实,为了让偷窃者不那么容易得手,引入混淆功能,类似于做了次代码加密,当然对于真正的高手,汇编都给你破了,就当防小毛贼吧。

言归正传,重点关注一下optimize任务,不难发现,先把你的.class文件打成一个temp.jar的包,然后把temp.jar包通过-injars方式当参数传入,然后配置一些混淆打包的其他参数,比如要不要预校验,
要不要压缩,要不要优化输入的类文件,要不要保留包名,要不要保留类名字,方法名称等等,不一一举例。

根据传入的参数,最后内部通过全局重命名替换一些类名,方法名,变量名,从而生成一个个不太容易看懂的class文件,什么a.class,al.class,达到减少包体量,让反编译的人看着蛋疼的目的。
具体的参数解释起来太麻烦了,请各位参考http://proguard.sourceforge.net/页面,Manual目录下的Examples子页一项项对照。

3、打包
说了半天,执行ant open-build-debug命令后,生成了个***.jar包,好像不是我们要的***.apk哦,做中间件久了,已经很久没看到界面了,补上打apk任务:
在project元素中加入以下任务
<target name="dex" depends="optimize">
<echo>Converting compiled files and external libraries into ${outdir}/${dex-file}...</echo>
<apply executable="${dx}" failοnerrοr="true" parallel="true">
<arg value="--dex" />
<arg value="--output=${intermediate-dex-ospath}" />
<arg path="${outdir-classes-optimized}" />
<fileset dir="${asset-dir}" includes="*.jar" />
</apply>
</target>

<target name="release" depends="dex, package-res">
<echo>Packaging ${out-unsigned-package} for release...</echo>
<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="-rj" />
<arg value="${external-libs-ospath}" />
<arg value="-nf" />
<arg value="${external-libs-ospath}" />
</exec>
<echo>It will need to be signed with jarsigner before being published.</echo>
</target>

<!--进行签名-->
<target name="jarsigner" depends="release">
<echo>sign package and compile ......</echo>
<exec executable="${jarsigner}" failοnerrοr="true">
<arg value="-verbose" />
<arg value="-storepass" />
<arg value="${password}" />
<arg value="-keystore" />
<arg value="${keystore}" />
<arg value="-signedjar" />
<arg value="${out-signed-package-ospath}" />
<arg value="${out-unsigned-package-ospath}" />
<arg value="${key.name}" />
</exec>
</target>
<!--进行优化-->
<target name="zipalign" depends="jarsigner">
<exec executable="${zipalign}" failοnerrοr="true">
<arg value="-v" />
<arg value="-f" />
<arg value="4" />
<arg value="${out-signed-package-ospath}" />
<arg value="${zipalign-package-ospath}" />
</exec>
</target>


dex任务,会将所有的class文件和.jar文件打包称为class.dex压缩包,有兴趣的同学可以通过dex2jar工具反编译class.dex文件,有助于理解。
release任务,通过执行apk-builder,把所有的class.dex和resource资源等打包成为apk文件。
注意:在android4.0以后(3.0是pad上的,很少用,不知道是不是3.0开始),apk-builder找不到,不过木有关系,apk-builder的真是身份其实是一个批处理文件,那么拿出里面内容重新写一下,照样可行,脚本如下:
<java classpath="${android.tools}/lib/sdklib.jar" classname="com.android.sdklib.build.ApkBuilderMain">  
            <arg value="${path.build.main}/bin/unsigned.apk" />  
            <arg value="-u" />  
            <arg value="-z" />  
            <arg value="${path.build.main}/bin/res.zip" />  
            <arg value="-f" />  
            <arg value="${path.build.main}/bin/classes.dex" />  
            <arg value="-rf" />    
            <arg value="${path.build.main}/src" />   
            <arg value="-rj"/>  
            <arg value="${path.build.main}/libs"/>   
            <arg value="-nf"/>  
            <arg value="${path.build.native}"
</java>

jarsigner任务,顾名思义,签名
<arg value="-storepass" /> 证书密码
<arg value="-keystore" /> 证书地址
<arg value="${key.name}" /> 证书名称

证书制作参考这位老兄的博客http://blog.csdn.net/androidzhaoxiaogang/article/details/10972441

zipalign任务,总的来说是用来优化apk的执行效率
zipalign使用了4字节的边界对齐方式来影射内存,通过空间换时间的方式提高执行效率。

好了,三更半夜了,可能很多地方写得不清晰,大家拍砖。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值