使用 Ant 实现批量打包Android应用
由于公司运维需要以及应用中需要加上应用推广的统计,往往要对应二三十个渠道,按照正常方法一个一个的去生成不同渠道包的应用,不仅浪费了时间,而且大大降低了效率.
上一篇讲到使用Ant进行Zip/Tar包的解压缩,实际上Ant工具不仅仅具有此类功能,它更强大的地方在于自动化调用程序完成项目的编译,打包,测试等. 类似于C语言中的make脚本完成这些工作的批处理任务. 不同于MakeFile的是,Ant是纯Java编写的,因此具有很好的跨平台性.
在此我主要讲下如何自动构建工具Ant, 对应用进行批量打包, 生成对应不同市场的应用:
首先分别看一下用于打包的Java工程AntTest和需要被打包进行发布的Android工程结构:
market.txt里保存需要打包的市场标识,如:
youmeng
gfan
.......
此文件里自行根据需求添加渠道名称.
然后看一下实现批量打包AntTest类中的内容:
注意:红色标注部分需要进行修改:
- packagecom.cn.ant;
- importjava.io.BufferedReader;
- importjava.io.BufferedWriter;
- importjava.io.File;
- importjava.io.FileReader;
- importjava.io.FileWriter;
- importjava.io.IOException;
- importjava.text.SimpleDateFormat;
- importjava.util.Calendar;
- importorg.apache.tools.ant.DefaultLogger;
- importorg.apache.tools.ant.Project;
- importorg.apache.tools.ant.ProjectHelper;
- publicclassAntTest{
- privateProjectproject;
- publicvoidinit(String_buildFile,String_baseDir)throwsException{
- project=newProject();
- project.init();
- DefaultLoggerconsoleLogger=newDefaultLogger();
- consoleLogger.setErrorPrintStream(System.err);
- consoleLogger.setOutputPrintStream(System.out);
- consoleLogger.setMessageOutputLevel(Project.MSG_INFO);
- project.addBuildListener(consoleLogger);
- //Setthebasedirectory.Ifnoneisgiven,"."isused.
- if(_baseDir==null)
- _baseDir=newString(".");
- project.setBasedir(_baseDir);
- if(_buildFile==null)
- _buildFile=newString(projectBasePath+File.separator
- +"build.xml");
- //ProjectHelper.getProjectHelper().parse(project,new
- //File(_buildFile));
- <spanstyle="color:#FF0000;">//关键代码</span>
- ProjectHelper.configureProject(project,newFile(_buildFile));
- }
- publicvoidrunTarget(String_target)throwsException{
- //Testiftheprojectexists
- if(project==null)
- thrownewException(
- "Notargetcanbelaunchedbecausetheprojecthasnotbeeninitialized.Pleasecallthe'init'methodfirst!");
- //Ifnotargetisspecified,runthedefaultone.
- if(_target==null)
- _target=project.getDefaultTarget();
- //Runthetarget
- project.executeTarget(_target);
- }
- <spanstyle="color:#FF0000;">privatefinalstaticStringprojectBasePath="D:\\android\\workspace3\\XXX";//要打包的项目根目录
- privatefinalstaticStringcopyApkPath="D:\\android\\apktest";//保存打包apk的根目录
- privatefinalstaticStringsignApk="XXX-release.apk";//这里的文件名必须是准确的项目名!
- privatefinalstaticStringreNameApk="XXX_";//重命名的项目名称前缀(地图项目不用改)
- privatefinalstaticStringplaceHolder="@[email protected]";//需要修改manifest文件的地方(占位符)
- </span>
- publicstaticvoidmain(Stringargs[]){
- longstartTime=0L;
- longendTime=0L;
- longtotalTime=0L;
- Calendardate=Calendar.getInstance();
- SimpleDateFormatsdf=newSimpleDateFormat("yyyy-MM-dd:HH:mm:ss");
- try{
- System.out.println("---------ant批量自动化打包开始----------");
- startTime=System.currentTimeMillis();
- date.setTimeInMillis(startTime);
- System.out.println("开始时间为:"+sdf.format(date.getTime()));
- BufferedReaderbr=newBufferedReader(newFileReader("market.txt"));
- Stringflag=null;
- while((flag=br.readLine())!=null){
- //先修改manifest文件:读取临时文件中的@[email protected]修改为市场标识,然后写入manifest.xml中
- StringtempFilePath=projectBasePath+File.separator
- +"AndroidManifest.xml.temp";
- StringfilePath=projectBasePath+File.separator
- +"AndroidManifest.xml";
- write(filePath,read(tempFilePath,flag.trim()));
- //执行打包命令
- AntTestmytest=newAntTest();
- mytest.init(projectBasePath+File.separator+"build.xml",
- projectBasePath);
- mytest.runTarget("clean");
- mytest.runTarget("release");
- //打完包后执行重命名加拷贝操作
- Filefile=newFile(projectBasePath+File.separator+"bin"
- +File.separator+signApk);//bin目录下签名的apk文件
- FilerenameFile=newFile(copyApkPath+File.separator+reNameApk
- +flag+".apk");
- booleanrenametag=file.renameTo(renameFile);
- System.out.println("rename------>"+renametag);
- System.out.println("file------>"+file.getAbsolutePath());
- System.out.println("rename------>"+renameFile.getAbsolutePath());
- }
- System.out.println("---------ant批量自动化打包结束----------");
- endTime=System.currentTimeMillis();
- date.setTimeInMillis(endTime);
- System.out.println("结束时间为:"+sdf.format(date.getTime()));
- totalTime=endTime-startTime;
- System.out.println("耗费时间为:"+getBeapartDate(totalTime));
- }catch(Exceptione){
- e.printStackTrace();
- System.out.println("---------ant批量自动化打包中发生异常----------");
- endTime=System.currentTimeMillis();
- date.setTimeInMillis(endTime);
- System.out.println("发生异常时间为:"+sdf.format(date.getTime()));
- totalTime=endTime-startTime;
- System.out.println("耗费时间为:"+getBeapartDate(totalTime));
- }
- }
- /**
- *根据所秒数,计算相差的时间并以**时**分**秒返回
- *
- *@paramd1
- *@paramd2
- *@return
- */
- publicstaticStringgetBeapartDate(longm){
- m=m/1000;
- Stringbeapartdate="";
- intnDay=(int)m/(24*60*60);
- intnHour=(int)(m-nDay*24*60*60)/(60*60);
- intnMinute=(int)(m-nDay*24*60*60-nHour*60*60)/60;
- intnSecond=(int)m-nDay*24*60*60-nHour*60*60-nMinute
- *60;
- beapartdate=nDay+"天"+nHour+"小时"+nMinute+"分"+nSecond+"秒";
- returnbeapartdate;
- }
- publicstaticStringread(StringfilePath,StringreplaceStr){
- BufferedReaderbr=null;
- Stringline=null;
- StringBufferbuf=newStringBuffer();
- try{
- //根据文件路径创建缓冲输入流
- br=newBufferedReader(newFileReader(filePath));
- //循环读取文件的每一行,对需要修改的行进行修改,放入缓冲对象中
- while((line=br.readLine())!=null){
- //此处根据实际需要修改某些行的内容
- if(line.contains(placeHolder)){
- line=line.replace(placeHolder,replaceStr);
- buf.append(line);
- }else{
- buf.append(line);
- }
- buf.append(System.getProperty("line.separator"));
- }
- }catch(Exceptione){
- e.printStackTrace();
- }finally{
- //关闭流
- if(br!=null){
- try{
- br.close();
- }catch(IOExceptione){
- br=null;
- }
- }
- }
- returnbuf.toString();
- }
- /**
- *将内容回写到文件中
- *
- *@paramfilePath
- *@paramcontent
- */
- publicstaticvoidwrite(StringfilePath,Stringcontent){
- BufferedWriterbw=null;
- try{
- //根据文件路径创建缓冲输出流
- bw=newBufferedWriter(newFileWriter(filePath));
- //将内容写入文件中
- bw.write(content);
- }catch(Exceptione){
- e.printStackTrace();
- }finally{
- //关闭流
- if(bw!=null){
- try{
- bw.close();
- }catch(IOExceptione){
- bw=null;
- }
- }
- }
- }
- }
然后是Android工程中需要进行修改的部分:
1. 修改local.properties中的sdk根目录:
sdk.dir=D:\\android\\android-sdk-windows-r17\\android-sdk-windows-r17
2. 修改ant.properties中签名文件的路径和密码(如果需要)
key.store=D:\\android\\mykeystore
key.store.password=123456
key.alias=mykey
key.alias.password=123456
3. 修改AndroidManifest.xml.temp
拷贝AndroidManifest.xml一份,命名为AndroidManifest.xml.temp
将需要替换的地方改为占位符,需与打包工程AntTest中的placeHolder常量一致
如: <meta-data android:value="@[email protected]" android:name="UMENG_CHANNEL"/>
4. Build.xml中:
<project name="XXX" default="help">,XXX必须为Android工程名称.
如果机器没有配置过Ant环境变量,可根据如下步骤进行配置:
Windows下ANT用到的环境变量主要有2个,ANT_HOME 、PATH。
设置ANT_HOME指向ant的安装目录。
设置方法:
ANT_HOME = D:/apache_ant_1.7.0
将%ANT_HOME%/bin; %ANT_HOME%/lib添加到环境变量的path中。
设置方法:
PATH = %ANT_HOME%/bin; %ANT_HOME%/lib