Android利用ant手动打包

首先我们要给自己的IDE eclispe配置ant,默认的eclipse是集成了ant构建工具的,但是google提供的Android集成开发工具ADT,里面封装了Eclipse,但是很奇怪的是竟然没有Ant插件在里面标准的Eclipse一般都是内置集成了Ant的。然后我们到eclipse的plugins目录下查看了,其实是有安装ant插件的,但是没有在界面体现出来。要让Eclipse在界面显示Ant的相关配置,可在命令行下作如下操作:

 $ cd install folder> $ eclipse -application org.eclipse.equinox.p2.director -repository http://download.eclipse.org/releases/juno -installIU org.eclipse.ant.ui Installing  org.eclipse.ant.ui 3.5.400.v20130514-1341.

然后重启一下你的eclipse就可以看到ant插件在菜单中正常显示出来了。 

通常我们习惯用eclipse来开发Android程序,它会自动帮我们打包当前的应用程序。如果在Navigator视图下,我们可以看到以下几个文件:

在上图中,com包放置的是我们的class文件,classes.dex是class文件经过转换后的可以在dalvik上跑的精简类文件,resources.ap_是经过打包的资源文件,ant.apk就是最终的打包文件。

使用ANT来对应用打包,一般会经过以下几个步骤:

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

为了便于理解和记忆,下面来用一张流程图来说明以上的几个过程:

以上就是整体的流程,下面我们就对其每个部分进行做出详细讲解,把每一个步骤都弄清楚了。

我们需要先熟悉一下每一个步骤所使用到的命令:

1.aapt(Android Asset Packaging Tool)命令,根据资源文件生成R.java文件

参数说明:

-f  强制覆盖已存在的文件。
-m  在-J指定的位置下自动生成相应的包的目录。
-J  指定R.java文件生成的目录。
-S  指定资源目录。
-M  指定清单文件。
-I  引入类库。

注意,我们当前所在的位置是ant项目根目录,所以必要时需要输入很多关于命令的路径,以下示例也是一样。

2.aidl(Android Interface Definition Language)命令,根据.aidl定义文件生成java文件

上面的示例所在位置为com/scott/ant下,根据包中的Person.aidl文件,在gen对应的目录中生成Person.java文件,示例中只是处理单一文件,下文中会讲述如何处理目录中的多个aidl文件。

3.javac(Java Compiler)命令,根据源文件生成对应的class文件

参数说明:

-d <目录>      指定存放生成的类文件的位置
-bootclasspath <路径>     覆盖引导类文件的位置

示例中并没有考虑到引用类路径下面的类库,复杂的情况会在稍后遇到的。

4.dx命令,将class文件转换成.dex文件

以上示例是将bin目录下的class文件转换成classes.dex文件,输出到bin目录,我们也许会用到第三方类库,等一会就会看到。

5.aapt将资源文件打包

参数说明:

-f 强制覆盖

-M 指定Manifest文件

-S 指定资源目录

-A 指定资产目录

-I 指定引入的类库

-F 指定要生成的包

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

参数说明:

-rf 参照源文件的目录的结构

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

在签证的过程中,需要使用到证书文件,需要注意的是最后的release是证书的别名,关于如何创建证书,请看下图:

当然也可以在eclipse里使用ADT提供的图形界面完成以上步骤,选中项目,点击右键,“Android Tools=>Export Signed Application Package”,然后再其中的Keystore selection环节选择“Create new keystore”,然后按照提示填写信息就可以了。

以上是我们使用到的命令,接下来我们就该来分析一下ANT所必须的build.xml:

首先我们需要定义大量的变量属性,用来表示使用到的路径、目录等,如下:

