Android中利用ant进行多渠道循环批量打包

来源:互联网 发布:流星网络电视 卡 编辑:程序博客网 时间:2024/05/01 14:26

目前国内的安卓渠道有几百家,我们要根据不同的渠道打不同渠道的apk来统计每个渠道带来的用户数,统计每个渠道用户的存活率和活跃度等等信息,但是手动对每个渠道的APK进行签名打包实在是让人感到厌烦且低效,这时我们需要一个全自动化的打包工具----ant。Android SDK的tools中已经包括了ant的打包工具,那么我们该如何运用它达到我们的要求呢?之前卤煮做这块的时候也参考了很多前辈的文章,首先向前辈们致敬,下面说下卤煮的方法,有什么不对的地方或者疑问欢迎大家留言交流。(以下步骤均在MAC系统下完成)

一.打包前准备工作

1.首先确定你的JDK版本为1.6!

2.在AndroidManifest.xml中application标签下添加一个用来识别渠道的标签:

[java] view plaincopy
  1. <meta-data  android:name="qudao"  android:value="channel" />  

3.为了让ant支持循环功能,我们要在Android SDK/tools/lib下放一个ant-contrib-1.0b3.jar包

4.项目中放置第三方jar包的文件夹必须叫libs而不是lib

 

二.build.xml等文件的生成和配置

1.通过终端(cmd)命令自动生成build.xml和local.properties两个文件,方法如下:

[java] view plaincopy
  1. <sdk>/tools/android update project -p <project> -t <target>  

例如:

[java] view plaincopy
  1. /Users/moushou/Downloads/AndroidSDK/tools/android update project -p /Users/moushou/Documents/workspace/HelloWorld -t 14  

其中<sdk>为SDK全路径,<project>为项目全路径,<target>为API版本。

执行完成截图如下:

执行完成后,Refresh你的项目就会发现项目的根目录下多了两个文件:build.xml和local.properties

其中local.properties的内容是:

[java] view plaincopy
  1. # This file is automatically generated by Android Tools.  
  2. # Do not modify this file -- YOUR CHANGES WILL BE ERASED!  
  3. #  
  4. # This file must *NOT* be checked into Version Control Systems,  
  5. # as it contains information specific to your local configuration.  
  6.   
  7. # location of the SDK. This is only used by Ant  
  8. # For customization when using a Version Control System, please read the  
  9. # header note.  
  10. sdk.dir=/Users/moushou/Downloads/AndroidSDK  

project.properties的内容如下:

[java] view plaincopy
  1. # This file is automatically generated by Android Tools.  
  2. # Do not modify this file -- YOUR CHANGES WILL BE ERASED!  
  3. #  
  4. # This file must be checked in Version Control Systems.  
  5. #  
  6. # To customize properties used by the Ant build system use,  
  7. "ant.properties", and override values to adapt the script to your  
  8. # project structure.  
  9. #proguard.config=proguard.cfg  
  10. # Project target.  
  11. target=Google Inc.:Google APIs:14  
  12. proguard.config=proguard.cfg  

项目的目录结构如下图所示:

:project.properties中target=GoogleInc.:GoogleAPIs:14代表所使用的SDK的版本,可进行手动修改。

2.手动为项目新建一个File,该文件名为:ant.properties,创建完成项目的目录结构如下图:

创建完成后在ant.properties中添加如下内容:

[java] view plaincopy
  1. key.store=<keystore>  
  2. key.alias=<key>  
  3. key.store.password=<keystore pwd>  
  4. key.alias.password=<key pwd>  
  5. market_channels=xx,yy,zz  
  6. app_version=1_0_build_0  

例如:

[java] view plaincopy
  1. key.store=/Users/moushou/Desktop/qianming  
  2. key.alias=meilihuaduo  
  3. key.store.password=123456xx  
  4. key.alias.password=123456xx   
  5. market_channels=anzhuoshichang,jifengshichang,baiduyingyongzhongxin  
  6. app_version=1_0_build_0  

