第三篇 提高篇—大胆曹贼,我跟你拼啦!第21回 反编译比较符合我的性格!

来源:互联网 发布:玲珑醉梦网络剧百度云 编辑:程序博客网 时间:2024/06/05 00:18

话说刘关张三人骑着赤兔马,走呀走,走呀走,好不容易走回了卧龙岗。一进门,只见卧龙气喘吁吁地跑出来,“你们可算回来了!”

刘备:“军师何事如此慌张,难道说厕所没手纸了吗?”

孔明:“别扯那没用的,出大事啦!你们还记的曹操不?”

刘备:“废话,我被灭成灰也忘不了他!”

关羽:“大哥,此话不是这么讲的吧……”

孔明:“那曹贼趁你们三人不在之时,通过反编译你们之前做的项目,改一改就放到网上去了,倒成了他的产品了!”

刘备:“那还有没有王法了?难道这种事献帝不管的吗?”

孔明:“献帝只管平时打打酱油喝喝茶,这种事如何能管?”

刘备:“那军师有何妙计?”

孔明:“唉……为今之计,只有认了。”

张飞:“这算哪门子妙计,我找他们拼命去!”

关羽一把拉住张飞,“三弟,先等大哥做决定吧。”

刘备:“孔明,这反编译是什么东西,没有什么防范措施吗?”

孔明:“之前我没跟你们讲反编译,是因为觉得用不到,做出来的产品还没有到达值得别人抄袭的地步。现在你们技术成长了,做出来的东西有价值了,自然会有小人打你们源码的主意。不过这从另一个方面说明你们确实上升了一个台阶。现在看来是时候好好教授你们怎么防范反编译了。”

刘备:“嘿嘿,军师,要不先教教我们怎么反编译吧,纯粹是处于学术上的考虑哈,没什么其他歪念~”

孔明:“我就知道你会这么说。好吧,其实这种反编译这种事情,我也是经常干的……”

1.1. 反编译详解

许多人常常认为反编译是盗取别人的代码。但其实反编译不仅可以开阔自己的视野,汉化外国软件和去除广告,而且可以限制应用程序的权限,增加软件的安全性。例如很多软件,申请了一些可能会导致付费(如:发短信、呼叫号码)或者泄漏隐私(如:读取通讯录)的权限。

本节将介绍如何对Android应用程序进行反编译。通过反编译,不仅可以学习别人的代码,而且会对Android应用程序的构成有更深层次的了解。下面首先介绍一些常见的反编译工具。

1.1.1.反编译工具介绍

jd-gui工具

jd-gui工具是一个用C++开发的Java反编译工具,由PavelKouznetsov开发,支持Windows、Linux和苹果Mac三个平台。jd-gui工具还提供了Eclipse平台下的插件JD-Eclipse。JD-Eclipse实现了Eclipse的高亮着色,多文件标签浏览的功能。jd-gui工具运行界面如图21-1所示:

图21-1 jd-gui运行界面

 

jad反编译器

jad是非常出色的免费Java字节码反编译器,提供了大量的命令行选项。基本用法:Usage:jad[option(s)],可直接输入类文件名,支持通配符。下面给出一个直接使用命令行批量反编译整个目录的例子:jad-o -r –s java -d src bin/**/*.class。src:反编译的目录;bin:将bin里面所有的“.class”文件反编译到src目录下。下面介绍jad命令行选择的列表:

l  -a:用JVM字节格式来注解输出。

l  -af:同-a,但是注解的时候用全名称。

l  -clear:清除所有的前缀。

l  -b:输出多余的括号。

l  -d:指定输出文件的文件目录。

l  -dead:试图反编译代码的dead 部分。

l  -disass:不用字节码的方式反编译。

l  -f:无论是类还是方法,输出其整个的名字。

l  -ff:在方法之前输出类的成员。

l  -i:输出所有变量的缺省最初值。

l  -l:将strings分割成指定数目的块字符。

l  -lnc:将输出文件用行号来注解。

l  -nl:用新一行字符分割strings。

l  -nodos:不去检查class文件是否以dos方式写。

l  -nocast:不生成辅助文件。

l  -nocode:不生成方法的源代码。

