最近由于项目需要,要在自有平台上发布若干个代码一致,但包名,版本,引用资源都不同的App。结合了一下网上查到的资料,成功的使用ant实现。
主要需求
- 重用android项目生成的build.xml来生成apk,复用它的release,debug等target
- 操作前后不需要手工对源代码进行修改,保证源代码能正常运行
- 通过build参数的不同,实现一个代码树生成多个版本的apk。
步骤
思路:
使用根目录下的build.xml 来把代码和相关文件复制到临时文件内,并进行对应版本的处理,再在临时文件夹内使用
<project name="main" default="subant">
<target name="subant">
<subant target="release"><!--subant相当于子调用-->
<property name="basedir" value="./ant_temp/"/> <!--重要:这一行指定了subant执行时的工作目录-->
<fileset dir="./ant_temp/" includes="build.xml"/><!--调用临时目录的build.xml,即项目原自带build.xml-->
</subant>
</target>
</project>
目录配置:
版本特定内容,分目录放到指定目录下:
custom_versions/{version}/yoyo_project.properties #配置的properties文件
custom_versions/{version}/res #资源目录
文件复制:
在进行apk的build之前,将代码,资源以及manifest等需要的文件复制至临时目录:
<echo message="Create temp folder ./ant_temp ..."/>
<mkdir dir="./ant_temp"/>
<echo message="Copy files to ./ant_temp ..."/>
<copy todir="./ant_temp/assets">
<fileset dir="./assets"/>
</copy>
...
<copy file="./android.keystore" tofile="./ant_temp/android.keystore"/>
<copy file="./android_build.xml" tofile="./ant_temp/build.xml"/>
<copy file="./AndroidManifest.xml" tofile="./ant_temp/AndroidManifest.xml"/>
...
对应项目的资源文件复制到临时文件来覆盖通用的资源:
<copy todir="./ant_temp/res" overwrite="true">
<fileset dir="./custom_versions/${version}/res"/>
</copy>
读取配置
复制后还需要对配置文件的内容进行修改,替换到对应的版本。首先从资源文件读取项目属性:
<loadproperties srcFile="custom_versions/${version}/yoyo_project.properties"/>
属性包括:
{u9.package}: 包名
{u9.versionName}: 版本号
{u9.versionCode}: 版本编号
{u9.channelName}: 渠道号
修改文件内容
替换文件内容目前使用的是正则来替换,如果有必要的话可以改成xpath。
对AndroidManifest.xml做制定,替换包名,版本号:
<replaceregexp
byline="true"
encoding="utf-8"
file="./ant_temp/AndroidManifest.xml"
match='package="([^"]+)"'
replace='package="${u9.package}"'/>
<replaceregexp
encoding="utf-8"
flags="s"
file="./ant_temp/AndroidManifest.xml"
match='versionCode="[^"]+".+versionName="[^"]+"'
replace='versionCode="${u9.versionCode}" versionName="${u9.versionName}"'/>
<replaceregexp
byline="true"
encoding="utf-8"
file="./ant_temp/AndroidManifest.xml"
match='android:authorities="([^"]+)"'
replace='android:authorities="${u9.package}\.downloads"'/>
<replaceregexp
encoding="utf-8"
file="./ant_temp/AndroidManifest.xml"
flags="s"
match='android:name="UMENG_CHANNEL".+android:value="([^"]+)"'
replace='android:name="UMENG_CHANNEL" android:value="${u9.channel}"'/>
由于包名换了,所以需要替换代码内的R文件引用路径:
<replaceregexp
match='import (.+)\.R;'
encoding="utf-8"
replace='import ${u9.package}.R;'>
<fileset dir="./ant_temp/src">
<include name="**/*.java"/>
</fileset>
</replaceregexp>
替换完成后调用之前的ant任务。
完整Ant文件:
<?xml version="1.0" encoding="UTF-8"?>
<project name="YoYoMain" >
<echo message="Create temp folder ./ant_temp ..."/>
<mkdir dir="./ant_temp"/>
<mkdir dir="./build"/>
<echo message="Copy files to ./ant_temp ..."/>
<copy todir="./ant_temp/assets">
<fileset dir="./assets"/>
</copy>
<copy todir="./ant_temp/jni">
<fileset dir="./jni"/>
</copy>
<copy todir="./ant_temp/libs">
<fileset dir="./libs"/>
</copy>
<copy todir="./ant_temp/obj">
<fileset dir="./obj"/>
</copy>
<copy todir="./ant_temp/res">
<fileset dir="./res"/>
</copy>
<copy todir="./ant_temp/src">
<fileset dir="./src"/>
</copy>
<copy file="./android.keystore" tofile="./ant_temp/android.keystore"/>
<copy file="./ant.properties" tofile="./ant_temp/ant.properties"/>
<copy file="./android_build.xml" tofile="./ant_temp/build.xml"/>
<copy file="./AndroidManifest.xml" tofile="./ant_temp/AndroidManifest.xml"/>
<copy file="./lint.xml" tofile="./ant_temp/lint.xml"/>
<copy file="./custom_versions/custom_rules.xml" tofile="./ant_temp/custom_rules.xml"/>
<copy file="./project.properties" tofile="./ant_temp/project.properties"/>
<copy file="./proguard-project.txt" tofile="./ant_temp/proguard-project.txt"/>
<loadproperties srcFile="custom_versions/${version}/yoyo_project.properties"/>
<copy todir="./ant_temp/res" overwrite="true">
<fileset dir="./custom_versions/${version}/res"/>
</copy>
<echo message="Rewrite AndroidManifest.xml"/>
<replaceregexp
byline="true"
encoding="utf-8"
file="./ant_temp/AndroidManifest.xml"
match='package="([^"]+)"'
replace='package="${u9.package}"'/>
<replaceregexp
encoding="utf-8"
flags="s"
file="./ant_temp/AndroidManifest.xml"
match='versionCode="[^"]+".+versionName="[^"]+"'
replace='versionCode="${u9.versionCode}" versionName="${u9.versionName}"'/>
<replaceregexp
byline="true"
encoding="utf-8"
file="./ant_temp/AndroidManifest.xml"
match='android:authorities="([^"]+)"'
replace='android:authorities="${u9.package}\.downloads"'/>
<replaceregexp
encoding="utf-8"
file="./ant_temp/AndroidManifest.xml"
flags="s"
match='android:name="UMENG_CHANNEL".+android:value="([^"]+)"'
replace='android:name="UMENG_CHANNEL" android:value="${u9.channel}"'/>
<replaceregexp
match='import (.+)\.R;'
encoding="utf-8"
replace='import ${u9.package}.R;'>
<fileset dir="./ant_temp/src">
<include name="**/*.java"/>
</fileset>
</replaceregexp>
<target name="subant">
<subant target="release">
<property name="basedir" value="./ant_temp/"/>
<property name="final_name" value="YoYo-${u9.channel}-${u9.versionName}.apk"/>
<fileset dir="./ant_temp/" includes="build.xml"/>
</subant>
</target>
</project>
调用:
build版本的时候如下:
ant -Dversion=official #版本所在的目录名称
即可。