<project name="ant" default="release">            <property environment="env" />            <property name="appName" value="${ant.project.name}"/>            <property name="sdk-folder" value="${env.ANDROID_SDK_HOME}" />            <property name="sdk-platform-folder" value="${sdk-folder}/platforms/android-8"/>            <property name="sdk-tools" value="${sdk-folder}/tools" />            <property name="sdk-platform-tools" value="${sdk-platform-folder}/tools" />              <property name="aapt" value="${sdk-platform-tools}/aapt" />      <property name="aidl" value="${sdk-platform-tools}/aidl" />      <property name="dx" value="${sdk-platform-tools}/dx.bat" />      <property name="apkbuilder" value="${sdk-tools}/apkbuilder.bat" />      <property name="jarsigner" value="${env.JAVA_HOME}/bin/jarsigner" />                  <property name="android-jar" value="${sdk-platform-folder}/android.jar" />      <property name="android-maps-jar" value="${sdk-folder}/add-ons/addon_google_apis_google_inc_8/libs/maps.jar"/>                  <property name="framework-aidl" value="${sdk-platform-folder}/framework.aidl" />              <property name="outdir-gen" value="gen" />            <property name="outdir-bin" value="bin" />                  <property name="manifest-xml" value="AndroidManifest.xml" />            <property name="resource-dir" value="res" />      <property name="asset-dir" value="assets" />            <property name="srcdir" value="src" />      <property name="srcdir-ospath" value="${basedir}/${srcdir}" />            <property name="external-lib" value="lib" />      <property name="external-lib-ospath" value="${basedir}/${external-lib}" />              <property name="outdir-classes" value="${outdir-bin}" />      <property name="outdir-classes-ospath" value="${basedir}/${outdir-classes}" />              <property name="dex-file" value="classes.dex" />      <property name="dex-path" value="${outdir-bin}/${dex-file}" />      <property name="dex-ospath" value="${basedir}/${dex-path}" />              <property name="resources-package" value="${outdir-bin}/resources.ap_" />      <property name="resources-package-ospath" value="${basedir}/${resources-package}" />                  <property name="out-unsigned-package" value="${outdir-bin}/${appName}-unsigned.apk" />      <property name="out-unsigned-package-ospath" value="${basedir}/${out-unsigned-package}" />                  <property name="keystore-file" value="${basedir}/release.keystore" />                  <property name="out-signed-package" value="${outdir-bin}/${appName}.apk" />      <property name="out-signed-package-ospath" value="${basedir}/${out-signed-package}" />          ...  project> 

然后,我们分步骤来进行,首先是初始化:

      <target name="init">          <echo>Initializing all output directories...echo>          <delete dir="${outdir-bin}" />          <mkdir dir="${outdir-bin}" />          <mkdir dir="${outdir-classes}" />      target>  

其次是生成R.java文件:

      <target name="gen-R" depends="init">          <echo>Generating R.java from the resources...echo>          <exec executable="${aapt}" failonerror="true">              <arg value="package" />              <arg value="-f" />              <arg value="-m" />              <arg value="-J" />              <arg value="${outdir-gen}" />              <arg value="-S" />              <arg value="${resource-dir}" />              <arg value="-M" />              <arg value="${manifest-xml}" />              <arg value="-I" />              <arg value="${android-jar}" />          exec>      target>  

接着是aidl生成java源文件:

      <target name="aidl" depends="gen-R">          <echo>Compiling .aidl into java files...echo>          <apply executable="${aidl}" failonerror="true">                            <arg value="-p${framework-aidl}"/>                            <arg value="-I${srcdir}"/>                            <arg value="-o${outdir-gen}"/>                            <fileset dir="${srcdir}">                  <include name="**/*.aidl"/>              fileset>          apply>      target>  

我们指定了一个framework.aidl,里面定义了很多android内置对象,然后我们指定了aidl所在目录和输出目录,组后指定编译后缀为aidl的文件。接下来是将源文件编译成class文件:

      <target name="compile" depends="aidl">          <echo>Compiling java source code...echo>          <javac encoding="utf-8" target="1.5" srcdir="." destdir="${outdir-classes}" bootclasspath="${android-jar}">              <classpath>                  <fileset dir="${external-lib}" includes="*.jar"/>                  <filelist>                      <file name="${android-maps-jar}"/>                  filelist>              classpath>          javac>      target>  

如果使用到了第三方类库,我们可以在classpath标签下配置。接着是将class文件转换成classes.dex:

      <target name="dex" depends="compile">          <echo>Converting compiled files and external libraries into a .dex file...echo>          <exec executable="${dx}" failonerror="true">              <arg value="--dex" />                            <arg value="--output=${dex-ospath}" />                            <arg value="${outdir-classes-ospath}" />              <arg value="${external-lib-ospath}"/>          exec>      target>  

就像上面的代码一样,如果使用到第三方类库,可以在最后一参数的形式追加进去。然后是将资源文件打包:

      <target name="package-res-and-assets">          <echo>Packaging resources and assets...echo>          <exec executable="${aapt}" failonerror="true">              <arg value="package" />              <arg value="-f" />              <arg value="-M" />              <arg value="${manifest-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>      target>  