l  -noconv:不转换Java的定义符。

l  -noctor:不允许空的构造器存在。

l  -noinner:关掉对内部类的支持。

l  -nolvt:忽略局部变量的信息。

l  -nonlb:在打开一个括号之前不输出一个新行。

l  -o:无需确认直接覆盖输出。

l  -p:发送反编译代码到标准输出STDOUT。

 

dex2jar工具

Android应用会将Java代码编译成class.dex。dex2jar是一个用来将Android的Dalvik Executable(.dex)格式的文件转化成 Java 类文件的工具。jd-gui和jad都是对“.class”文件的反编译,所以它们常常需要配合起来一起使用。首先将apk中的classes.dex转化成jar文件,再用“.class”文件的反编译工具,直接查看jar包的源代码。常用方法是在命令行下定位到dex2jar.bat所在目录,运行“dex2jar.bat classes.dex”命令,生成classes.dex.dex2jar.jar文件,如图21-2所示:

图21-2dex2jar反编译结果

 

Android apktool工具包

Android apktool是一个第三方的工具包,用来从Android的apk安装程序中提取各种资源,生成程序的源代码、图片、xml配置和语言资源等文件。通过修改图片和资源文件,重新编译打包,签名apk,可以生成本地化/修正版的apk。

 

AXMLPrinter2工具

直接打开apk压缩包中的xml文件往往看见一堆乱码,AXMLPrinter2可以方便的把apk中已经序列化的xml还原为文本格式。

 

Gapktool工具

Gapktool是一个强大的apk反编译工具,集成了 jd-gui、jad、dex2jar、apktool,默认使用jad反编译。Gapktool运行界面如图21-3所示:

图21-3 Gapktool反编译

1.1.2.反编译实战

本节通过对一个带有广告的HelloWorld.apk进行反编译、去除广告、重新打包,演示如何进行反编译。首先建立HelloWorld工程,添加广告,HelloWorld工程的结构目录和运行结果如图21-4所示:

图21-4结构目录和运行结果图

然后下载两个工具dex2jar、jd-gui用于反编译Java源代码。首先将apk文件后缀改为zip,解压得到通过dx工具打包的class.dex文件;接着,将class.dex复制到dex2jar.bat所在目录下,在命令行下输入命令:dex2jar.bat classes.dex,生成jar文件,如图21-5所示:

图21-5 dex2jar反编译命令示意图

运行jd-gui,打开上面生成的jar文件,看到源代码如图21-6所示:

图21-6 jd-gui反编译代码

对比HelloWorld.java源代码,可见看出,已经实现了反编译apk的大部分逻辑代码。

public class HelloWorld extendsActivity {

    @Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

       setContentView(R.layout.main);

    }

}

下面通过反编译xml文件去除图21-4的广告。首先下载apktool工具:apktool1.4.1.tar.bz2 和 apktool-install-windows-r04-brut1.tar.bz2;接着将下载的两个包解压得到:aapt.exe、apktool.bat和apktool.jar;然后在命令行下定位到apktool.bat目录下,输入命令“apktool d C:\*.apk C:\*文件夹”,命令行解释:apktool d [apk文件路径] [输出文件夹路径],结果如图21-7所示:

图21-7 apktool反编译代码

修改HelloWorld工程的AndroidManifest.xml文件和main.xml文件,将广告权限和广告的代码移除,代码如下所示:

AndroidManifest.xml代码清单23-1-2:

<!—刘备:有困难要帮,没有困难制造困难也要帮!-->

<?xml version="1.0"encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.firstpeople.apk"

   android:versionCode="1"

   android:versionName="1.0">

<application

       android:icon="@drawable/ic_launcher"

       android:label="@string/app_name">

<activity android:name="com.firstpeople.apk.HelloWorld"

           android:theme="@android:style/Theme.NoTitleBar"

           android:windowSoftInputMode="adjustPan"

           android:screenOrientation="portrait">

<intent-filter>

<action android:name="android.intent.action.MAIN"/>

<category android:name="android.intent.category.LAUNCHER"/>

</intent-filter>

</activity>

                      <meta-data android:value="56OJyM1ouMGoaSnvCK"android:name="DOMOB_PID"/>

