命令行打包android程序

  • Post author:
  • Post category:其他


因为需要记录不同渠道下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