接着是打包成未签证的apk包:

      <target name="package" depends="dex, package-res-and-assets">          <echo>Packaging unsigned apk for release...echo>          <exec executable="${apkbuilder}" failonerror="true">              <arg value="${out-unsigned-package-ospath}" />              <arg value="-u" />              <arg value="-z" />              <arg value="${resources-package-ospath}" />              <arg value="-f" />              <arg value="${dex-ospath}" />              <arg value="-rf" />              <arg value="${srcdir-ospath}" />          exec>          <echo>It will need to be signed with jarsigner before being published.echo>      target>  

然后是对apk签证:

      <target name="jarsigner" depends="package">          <echo>Packaging signed apk for release...echo>          <exec executable="${jarsigner}" failonerror="true">              <arg value="-keystore" />              <arg value="${keystore-file}" />              <arg value="-storepass" />              <arg value="123456" />              <arg value="-keypass" />              <arg value="123456" />              <arg value="-signedjar" />              <arg value="${out-signed-package-ospath}" />              <arg value="${out-unsigned-package-ospath}"/>                            <arg value="release"/>          exec>      target>  

最后发布:

      <target name="release" depends="jarsigner">                    <delete file="${out-unsigned-package-ospath}"/>          <echo>APK is released. path:${out-signed-package-ospath}echo>      target>  

这样就完成了build.xml的编辑,eclipse继承了ANT,所以我们可以在eclipse中直接运行,也可以在代码中调用。首先我们需要下载ANT,然后配置相应的环境变量信息,最后我们这样调用:

Process p = Runtime.getRuntime().exec("ant.bat -buildfile d:/workspace/ant/build.xml");  InputStream is = p.getInputStream();  BufferedReader br = new BufferedReader(new InputStreamReader(is));  String line = null;  while ((line = br.readLine()) != null) {      System.out.println(line);  }  System.out.println("SUCCESS.");  

 用ant去给android进行打包时,发现apkbuilder找不到了,sdk更新3.0以后貌似apkbuilder已经被删除了,并且一些命令的目录也换了。下面就说一下怎么在没有apkbuilder的情况下生成apk文件,其实apkbuilder是一个批处理文件,打开里面就能发现,其实他内部执行的是sdklib.jar里面的一个class,所以就知道怎么做了,很简单,我们自己直接去调用java去执行这个类,如下:

<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>  

其实以前的apkbuilder.bat内部也是执行的

com.android.sdklib.build.ApkBuilderMain 

//这个类,我们在这里自己直接执行了,其实一样的!  

解决Android项目Dex中方法超出65536个方法异常

当我们的项目代码过大时,编译运行时会报Unable to execute dex: method ID not in[0, 0xffff]: 65536)错误。当出现这个错误时说明你本身自己的工程代码中含有的太多的方法,或者你的工程lib文件夹下引用的第
三方插件jar包有太多的方法,这两者的方法加起来已经超过了65536这个数目。而谷歌规定单个dex文件中的方法不能超过65536的限制。那么这个时候,我们就需要分包处理解决。一般情况下的解决方案就是把整个项目工程包括jar,区分开来分解成两个dex文件。网上很多这些解决方案,有的把项目代码中比较独立的模块打包成jar文件,然后利用dx工具将打包的jar文件转成dex文件的jar,然后将其放到SD卡中去动态加载。这种方案是不符合我们的需求的。那么问题来了,该如何更好的去拆分Dex文件,绕过谷歌规定的65536呢?其实,网上已经有些牛人帮我们提出了很多方案了,尤其是在github上。特别是mmin18提出的方案,githut地址如下:

https://github.com/mmin18/Dex65536

该解决方案的原理差不多是这样:

1.在工程目录下创建custom_rules.xml文件,修改编译策略。将工程lib的文件中含有的第三方插件jar包全部打包成libs.apk,然后将其作为编译运行时的第二个dex文件。

2.最后通过ant命令执行操作,运行整个工程或签名加密打包整个工程。

看起来很简单,如果要真正的去了解整个原理,还是很有难度,首先你得对custom_rules.xml文件的相关配置和android工程的编译策略非常熟悉。不过,这里我们不用管它,既
然牛人已经帮我们写好了,那我们只要知道怎么去用到我们的项目中就行了。接下来就是怎么去用到我们的项目代码中了(当然,感兴趣的同志可以去研究研究它的实现原理)。

一.配置和运行工程步骤如下:

1. 竟然要用到ant,首先就要先下载ant和配置ant环境,下载链接地址为:http://ant.apache.org/bindownload.cgi。下载好apache-ant-1.9.4-bin.zip包后,解压到指定目录。然后配置环境变量,创建变量名为
ANT_HOME,值为ant文件对应的路径,比如我的是ANT_HOME = E:\apache-ant-1.9.4-bin\apache-ant-1.9.4。然后在Path变量的值中追加%ANT_HOME%/bin;%ANT_HOME%/lib。这样ant环境变量就配置好了。