其中:

keystore为签名文件的全路径。

key.alias为签名需要使用的私钥。

key.store.password为私钥库的密码。

key.alias.password为私钥的密码。

market_channels为渠道集合。

app_version为apk的版本(此字段可根据自己喜好编写)。

三.下面我来说下build.xml的编写方法:

1.修改build.xml的第二行,修改方法如下:

[java] view plaincopy
  1. <project name="HelloWorld" default="release">  

其中name为你项目的名称,default设置为release。

2.循环替换AndroidManifest.xml中qudao的value值并进行自动签名打包,方法如下:

[java] view plaincopy
  1. <import file="${sdk.dir}/tools/ant/build.xml" />  
  2.     <property name="out.unaligned.dir" value="/Users/moushou/Desktop/HelloWorld_${app_version}/" />  
  3.     <mkdir dir="${out.unaligned.dir}" />  
  4.     <target name="modify_update_file">  
  5.         <echo>*********************** make channel ${channel}</echo>  
  6.           
  7.         <replaceregexp file="AndroidManifest.xml"  
  8.             match='channel'  
  9.             replace='${channel}'  
  10.             byline="false"  
  11.             encoding="utf-8"  
  12.         />  
  13.         <property name="out.unaligned.file" location="${out.unaligned.dir}/HelloWorld_${app_version}_${channel}_android.apk"/>  
  14.           
  15.     </target>  
  16.   
  17.     <target name="make_one_channels" depends="savemanifest,modify_update_file,release,replacemanifest,deletebin" description="description">  
  18.     </target>  
  19.   
  20.     <target name="replacemanifest">  
  21.         <echo>*********************** replacemanifest</echo>  
  22.         <delete file="${basedir}\AndroidManifest.xml"/>  
  23.         <copy file="..\temp\build\META-INF\AndroidManifest.xml" todir="${basedir}" encoding="utf-8"/>  
  24.     </target>  
  25.   
  26.     <target name="savemanifest">  
  27.         <echo>*********************** savemanifest</echo>  
  28.         <copy file="${basedir}\AndroidManifest.xml" todir="..\temp\build\META-INF" encoding="utf-8" />  
  29.     </target>  
  30.   
  31.     <target name="deletebin">  
  32.         <delete dir="${basedir}\bin" />  
  33.     </target>  
  34.   
  35.     <taskdef name="foreach" classname="net.sf.antcontrib.logic.ForEach" classpath="/Users/moushou/Downloads/AndroidSDK/tools/lib/ant-contrib-1.0b3.jar" />  
  36.     <target name="make_channels">  
  37.         <foreach target="make_one_channels" list="${market_channels}" delimiter="," param="channel">  
  38.         </foreach>  
  39.     </target>  

其中:

1.out.unaligned.dir的value值为apk输出文件夹的绝对路径,文件夹采用HelloWorld结合app_version命名,app_version为ant.properties中的app_version

2.out.unaligned.file的location为apk最终的输出路径,apk命名采用HelloWorld加app_version加当前的channel加android方式

3.说一下打包的过程:

(1)第36行make_channels的target是ant的入口,该target中使用foreach循环调用名为make_one_channels的target(第17行)并把market_channels集合中的每个值替换给channel

(2)make_one_channels的target指定了每次打包的过程:

   savemanifest:打包前先将原始的AndroidManifest.xml复制到与项目同一层级目录下的temp下build下META-INF中

   modify_update_file:匹配到AndroidManifest.xml中的channel并将其替换

   release:自动编译加签名

   replacemanifest:删除AndroidManifest.xml,将temp/build/META-INF中的原始AndroidManifest.xml复制回项目根目录下

   deletebin:删除bin文件(:这步很重要,否则只能打出一个渠道的APK,当时做这块的时候碰到的问题)

