Android Ant 自动打包 修改包名,修改logo,修改名字,修改配置

虽然当下Android Studio盛行,昨天有朋友问到了用Ant 怎么自动打包,现在自动打包确实仍然是部分像我这样的菜鸟面临的问题,既然有人问就借此契机搞一波,说不定什么时候自己就用上了。

需求是要提供方便的方式在打包的时候修改 package、logo、label、meta-data(包名、图标、名称、第三方SDK配置),以及个别Java类的字段。

原料:ADT、Android  SDK、apache-ant-1.9.7、xmltask.jar。

这篇博客就是我昨天求知的坎坷过程。

首先要想使用Ant打包项目,第一步肯定是要配置相关的环境,默认创建的Android项目是没有Ant环境的,关于Ant我很久很久之前也写过一点东西或多或少能帮助理解什么是Ant,要想查看请点击这里

要配置Ant环境其实并不难,百度一波就能看到很多,这里我就把我配置的过程记录下来至于别的方式我就不过多列举了:

1、先去官网(http://ant.apache.org/bindownload.cgi)下载  apache-ant-1.9.7-bin.zip ,解压安装

2、配置环境变量以便于在任何目录都能使用命令行执行命令,以我的配置为例:

  添加系统变量  ANT_HOME    D:\Program Files\apache-ant-1.9.7-bin\apache-ant-1.9.7

  

 

    在Path中添加  ;%ANT_HOME%\bin

  

 

      测试配置是否成功,在命令行输入ant -version

    

   至此Ant已经安装成功,环境变量也配置好了。

3、为Android项目配置Ant环境,这里要使用到SDK中android.bat 批处理文件来配置工程里build.xml脚本,以及相关文件,具体操作如下:

   a.为了演示我创建Android项目(AntPackage)

   进入命令行切换到SDK/tool目录下,(或者在sdk\tools目录下直接进入命令行)

  输入android -h可看到如下帮助提示:

  

这些都是该批处理文件给我们提供的命令,我们要用到的是  android update project ,

android update project 可以有一下参数:

  

以上命令仔细看看都是我们可以理解的一些命令。

我在这里使用的命令如下: android update project -n AntPackage -t 2 -p D:\WorkSpace\Eclipse-Android2\AntPackage

刷新我们的项目可以看到SDK为该项目配置的 build.xml、loacal.properties、以及其他的相关文件,

4、添加 ant.properties、custom_rules.xml

  打开build.xml里面的一些命令或者注释仔细看我们都是可以看懂的,其中有一段注释是

 <!-- The ant.properties file can be created by you. It is only edited by the
         'android' tool to add properties to it.
         This is the place to change some Ant specific build properties.
         Here are some properties you may want to change/update:

         source.dir
             The name of the source directory. Default is 'src'.
         out.dir
             The name of the output directory. Default is 'bin'.

         For other overridable properties, look at the beginning of the rules
         files in the SDK, at tools/ant/build.xml

         Properties related to the SDK location or the project target should
         be updated using the 'android' tool with the 'update' action.

         This file is an integral part of the build system for your
         application and should be checked into Version Control Systems.

         -->

 大致意思就是我们应该创建自己的 ant.properties 我们可以在该文件中定义自己的配置属性,android tool会读取这些属性,那我么就创建这个文件,根据我们的需要添加配置属性值

#在此文件中定义我们使用到的属性,中文的话需要转成UTF-8编码,可以使用JDK自带的native2ascii工具转码

#包名  
application.package=com.tai.autopackage
#项目名,缺省时源码文件名  
ant.project.name=Autopackage
#编码方式  
#java.encoding=utf-8 
 
#编译输出绝对路径  
out.absolute.dir=d:/WorkSpace/out
#生成文件绝对路径  
gos.path=d:/WorkSpace/out


#签名key文件绝对路径  
key.store=D:/WorkSpace/a.keystore
#签名文件密码  
key.store.password=123456
#签名别称
key.alias=auto1
#签名别称密码  
key.alias.password=123456

basedir=D:/WorkSpace/Eclipse-Android2/Autopackage
xmltasklib.dir=libs
manifest.file=AndroidManifest.xml
project.name=NewProjectName
android.icon=@drawable/ic_launchernew
android.app_name=dsadasxc

 另外还有一段注释如下:

<!--
        Import per project custom build rules if present at the root of the project.
        This is the place to put custom intermediary targets such as:
            -pre-build
            -pre-compile
            -post-compile (This is typically used for code obfuscation.
                           Compiled code location: ${out.classes.absolute.dir}
                           If this is not done in place, override ${out.dex.input.absolute.dir})
            -post-package
            -post-build
            -pre-clean
    -->

这段注释大致是说我们可以添加自己的build rules文件(custom_rules.xml)来自定义自己的"过渡"target比如-pre-build 等,这些target会执行的原因可以查看sdk/tool/ant/build.xml,里面有如下几句

<!-- empty default pre-compile target. Create a similar target in
         your build.xml and it'll be called instead of this one. -->
    <target name="-pre-compile"/>

    <!-- Compiles this project's .java files into .class files. -->
    <target name="-compile" depends="-pre-build, -build-setup, -code-gen, -pre-compile">
        <do-only-if-manifest-hasCode elseText="hasCode = false. Skipping...">
            <!-- merge the project's own classpath and the tested project's classpath -->
            <path id="project.javac.classpath">
                <path refid="project.all.jars.path" />
                <path refid="tested.project.classpath" />
                <path path="${java.compiler.classpath}" />
            </path>
            <javac encoding="${java.encoding}"
                    source="${java.source}" target="${java.target}"
                    debug="true" extdirs="" includeantruntime="false"
                    destdir="${out.classes.absolute.dir}"
                    bootclasspathref="project.target.class.path"
                    verbose="${verbose}"
                    classpathref="project.javac.classpath"
                    fork="${need.javac.fork}">
                <src path="${source.absolute.dir}" />
                <src path="${gen.absolute.dir}" />
                <compilerarg line="${java.compilerargs}" />
            </javac>

从红色字体可以看出 sdk build.xml有<target name="-compile" depends="-pre-build, -build-setup, -code-gen, -pre-compile">

这就解释了我们写的脚本为什么会执行。

说了这么多贴出来我的custom_rules.xml

   

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project name="custom_rules">
 3     <path id="xmltask.classpath">  
 4          <pathelement path="${basedir}/${xmltasklib.dir}/xmltask.jar" />  
 5     </path>
 6     
 7     <taskdef name="xmltask" classname="com.oopsconsultancy.xmltask.ant.XmlTask" classpathref="xmltask.classpath"/>  
 8     <target name="-pre-build" depends="changeLogo"> 
 9         <echo>do something others</echo>  
10     </target>
11     
12     <target name="changeLogo" depends="changeName">
13         <echo>changelogo...</echo>  
14         <xmltask source="${basedir}/${manifest.file}" dest="${basedir}/${manifest.file}" encoding="utf-8" >
15             <attr path="//manifest/application" attr="android:icon" value="${android.icon}" />
16         </xmltask>
17     </target>
18     
19     <target name="changeName" >
20         <echo>changeName...</echo>
21         <xmltask source="${basedir}/res/values/strings.xml" dest="${basedir}/res/values/strings.xml" encoding="utf-8" >
22             <replace path="/resources/string[@name='app_name']/text()" withText="${android.app_name}"/>
23         </xmltask>  
24     </target>
25 </project>

 

 看着代码是不多,但是里面有一个xmltask, xmltask是什么呢?回到我们需求,我们需求是在打包的时候修改 package、logo、label、meta-data(包名、图标、名称、第三方SDK配置),以及个别Java类的字段。

Ant可以是提供了命令让我们修改文件、替换文件,可是我还是觉得不是很方便,为什么呢?

一下是我第一次修改应用名字的方式

 <!--<replace file ="res/values/strings.xml" token="Autopackage" value="新的名字"/>-->

这种文本替换的方式从某种意义上说能达到我们需求但是,操作之后文件就会被修改,下次我要打包成别的名字又要修改脚本或者string.xml文件,相当麻烦。同样的道理用replace命令修改logo也存在一样的问题。

这种麻烦产生的原因是以上的操作只是针对文本进行的操作,可能ant还有别的好用的命令,但是我们的这些都是都是存在XML文件中的,要是ant能提供一种让我们直接操作XML的命令那就方便多了。

Ant本身很强大,正因为它的强大才会有很多第三方的扩展包。xmltask就是一个非常方便的操作xml文件的扩展。

要想使用这个xmltask,首先要先下载他们的jar包放到项目里,最重要的是我们要在ant中引入xmltask.一下就是引入方式

<path id="xmltask.classpath">  
         <pathelement path="${basedir}/${xmltasklib.dir}/xmltask.jar" />  
    </path>
    
    <taskdef name="xmltask" classname="com.oopsconsultancy.xmltask.ant.XmlTask" classpathref="xmltask.classpath"/>  

里面的 basedir 、 xmltasklib.dir以及别的属性都是我们在ant.properties中定义好的。

 

OK,到此一切都配置妥当,让我们来试着打包一次,从Android项目根目录进入命令行执行 如下:

... ... .... 

 OK到这里我们就完成了动态的在打包的时候完成修改logo|name的操作,再看看怎么去修改应用中的某些Java变量

 现在我们有个常量Java类,里面有我们应用请求的根目录和请求的跟地址如下:

 1 package com.tai.antpackage.constants;
 2 
 3 public class HttpConstants {
 4 
 5     public final static String URL = "${URL}";
 6     public final static String BASEROOT = "${BASEROOT}";
 7     /**
 8      * other variables and methods
 9      */
10 }

这里我们首先把 URL 、BASEROOT 的都写的比较特殊,目的是为了在做替换的时候防止替换到别的变量或者文本。

一下是我们替换值得命令:

<target name="changeName" depends="changeJavaVariable">
        <echo>changeName...</echo>
        <xmltask source="${basedir}/res/values/strings.xml" dest="${basedir}/res/values/strings.xml" encoding="utf-8" >
            <replace path="/resources/string[@name='app_name']/text()" withText="${android.app_name}"/>
        </xmltask>  
    </target>
    
    <target name="changeJavaVariable">
        <echo>change java file variable value...</echo>
        <!--copy file="${basedir}/${srcdir}/${file.replace.path}/${fileName}" todir="res" /-->
        <replace file="${basedir}/${srcdir}/${file.replace.path}/${fileName}" token="${UrlKey}" value="${UrlValue}" encoding="utf-8"/>
        <replace file="${basedir}/${srcdir}/${file.replace.path}/${fileName}" token="${BaseRootKey}" value="${BaseRootVaue}" encoding="utf-8"/>
        <delete dir="${basedir}/bin/classes" />
    </target>

绿色部分相当于调用语句。与我们上面修改应用名字关联,修改应用名字之前就把变量修改了。需要注意的是:为了保持我们的代码不变,我们需要在打包完毕之后还原回变量

目的是为了下次再执行打包命令的时候不用去修改我们的代码命令如下:(注意该操作是在打包之后执行)

1 <target name="-post-compile"  depends="restoreJavaVariable">
2         <echo>restore java file variable value...</echo>
3     </target>
4     
5     <target name="restoreJavaVariable" >
6         <replace file="${basedir}/${srcdir}/${file.replace.path}/${fileName}" token="${UrlValue}" value="${UrlKey}" encoding="utf-8"/>
7         <replace file="${basedir}/${srcdir}/${file.replace.path}/${fileName}" token="${BaseRootVaue}" value="${BaseRootKey}" encoding="utf-8"/> 
8     </target>
target name="-post-compile" 与 -pre-build一样是需要我们去“重写”的,等待打包时候关联调用。

 以上就是如何修改Java文件中的变量的方法,此处有一个坑就是我的变量是静态变量,刚开始修改的时候无论我怎么修改都不起作用,但是文件已刷新我看到确实修改了,

这个问题一度让我怀疑自己、怀疑整个世界,http://blog.csdn.net/lizeyang/article/details/18218687,是这篇帖子帮我从坑里爬出来了。。。。 

所以大家要是在跟随我的一起探索的时候遇到了问题,请不要气馁,不要放弃,总会有解决办法的,我在这个过程中也不知道遇到了多少问题,毕竟我也是一只菜鸟。。。。

OK,继续我们的需求还剩下一个修改应用的包名:

 修改应用的包名有多种方式,网上有一种说法是需要目录的拷贝,这种方式我尝试了发现过程相对来说还是很繁琐的,

我尝试了一下其实修改应用的包名只是需要修改 AndroidManifest.xml包名以及java文件涉及到的包名(import、package等),如果只修改上述两处就可以达到效果那有何必要移动文件呢

我测试了,答案是可以的,以下就是现实方式:

 1 <target name="changePackName">
 2         <echo>changePackName...</echo>
 3       <!--替换AndroidManifest出现的包名 -->
 4       <replaceregexp flags="g" encoding="UTF-8" byline="true">
 5          <regexp pattern="package(.*)${old_package_name}"/>
 6          <substitution expression="package=&quot;${new_package_name}"/>
 7          <fileset dir="${basedir}" includes="AndroidManifest.xml"/>
 8        </replaceregexp>
 9       <!--替换工程中出现的包名 -->
10       <replaceregexp flags="g" encoding="UTF-8" byline="true">
11          <regexp pattern="import(.*)${old_package_name}.R"/>
12          <substitution expression="import ${new_package_name}.R"/>
13          <fileset dir="${basedir}/src" includes="**/*.java"/>
14        </replaceregexp>
15   </target>

如果想在打包之后还原回去之后就想修改java变量那样逆着操作一次就OK了,但是要注意 denpends,是要编译完或者打包完成之后操作。 

 

至此我们的需求就基本已经完成了,下面我贴出主要的两个文件 ant.properties、custom_rules.xml

 ant.properties:

 1 #在此文件中定义我们使用到的属性,中文的话需要转成UTF-8编码,可以使用JDK自带的native2ascii工具转码
 2 
 3 #包名  
 4 application.package=com.tai.antpackage
 5 #项目名,缺省时源码文件名  
 6 ant.project.name=Autopackage
 7 #编码方式  
 8 #java.encoding=utf-8 
 9  
10 #编译输出绝对路径  
11 out.absolute.dir=d:/MySelf/out
12 #生成文件绝对路径  
13 gos.path=d:/MySelf/out
14 
15 
16 #签名key文件绝对路径  
17 key.store=D:/MySelf/a.keystore
18 #签名文件密码  
19 key.store.password=123456
20 #签名别称
21 key.alias=auto1
22 #签名别称密码  
23 key.alias.password=123456
24 
25 basedir=D:/MySelf/AntPackage
26 xmltasklib.dir=libs
27 manifest.file=AndroidManifest.xml
28 project.name=NewProjectName
29 android.icon=@drawable/ic_launchernew
30 android.app_name=NewProjectName2
31 
32 srcdir=src
33 outdir=bin
34 file.replace.path=com/tai/antpackage/constants/
35 fileName=HttpConstants.java
36 
37 UrlKey=${URL}
38 BaseRootKey=${BASEROOT}
39 UrlValue=http://www.cnblogs.com/mauiie/p/5684374.html
40 BaseRootVaue = cnblogs
41 
42 old_package_name =com.tai.antpackage
43 new_package_name =com.tai.mauiie

custom_rules.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project name="custom_rules">
 3     <path id="xmltask.classpath">  
 4          <pathelement path="${basedir}/${xmltasklib.dir}/xmltask.jar" />  
 5     </path>
 6     
 7     <taskdef name="xmltask" classname="com.oopsconsultancy.xmltask.ant.XmlTask" classpathref="xmltask.classpath"/>  
 8     <target name="-pre-build" depends="changeLogo"> 
 9         <echo>do something others</echo>  
10     </target>
11     
12     <target name="changeLogo" depends="changeName" >
13         <echo>changelogo...</echo>  
14         <xmltask source="${basedir}/${manifest.file}" dest="${basedir}/${manifest.file}" encoding="utf-8" >
15             <attr path="//manifest/application" attr="android:icon" value="${android.icon}" />
16         </xmltask>
17     </target>
18     
19     <target name="changeName" depends="changeJavaVariable">
20         <echo>changeName...</echo>
21         <xmltask source="${basedir}/res/values/strings.xml" dest="${basedir}/res/values/strings.xml" encoding="utf-8" >
22             <replace path="/resources/string[@name='app_name']/text()" withText="${android.app_name}"/>
23         </xmltask>  
24     </target>
25     
26     <target name="changeJavaVariable" depends="changePackName">
27         <echo>change java file variable value...</echo>
28         <!--copy file="${basedir}/${srcdir}/${file.replace.path}/${fileName}" todir="res" /-->
29         <replace file="${basedir}/${srcdir}/${file.replace.path}/${fileName}" token="${UrlKey}" value="${UrlValue}" encoding="utf-8"/>
30         <replace file="${basedir}/${srcdir}/${file.replace.path}/${fileName}" token="${BaseRootKey}" value="${BaseRootVaue}" encoding="utf-8"/>
31         <delete dir="${basedir}/bin/classes" />
32     </target>
33     
34     <target name="-post-compile"  depends="restoreJavaVariable">
35         <echo>restore java file variable value...</echo>
36     </target>
37     
38     <target name="restoreJavaVariable" >
39         <replace file="${basedir}/${srcdir}/${file.replace.path}/${fileName}" token="${UrlValue}" value="${UrlKey}" encoding="utf-8"/>
40         <replace file="${basedir}/${srcdir}/${file.replace.path}/${fileName}" token="${BaseRootVaue}" value="${BaseRootKey}" encoding="utf-8"/> 
41     </target>
42     
43     
44     <target name="changePackName">
45         <echo>changePackName...</echo>
46       <!--替换AndroidManifest出现的包名 -->
47       <replaceregexp flags="g" encoding="UTF-8" byline="true">
48          <regexp pattern="package(.*)${old_package_name}"/>
49          <substitution expression="package=&quot;${new_package_name}"/>
50          <fileset dir="${basedir}" includes="AndroidManifest.xml"/>
51        </replaceregexp>
52       <!--替换工程中出现的包名 -->
53       <replaceregexp flags="g" encoding="UTF-8" byline="true">
54          <regexp pattern="import(.*)${old_package_name}.R"/>
55          <substitution expression="import ${new_package_name}.R"/>
56          <fileset dir="${basedir}/src" includes="**/*.java"/>
57        </replaceregexp>
58   </target>
59     
60 </project>

最新的这两个文件可能有部分配置与刚开始贴出来的不一样是因为我后面的这些是在家中完成的换了电脑。

在尝试的过程中你可能遇到

如果遇到该错误请在你SDK的tools/ant/buidl.xml中查找<property name="aapt.ignore.assets" value="" />

 把value设置为:crunch                                        <property name="aapt.ignore.assets" value="crunch" />

如果遇到别的错误不要气馁,不要放弃。

Demo 下载地址:ant 。

后面我会与想要一起学习的效果分享如何使用gradle,完成项目的自动打包。

感谢起初跟我提起这件事的小伙伴,我想做这件事很久了,久到现在使用ant已经落伍了。。。。 。 我是一个拖延症患者。。。。

 

posted @ 2016-07-19 15:45  Mauiie_娢  阅读(5963)  评论(1编辑  收藏  举报