</application>

<!--修改去除广告权限  -->

           <uses-permissionandroid:name="android.permission.INTERNET"/>

           <uses-permissionandroid:name="android.permission.ACCESS_NETWORK_STATE"/>

           <uses-permissionandroid:name="android.permission.READ_PHONE_STATE"/>

           <uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

           <uses-permissionandroid:name="android.permission.ACCESS_COARSE_LOCATION"/>

<uses-sdk android:minSdkVersion="8" />

</manifest>

main.xml代码清单23-1:

<?xml version="1.0"encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:orientation="vertical">

<TextView

      android:layout_width="fill_parent"

   android:layout_height="wrap_content"

    android:text="@string/hello" />

<!-- 广告位置,去除 -->

<cn.domob.android.ads.DomobAdView

           android:id="@+id/domobAdXML"

android:layout_width="fill_parent"

           android:layout_height="wrap_content"/>

</LinearLayout>

在命令行中输入“apktool b c:\***文件夹”命令将修改后的文件重新打包成apk,如下图21-8所示:

图21-8 apktool打包命令

打开目录“C:\HelloWorld”文件夹,可以发现生成了两个文件夹:build和dist。其中,打包生成的新HelloWorld.apk,在dist文件夹下,重新装载apk,发现广告已经移除。

1.2. 防范apk被反编译

有攻就有防!由于软件的商业价值,一些人,会反编译apk的代码,重新编译,发布到应用商店,赚取利益。对于涉及到商业价值的软件,有时做适当的混淆、加密,也是为了保护自身的权利。本节将重点介绍如何防止自己的apk被反编译。

1.2.1. 防止被反编译工具

Jocky混淆编译器

Jocky是一款优秀的Java混淆编译器。一般而言,现有的混淆器都是对编译好的“.class”文件进行混淆,需要编译和混淆两个步骤。而Jocky是直接对源码进行混淆,避免了程序较大时,复杂的配置工作。Jocky混淆编译器是在JDK提供的Java编译器(javac)的基础上完成的,修改其中的代码生成过程,对编译器生成的中间代码进行混淆,最后生成“.class”文件。这样使得编译和混淆只需要一个步骤就可以完成。

不仅可以使用命令行,也可以通过Jocky提供了Eclipse的插件直接在Eclipse中使用Jocky。命令行使用Jocky,只需要获得jocky.jar后,运行“java -jar jocky.jar”命令就可以启动Jocky混淆编译器。Jocky的命令行参数和javac基本相同,但增加了一个新的参数-scramble,它的用法如下:

l  -scramble:混淆所有package、private和private符号。

l  -scramble all:混淆所有符号。

l  -scramble:<level>:混淆相应级别的符号,其中<level>指定混淆级别。

l  -scramble:none:不进行混淆。

l  -scramble:private:对所有private访问级别的元素进行混淆。

l  -scramble:package:对所有private或package private元素进行混淆。

l  -scramble:protected:对所有private、package private、protected元素进行混淆。

l  -scramble:public:对所有的元素都进行混淆。

l  -scramble:all:相当于-scramble:public。

l  -scramble:不带级别参数,则相当于-scramble:package。 

在Eclipse中安装Jocky,只需要将eclipse/plugins/org.apusic.jocky_1.0.0目录复制至Eclipse的plugins目录下即可。或者在Eclipse/links文件夹中,通过link方式指定Jocky的插件目录。在Eclipse中使用Jocky,只需点中Java工程,点击Jocky,就可以出现Jocky的快捷菜单,如图21-9所示:

图21-9Jocky

proguard混淆源码

为了很好的保护Java源代码,往往会对编译好的“.class”文件进行混淆处理。Google从Android SDK 2.3版本开始,在“android-sdk-windows\tools\”目录下增加了一个proguard文件夹。proguard是一个Java类文件的瘦身器、优化器、混淆器和预校验器。瘦身器用于删除没有使用的类、属性、方法和变量;优化器用于分析和优化方法的字节码;混淆器使用短而无意义的名字重命名类、变量和方法名。这使得工程代码更小、更有效并且更难以实现逆向工程。打开android-sdk-windows\tools\lib\proguard.cfg文件,可以看到如下脚本:

-optimizationpasses 5  //设置混淆的压缩比率 0 ~ 7

-dontusemixedcaseclassnames //颠倒名字

-dontskipnonpubliclibraryclasses//如果应用程序引入的有jar包,并且想混淆jar包里面的class

-dontpreverify

-verbose//混淆后生产映射文件 map 类名,转化后类名的映射

-optimizations!code/simplification/arithmetic,!field/*,!class/merging/*//混淆采用的算法.

 

-keep public class * extendsandroid.app.Activity//所有activity的子类不要去混淆

-keep public class * extendsandroid.app.Application 

-keep public class * extendsandroid.app.Service

-keep public class * extendsandroid.content.BroadcastReceiver

-keep public class * extendsandroid.content.ContentProvider

-keep public class * extendsandroid.app.backup.BackupAgentHelper

-keep public class * extendsandroid.preference.Preference

-keep public classcom.android.vending.licensing.ILicensingService

 

-keep classes withmembernames class *{

   native <methods>;//所有native的方法不能去混淆.

}

-keep classeswithmembers class * {

   public <init>(android.content.Context,android.util.AttributeSet);//某些构造方法不能去混淆

}

-keepclasseswithmembers class * {

   public <init>(android.content.Context, android.util.AttributeSet,int);

}

-keepclassmembers class * extendsandroid.app.Activity {

  public void *(android.view.View);

}

-keepclassmembers enum * { //枚举类不能去混淆.

   public static **[] values();

   public static ** valueOf(java.lang.String);

}

-keep class * implementsandroid.os.Parcelable { //aidl文件不能去混淆.

 public static final android.os.Parcelable$Creator *;

}

该脚本主要保留了继承自Activity、Application、Service、BroadcastReceiver、ContentProvider、BackupAgentHelper、Preference和ILicensingService的子类不被混淆。因为这些子类,都是可能被外部调用的。另外,它还保留了含有native方法的类、从xml构造的类、枚举类型中的values和valueOf静态方法、继承Parcelable的跨进程数据类。

孔明:在实际的工程项目中,可以直接使用Google自动生成的配置进行混淆工作。也可以根据自己的需求编写一些proguard配置。如果需要修改 proguard混淆脚本可以查看SDK安装目录下的\docs\guide\developing\tools\proguard.html说明。

 

 

 


1.2.2.反编译实战

现在在Eclipse中新建一个项目,一般都会包含proguard.cfg文件。一般大多数情况下,不需要更改这个混淆脚本文件。下面就针对HelloWorld工程进行混淆。

首先在HelloWorld.java里增加一些多余代码,以便观察混淆后的效果。代码如下所示:

public class Test {

    String info ="this is a test!";

    // 调用的方法

public void infoPrint() {

       Log.i("Test", "info");

    }

    // 多余的方法

public void infoPrint2() {

    }

}

public class HelloWorld extendsActivity {

    @Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

       setContentView(R.layout.main);

        // 测试混淆

        Test mTest= new Test();

       mTest.infoPrint();

    }

}

然后在工程文件project.properties中加入“proguard.config=proguard.cfg”。HelloWorld编译后,导出apk,反编译,可以看到如图21-10中所示代码:

图21-10反编译结果

从图21-10可以看出,有用的类Test名字变成了a,多余的方法infoPrint2()不见了,infoPrint()方法的内容直接写入到Activity里。同时,在工程目录下生成了proguard/dump.txt、proguard/ mapping.txt、proguard/seeds.txt、proguard/ usage.txt四个文件,它们具体的功能如下:

l  dump.txt:描述“.apk”包中所有“.class”文件的内部结构。

l  mapping.txt:列出了源代码与混淆后的类、方法和属性名字之间的映射。该文件可以把混淆的堆栈跟踪信息反翻译为源代码中的类、方法和成员名字,因此它可以用于分析构建之后得到的bug报告。

l  seeds.txt:列出未混淆的类和成员。

l  usage.txt:列出从“.apk”中剥离的代码。