4.第35行taskdef标签下的classpath是ant-contrib-1.0b3.jar的绝对路径

 

四.打包方法的使用

打开终端(cmd),执行:

[java] view plaincopy
  1. cd /Users/moushou/Documents/workspace/HelloWorld  

然后执行:

[java] view plaincopy
  1. ant make_channels  

此时,打包就开始进行啦!当出现BUILD SUCCESSFUL代表打包成功!如下图所示:

此时你会发现你输出的文件夹中多了三个APK,如下图:

 1.每次打包前一定要删除掉temp/build/META-INF中的AndroidManifest.xml,特别是在给不同项目做打包时

   2.打包前请检查AndroidManifest.xml中qudao的value值是否为channel,特别是打包失败后再次重新打包的时候一定要将value值改为channel

   3.如果打包时出现Cannot recover key错误导致BUILD FAILD的话,请检查ant.properties中key.alias.password的值后面是否有多余的空格!有的话请把空格删除掉!

 

五.在代码中获取渠道值,方法如下:

[java] view plaincopy
  1. public static String getAppChannel(Context context) {  
  2.     String channel = "dudao";  
  3.     try {  
  4.         ApplicationInfo appInfo = context.getPackageManager()  
  5.                 .getApplicationInfo(context.getPackageName(),  
  6.                         PackageManager.GET_META_DATA);  
  7.         channel = appInfo.metaData.getString("dudao");  
  8.     } catch (NameNotFoundException e) {  
  9.         e.printStackTrace();  
  10.     }  
  11.     return channel;  
  12. }  

相关代码注解:

复制代码
<?xml version="1.0" encoding="UTF-8"?><project name="custom_rules" ><!--     声明ant loop ,这里直接用ant的循环功能,批处理什么的又要多写代码,而且我也不熟 -->    <taskdef resource="net/sf/antcontrib/antcontrib.properties" >        <classpath>            <pathelement location="lib/ant-contrib-1.0b3.jar" />        </classpath>    </taskdef><!-- 这里相当于一个方法把,(表示ant不会,只能看懂= =) ,以后可以用命令行 ant deploy 来表示批量打包 --><!-- ${market_channels} 要在local.properties里声明,并用,来分隔你要打包的channel名 --><!-- 比如我的local.properties里是这样写的   market_channels=Google,Gfan,AnZhi,MuMayi -->    <target name="deploy" >        <foreach            delimiter=","            list="${market_channels}"            param="channel"            target="modify_manifest" >        </foreach>    </target><!-- 修改manifest.xml里的渠道名,如果你要改其他文件,举一反三把 --><!-- regexp pattern是正则匹配,这里双引号要用&quot;而不是\ --><!-- substitution expression 是你要替换的的channel名--><!-- 打包完毕后要把apk移动到一个指定的目录把,你可以在sdk/tools/ant/build.xml搜下out.final.file这个property在哪用到的--><!-- <property name="out.final.file" location="${apk.dir}/XXX_${channel}.apk" />  ${apk.dir}表示你要指定的apk目录 XXX表示你要定义apk名和${channel}渠道号--><!-- <antcall target="clean" /> <antcall target="release" /> release之前要调下clean,不然以后改的channel名不生效,你懂得-->    <target name="modify_manifest" >       <replaceregexp flags="g" byline="false">          <regexp pattern="android:value=&quot;(.*)&quot; android:name=&quot;UMENG_CHANNEL&quot;" />              <substitution expression="android:value=&quot;${channel}&quot; android:name=&quot;UMENG_CHANNEL&quot;" />             <fileset                dir=""                includes="AndroidManifest.xml" />        </replaceregexp>        <property            name="out.final.file"            location="${apk.dir}/XXX_${channel}.apk" />        <antcall target="clean" />        <antcall target="release" />    </target></project>
复制代码
转自:http://blog.csdn.net/i_lovefish/article/details/35640257
0 0
原创粉丝点击