2. 接下来就是拷贝文件custom_rules.xml和pathtool.jar到我们项目的根目录下。

3. 然后就在我们的项目运行之前添加代码执行去加载第二个dex文件,下面的dexTool方法就是执行加载第二个dex文件的功能代码,直接copy到我们的自定义application类中就行了,代码如下:

@SuppressLint("NewApi")
private void dexTool() {
File dexDir = new File(getFilesDir(), "dlibs");
dexDir.mkdir();
File dexFile = new File(dexDir, "libs.apk");
File dexOpt = getCacheDir();
try {
InputStream ins = getAssets().open("libs.apk");
if (dexFile.length() != ins.available()) {
FileOutputStream fos = new FileOutputStream(dexFile);
byte[] buf = new byte[4096];
int l;
while ((l = ins.read(buf)) != -1) {
fos.write(buf, 0, l);
}
fos.close();
}
ins.close();
} catch (Exception e) {
throw new RuntimeException(e);
}

ClassLoader cl = getClassLoader();
ApplicationInfo ai = getApplicationInfo();
String nativeLibraryDir = null;
if (Build.VERSION.SDK_INT > 8) {
nativeLibraryDir = ai.nativeLibraryDir;
} else {
nativeLibraryDir = "/data/data/" + ai.packageName + "/lib/";
}
DexClassLoader dcl = new DexClassLoader(dexFile.getAbsolutePath(),
dexOpt.getAbsolutePath(), nativeLibraryDir, cl.getParent());

try {
Field f = ClassLoader.class.getDeclaredField("parent");
f.setAccessible(true);
f.set(cl, dcl);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

接着在自定义application类的onCreate方法中调用dexTool。

4. 自动生成build.xml文件。打开命令窗口,进入到工程的根目录下,输入如下命令android update project -p . (.代表当前目录)在输入该命令之前,要确保你配置的sdk/tools目录和sdk/tools/lib文件夹中有android.bat和find_java.bat文件。

5. 然后就是运行该工程了。输入命令ant clean debug install run,在输入该命令之前要确保你的ant环境配置没有问题。

二.签名混淆代码:

上面的运行apk并没有通过代码混淆和签名,一般情况下我们需要生成一个经过代码混淆和签名的apk,那么ant环境下怎么去配置才能生成代码混淆和签名的apk呢。接下来将进行说明。

1. 在刚刚已经配置好的工程根目录下创建ant.properties文件,该文件在创建工程时是不会自动生成的,需要我们自己去创建。这个文件会在build.xml文件中声明。

2. 然后在创建好的ant.properties中添加相关信息,比如我添加的信息如下

第一行内容为配置关联相关的加密信息文件(也可能为proguard.config = proguard.cfg)

第二行内容为指定签名文件所在路径,./keystore.eking,说明该签名文件在工程根目录下(拷贝签名文件到工程根目录)

第三行内容为签名文件的alias值为eking

第四、第五行分别为签名文件对应的store、alias密码。

3.接着在工程目录下执行如下命令antrelease, 执行完后会自动在工程的bin目录下生成appname-release.apk文件,这个就是签名后生成的apk。

转载于:https://www.cnblogs.com/wxishang1991/p/5867626.html

更多相关文章

  1. Android(安卓)官方 Training 文档学习总结系列之「支持不同的设
  2. Android(安卓)仿Iphone文件夹分裂效果
  3. Android(安卓)关于录音文件的编解码 实现米聊 微信一类的录音上
  4. 引用 android string.xml文件中的整型和string型代替
  5. 关于android 4.2版本后的多用户目录结构分析(二)- /storage/sdcard
  6. Android(安卓)国际化
  7. A007-assets资源
  8. PC客户端与Android服务端的Socket同步通信(USB)(转载)
  9. cocos2dx android mk 2.0.2编译文件目录以及导入库问题

随机推荐

  1. SQL Server 2016 查询存储性能优化小结
  2. MyBatis MapperProvider MessageFormat拼
  3. SQL Server 触发器实例详解
  4. 常用SQL语句查询分享
  5. ASP.NET和MSSQL高性能分页实例代码
  6. SQL SERVER使用ODBC 驱动建立的链接服务
  7. SQL语句优化提高数据库性能
  8. SQL Server无法收缩日志文件的原因分析及
  9. 实例详解Group by和Having子句
  10. 详解Sql基础语法