孔明:保存好每一个已发布给用户的程序的mapping.txt文件很重要。通过保存发布构建版本的mapping.txt文件,可以确保当用户碰到bug时,能够提交混淆后的堆栈调试跟踪信息,从而修复bug

 

 

 


1.3. Ant编译打包

Ant是一种基于Java的build工具,它类似于(Unix)C中的make。当项目较大时,每次重新编译、打包、测试等都会变得非常复杂而且重复,因此C语言提供了make脚本来批量完成这些工作。由于Java应用是平台无关的,所以不会用平台相关的make脚本来完成这些批处理任务了。Ant是一个流程脚本引擎,用于自动完成项目的编译、打包、测试。在Android工程里,可以使用Ant来编译工程、打包工程、测试工程、将工程直接安装到手机或模拟器中。

使用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。

为了更好的理解Ant编译Android工程,必须首先熟悉步骤所使用到各命令。

 

aapt(Android Asset Packaging Tool)命令

aapt命令可以根据资源文件自动生成R.java文件,该命令主要有如下参数:

l  -f:强制覆盖已存在的文件。

l  -m:在-J指定的位置下自动生成相应包的目录。

l  -J:指定R.java文件生成的目录。

l  -S:指定资源目录。

l  -M:指定清单文件。

l  -I:引入类库。

图21-11就是一个生成R.java文件的示例,命令表示根据res文件资源,在gen文件下生成R文件。

图21-11 aapt命令运行

图21-12演示了如何打包res、assets资源文件生成到指定包resources.ap_下。

图21-12 aapt命令运行资源

 

aidl(Android Interface Definition Language)命令

aidl是一种Android内部进程通信接口的描述语言,通过它可以定义进程间的通信接口。在Eclipse开发中,编译aidl文件,ADT插件会像资源文件一样把aidl文件编译成Java代码,生成在gen文件夹下。利用aidl命令也可以编辑上述过程,输入命令为“aidl OPINONS INPUT [OUTPUT]”,其中,INPUT表示输入aidl文件路径,OUTPUT表示输出aidl文件对应的Java文件路径。

 

javac(Java Compiler)命令

javac命令是根据源Java文件生成对应的“.class”文件命令,其主要的参数有:

l  -d <目录>:指定存放生成的类文件的位置。

l  -bootclasspath <路径>:覆盖引导类文件的位置。

 

dx命令

在Android中,模拟器运行的是“.dex”文件,dx命令就是将“.class”文件转换成“.dex”文件。如图21-13所示,将bin目录下的“.class”文件转换成classes.dex文件,输出到bin目录下。

图21-13 dx命令运行示意图

 

apkbuilder命令

apkbuilder命令将classes.dex文件和resources.ap_文件生成apk包。命令形式为:“apkbuilder ${output.apk.file}-u -z ${packagedresource.file} -f ${dex.file} -rf  ${source.dir} –rj ${libraries.dir}”,参数解释如下:

l  -u:创建一个未签名的apk。

l  ${output.apk.file} :表示要输出的apk路径,例如:d:/HelloWorld/bin/my.apk。

l  -z ${packagedresource.file}:编译好的资源包路径,例如:d:/HelloWorld/bin/resources.ap_。

l  -f ${dex.file}:添加的dex文件的路径,例如:d:/HelloWorld/bin/classes.dex。

l  -rf ${source.dir} :源文件的路径,例如:d:/HelloWorld/src。

l  -rj ${libraries.dir} :表示引用的库的路径,例如:d:/HelloWorld/libs。

图21-14显示了如何使用apkbuilder命令将classes.dex文件和resources.ap_生成apk包。

图21-14 apkbuilder命令运行

 

 

jarsigner命令

jarsigner命令对生成的apk包进行签证,如图21-15显示了如何利用jarsigner命令将无签证的apk包签证。

图21-15 jarsigner命令运行

在签证的过程中,需要使用到证书文件,可以利用keytool命令,创建证书,如图21-16所示:

图21-16 keytool命令运行

也可以在Eclipse里使用ADT提供的图形界面完成证书的创建。选中项目,点击右键:“Android Tools”→“Export Signed Application Package”,在其中的“Keystoreselection”选择“Create new keystore”,然后按照提示填写信息,完成创建。

