您的位置:首页 > 移动开发 > Android开发

Android项目自动批量打包之程序实现

2014-12-12 12:26 489 查看
  http://blog.sina.com.cn/s/blog_6d8459b901011ddc.html
因为需要记录不同渠道下apk的使用情况,每一个渠道对应的apk都需要附带自己的渠道号。而当你手动完成92个渠道的打包时,切腹的心都有了!!

现在的任务就是:实现项目的自动更改配置文件的渠道号,自动完成打包,签名工作。 
开始的解决方案是,使用ant完成自动打包。据说这个方案是可行的,尝试了N多次build.xml的配置,始终运行出错,以后再慢慢研究吧。
下面详细讲解我的实现方案:首先普及下,如何手动实现一个android项目的编译,打包,签名的过程。为了看到效果,先把eclipse的自动编译开关去掉。新建一个Android工程。里面除了源码什么都没有了,eclipse也没有帮你编译生成R文件和class文件。开启命令行:第一步:使用aapt工具生成R文件命令行进入工程目录:aapt package -f -m -J gen\(指定R文件存放目录) -S res\ -M AndroidManifest.xml -I ../android-8/android.jar  参数的意思应该不用解释了。执行命令,会看到再gen/目录下生成了对应资源的R文件。第二步:使用javac编译java文件javac -encoding utf-8 -target 1.5 -d bin/ src/../../../*.java gen/*.java -bootclasspath ../{sdk-path}/android-8/android.jar 
第三步:class文件已经生成,使用dx工具将所有class打包生成dex文件。dx.bat --dex --output=bin/classes.dex bin/classes/如果有第三方jar包,需要将jar一并打入到dex文件中。 在命令后面再附带jar的路径。如:dx.bat --dex --output=bin/classes.dex bin/classes/ libs/***.jar
第四步:dex已经有了,但这些都是java文件编译而成。所以还需要将对应的资源文件打包生成resources.ap_ 文件。依然使用aapt工具aapt package -f -M AndroidManifest.xml -S res/ -A assets/ -I ../{sdk-path}/android-8/android.jar -F bin/resources.ap_第五步:将resource和dex封装到一起。生成未签名apk文件。使用apkbuilder工具apkbuilder bin/unsigned.apk -u -z bin/resources.ap_ -f bin/classes.dex -rf src/如果引入了第三方jar包,还需要加入jar包的引用。在命令的最后加上: -rj libs/
第六步:对未签名的apk进行签名。使用jarsigner 工具jarsigner -keystore {keystore path} -storepass *** -keypass {alias pass} -signedjar e:\signed.apk bin/unsigned.apk {alias name}
到此,手动对一个Android工程的编译,打包,签名就完成了。 而我的方案也就出来了。 每个不同的渠道包有一个不同的渠道属性。 可以通过文件流操作循环改变这个这个属性的值。 每次改变完成之后,在程序中调用命令,完成项目的打包签名工作。下面看具体实现:我的项目中渠道号是写在strings.xml文件中。其实任何地方都可以,只要你的工程能引用到。因为eclipse能够自动编译,所以我们省去了很多麻烦。不需要手动生成R文件,不需要手动编译java文件。 
因为需要替换strings文件中的字段,在strings中设置一个标记变量%channel%,当读取到这个标记时,将标记替换成指定的值。先将strings文件做一个临时备份。读取临时文件,读取的同时修改渠道号并将新的文件写入到res/values/strings.xml 目录下。(读取时,因为strings文件有很多中文,注意编码问题)下面看具体代码实现:public static final String PROJECT_PATH = "D:\\workspace\\Idea123_v3\\"; //工程的具体路径。后面很多地方会用到
public static void main(String[] args) {  int minChannel = 10, maxChannel = 20;  // 设置最小渠道,最大渠道号  try {  Process process = Runtime.getRuntime().exec("D:\\android-sdk-windows\\platform-tools\\dx.bat --dex --output="+PROJECT_PATH+"bin\\classes.dex "+PROJECT_PATH+"bin\\classes\\  +"PROJECT_PATH"+libs\\pinyin4j-2.5.0.jar" ); process.waitFor(); process.destroy();  // 先完成class--》dex的打包。因为java文件未曾改变过,所以打包一次就够。 replaceChannel(minChannel, maxChannel); // 替换渠道号System.out.println("batch pack finished!");  } catch (IOException e) {  e.printStackTrace();  } catch (InterruptedException e) { e.printStackTrace(); } } 

public static void replaceChannel(int minChannel, int maxChannel) {try {String outPath = PROJECT_PATH + "res\\values\\strings.xml"; //输出文件位置String tempPath = "e:\\temp.xml"; //临时文件位置BufferedReader reader;BufferedWriter writer;for (int channelid = minChannel; channelid <= maxChannel; ++channelid) {String line = null;reader = new BufferedReader(new FileReader(tempPath));writer = new BufferedWriter(new FileWriter(outPath));while ((line = reader.readLine()) != null) {if (line.contains("%channel%"))line = line.replace("%channel%", channelid + "");//设置渠道号writer.write(line + "\r\n");writer.flush();}writer.close();reader.close();generatePackage(channelid); // 一次渠道号的更改完成。可以进行打包了。}} catch (Exception e) {e.printStackTrace();}}

public static void generatePackage(int channelid) {try {Process process = null ;process = Runtime.getRuntime().exec("D:\\android-sdk-windows\\platform-tools\\aapt package -f -M "+PROJECT_PATH+"AndroidManifest.xml -S "+PROJECT_PATH+"res -A "+PROJECT_PATH+"assets -I D:\\android-sdk-windows\\platforms\\android-8\\android.jar -F "+PROJECT_PATH+"bin\\resources.ap_"); // 将资源文件打包resources.ap_process.waitFor();process.destroy();process= Runtime.getRuntime().exec("D:\\android-sdk-windows\\tools\\apkbuilder.bat "+PROJECT_PATH+"bin\\Idea123_unsigned.apk -u -z "+PROJECT_PATH+"bin\\resources.ap_ -f "+PROJECT_PATH+"bin\\classes.dex -rf "+PROJECT_PATH+"src -rj "+PROJECT_PATH+"\\libs"); // 生成未签名的apkprocess.waitFor();process.destroy();process = Runtime.getRuntime().exec("jarsigner -keystore E:\\idea123 -storepass *** -keypass *** -signedjar E:\\test_apk\\Idea123_"+channelid+".apk "+PROJECT_PATH+"bin\\Idea123_unsigned.apk idea123"); //对apk进行签名process.waitFor();process.destroy();System.out.println(channelid+" finished..."); // 一条渠道的打包完成。文件会输出到指定目录} catch (Exception e) {e.printStackTrace();}}
ok! 批量打包的简单实现就此完成。代码有待优化,欢迎指正。

这短短一个月就像历经了一年那么漫长。生活的变化总是发生的太快太突然,几乎让我无暇应接。最无奈的是发现所有的事决定权都不在自己手上,你只能被迫接受。唯一能安慰自己的就是,既然过去的不能被改变,那我必须轻松的面对将来。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: