因为需要记录不同渠道下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"); // 生成未签名的apk 

 process.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(); 

 } 
}


android update project -p D:\GSW-1.1.0 -t "Google Inc.:Google APIs:14" -n Warriors

 ant clean


 D:\developsoft\android-sdk\platforms\android-14\android.jar

 aapt package -f -m -J gen -S res\ -M AndroidManifest.xml -I D:\developsoft\android-sdk\platforms\android-14\android.jar