下面详解介绍如何编写build.xml,用于实现Android工程的自动编译、打包。首先需要定义多个变量属性,用来表示使用到的路径、目录等。如下所示定义了一个build.properties文件,用于定义变量属性:

build.properties代码清单21-3-0:

target=android-8

sdk.dir=G:\\android\\android\\android-sdk        

apkbuilder=${sdk.dir}\\tools\\apkbuilder.bat

 

sdkhomedir=G:\\android\\android\\android-sdk

android-framework=${sdk.dir}

android-jar=${sdkhomedir}\\platforms\\android-8\\android.jar

 

aapt=${sdkhomedir}\\platform-tools\\aapt

aidl=${sdkhomedir}\\platform-tools\\aidl

dx=${sdkhomedir}\\platform-tools\\dx.bat

adb=${sdkhomedir}\\platform-tools\\adb

apkbuilder=${sdkhomedir}\\tools\\apkbuilder.bat

jarsigner=D:\\jdk1.6.0_18\\bin\\jarsigner

 

projecthomedir=G:\\workspace\\AntTest

builddir=${projecthomedir}\\build

resource-dir=${projecthomedir}\\res

asset-dir=${projecthomedir}\\assets

srcdir=${projecthomedir}\\src

 

outdir-gen=${builddir}\\src

outdir-classes=${builddir}\\classes

outdir-dx=${builddir}\\dx

resources-package=${builddir}\\respak

apkdir=${builddir}\\apk

unsignedapkname=unsigntest.apk

apkname=test.apk

然后,在build.xml文件里使用<property file="build.properties"/>引入变量,实现初始化:

<!-- 初始化工作 -->

<target name="init">

           <echo>Initializingall output directories...</echo>

                     <deletedir="${outdir-bin}" />

                     <mkdirdir="${outdir-bin}" />

                     <mkdirdir="${outdir-classes}" />

</target>

使用aapt命令生成R.java文件,关键代码如下所示:

           <target name="GenRJAVA">

                     <echo>GeneratingR.java / Manifest.java from the resources...</echo>

                     <mkdirdir="${outdir-gen}" />

                     <execexecutable="${aapt}" failonerror="true">

                                <argvalue="package" />

                                <argvalue="-m" />

                                <argvalue="-J" />

                                <argvalue="${outdir-gen}" />

                                <argvalue="-M" />

                                <argvalue="${projecthomedir}/AndroidManifest.xml" />

                                <argvalue="-S" />

                                <argvalue="${resource-dir}" />

                                <argvalue="-I" />

                                <argvalue="${android-jar}" />

                     </exec>

           </target>

接着,利用aidl命令生成Java源文件:

           <targetname="aidl" depends="copy">

                     <echo>Compilingaidl files into Java classes...</echo>

                     <applyexecutable="${aidl}" failonerror="true">

<!-- 指定预处理文件 -->

                                <argvalue="-p${sdk.dir}" />

                                <!--aidl声明的目录 -->

                                <argvalue="-I${srcdir}" />

<!-- 指定哪些文件需要编译 -->

                                <filesetdir="${srcdir}">

                                          <includename="**/*.aidl" />

                                </fileset>

                     </apply>

           </target>

然后,将源文件编译成“.class”文件,如果使用到了第三方类库,可以在classpath标签下配置:

       <targetname="compile" depends="copy, GenRJAVA, aidl">

                     <mkdirdir="${outdir-classes}" />

                     <javacencoding="UTF-8" target="1.5"

debug="true" extdirs=""

srcdir="${outdir-gen}"

destdir="${outdir-classes}"

bootclasspath="${android-jar}">

                                <classpathrefid="project.classpath" />

                     </javac>

           </target>

接着,将“.class”文件转换成classes.dex文件,如果使用到第三方类库,可以在最后用参数的形式配置:

<target name="dex" depends="compile">

<echo>Converting compiled files and externallibraries into ${outdir-dx}/test.dex...</echo>

           <mkdirdir="${outdir-dx}" />

           <applyexecutable="${dx}" failonerror="true"parallel="true">

                     <argvalue="--dex" />

              <!--输出文件 -->

                     <argvalue="--output=${outdir-dx}/test.dex" />

              <!--要生成.dex文件的源classes和libraries -->

                     <argpath="${outdir-classes}" />

                     <filesetdir="${projecthomedir}" includes="*.jar" />

           </apply>

</target>

然后,利用aapt命令将资源文件打包:

       <targetname="package-res">

                     <echo>Packagingresources and assets...</echo>

                     <mkdirdir="${apkdir}" />

                     <execexecutable="${aapt}" failonerror="true">

                                <argvalue="package" />

                                <argvalue="-f" />

                                <argvalue="-M" />

                                <argvalue="${projecthomedir}/AndroidManifest.xml" />

                                <argvalue="-S" />

                                <argvalue="${resource-dir}" />

                                <argvalue="-A" />

                                <argvalue="${asset-dir}" />

                                <argvalue="-I" />

                                <argvalue="${android-jar}" />

                                <argvalue="-F" />

                                <argvalue="${resources-package}" />

                     </exec>

           </target>

接着,利用apkbuilder命令打包未签证的apk包:

       <targetname="packageAPK" depends="dex, package-res">

                     <echo>Packagingapk for release...</echo>

                     <execexecutable="${apkbuilder}" failonerror="true">

                                <argvalue="${apkdir}/${unsignedapkname}" />

                                <argvalue="-u" />

                                <argvalue="-z" />

                                <argvalue="${resources-package}" />

                                <argvalue="-f" />

                                <argvalue="${outdir-dx}/test.dex" />

                                <argvalue="-rf" />

                                <argvalue="${srcdir}" />

                                <argvalue="-rj" />

                                <argvalue="${outdir-gen}" />

                     </exec>

                     <echo>It will need to be signed withjarsigner before being published.</echo>

           </target>

然后,利用jarsigner命令对apk签证:

       <targetname="signAPK" depends="packageAPK">

                     <echo>Packaging${out-unsigned-package} for release...</echo>                 

                     <execexecutable="${jarsigner}" failonerror="true">

                                <argvalue="-verbose" />

                                <argvalue="-storepass" />

                                <argvalue="firstpeople" />

                                <argvalue="-keypass" />

                                <argvalue="firstpeople" />

                                <argvalue="-keystore" />

                                <argvalue="android.keystore" />

                                <argvalue="-signedjar" />

                                <argvalue="${apkdir}/${apkname}" />

                                <argvalue="${apkdir}/${unsignedapkname}" />

                                <argvalue="android.keystore" />

                     </exec>

           </target>

最后,利用adb命令发布apk,如下所示:

       <targetname="installAPK" depends="signAPK">

                     <echo>InstallAPK...</echo>

                     <execexecutable="adb" failonerror="true">

                                <argvalue="install" />

                                <argvalue="${apkdir}/${apkname}" />

                     </exec>

           </target>

这样就完成了build.xml文件的编辑。Eclipse包含了Ant的所有功能,可以在Eclipse中直接运行Ant,如图21-17所示:

图21-17 Ant运行

使用Ant打包使得Android项目编译周期变短,编译效率大大提高,同时利用xml脚本,可以高效的控制编译的细节,实现批量编译,批量打包。

1.4. 玄德有话说

刘备:反编译apk,资源文件在Java文件中都是十进制,这咋办?

孔明:可以编写程序根据R.java的映射关系,扫描Java文件替换十进制的字符串。

 

张飞:现在AndroidSDK 2.3版本之后启用了混淆,反编译还有什么用?

孔明:虽然AndroidSDK 2.3版本之后启用了混淆机制,但反编译对以前的老的版本还是可以的。反编译Android SDK 2.3之后的版本,还是可以看出工程的部分信息,例如布局文件。只要有一些开发功底,反编译后的代码还是可以给我们很多启发的。

 

关羽:Ant打包的apk怎么签名不正确?

孔明:请检查keystore文件名与别名是否一致。

 

刘备:Ant打包,adb报错咋办?

孔明:第一,确保E:\Android\android-sdk\platform-tools目录下有adb.exe文件。第二,确保环境变量path中有“\android-sdk\platform-tools”。

0 0
原创粉丝点击