最近看到公司IOS的同事做了一个app打包工具给QA使用,极大的方便了QA的工作,也给开发节省了不少精力,不需要频繁的接收QA的要求给QA打包新app做测试,防止编程思路被打包这些琐事给打断。
为了编写方便和跨平台应用,我使用了网页版的交互方式,使用tomcat 8做服务器,这样可以让任意一台手机和电脑通过浏览器就可以轻松的打包然后收到相应的.app文件,界面大概是这个样子
最近整理了一下写了一个Demo,github源码地址:https://github.com/AlexZhuo/AndroidOnlinePackage
主要的功能是这样的
1、可以自由切换分支,分支号通过下拉列表的形式显示在网页上
2、可以自由切换服务器环境,比如测试服,开发服,正式服等等,上图的staging,dev,live就属于服务器
3、可以自动拉取git分支最新代码
4、可以自动进行apk的签名,apk对齐
大体思路是这样:
1、关于切换分支
因为不同git分支的上的代码不一样,有些依赖库也不一样,通过git命令行直接克隆分支然后用gradle编译是不行的,因为直接克隆下来的代码,尤其是一些iml配置文件在本机是不能直接用的,而且有些依赖库是以com.google.xxx.xxx这样的方式写在gradle.xml里的,这些依赖库本身需要联网进行下载,另外不同的分支用的gradle版本也不一样,需要下载对应的gradle,所以使用一个git 仓库通过check分支来切换这种方式行不通。所以我使用的多个git仓库,每个git仓库放一个分支的代码,切换分支实际上就是通过切换不同的git仓库实现的。这样做之后,下载依赖库和重写iml文件就交给Android Studio来进行,说白了就是克隆完一个分支之后,先用Android Studio先clean一遍,再用AS打一个apk,这样这个git仓库就和本机的配置契合,可以被命令行打包了。
2、关于切换环境
因为这个项目里服务器的ip地址写死在了.java文件里面,所以只要修改相关java文件里面的ip地址就可以实现服务器的切换。所以我在这里是将各个写有不同ip地址的java文件放在git仓库之外,当打包时根据要打包的环境动态替换项目目录中的.java文件实现环境的切换。
3、关于pull代码,签名,对齐,这些通过直接的git命令和gradle命令执行就好了
4、关于进度的提示:
因为gradle在编译的时候对CPU和内存的开销很大,所以一次只能有一个编译进程执行,所以我就把进度直接用一个静态保存了,获取进度直接获取这个静态的变量的值就行。
在web端就做的很简单,用http请求每隔两秒进行轮询,没有采用高大尚的socket通讯。
先来复习一下gradle相关的命令行指令吧
打包指令:
首先cd到项目根目录下,就是有gradlew.bat这个文件的那个目录,然后执行(gradle命令比Eclipse打包容易多了)
gradle bulid
或 gradlew build
或 gradlew clean build
keytool -genkeypair -alias mykeyName -keyalg RSA -validity 100 -keystore mydemo.keystore
myKeyName是生成签名文件的别名,非常重要,100是有效期,mydemo.keystore是签名文件的文件名,执行完这一条指令会让你输入一个密码,注意区别密码和前面“alias”(别名)的区别,不要搞混,当时我就搞混了然后浪费了很多时间,下面三张图显示了alias和password的在eclipse和Android Studio打包签名时的截图,帮助你区别alias和password
对apk进行签名:
jarsigner -verbose -keystore E:\QA\file\key -signedjar app-signed.apk -digestalg SHA1 -sigalg MD5withRSA app-release-unsigned.apk mkeyName
首先cd到存放gradle编译好的未签名的apk的目录下
-digestalg SHA1 -sigalg MD5withRSA是非常重要的,我使用jdk1.8签名后Android 5.0以上机器可以跑,但是5.0一下的机器就装不上,网上说使用jdk1.6以上版本会出现这个签名问题,所以如果你的电脑上装的是jdk1.6以上版本,别忘了加上这句。
对签名好的文件进行对齐,传说对齐可以让安卓系统访问apk包里的资源更快,具体怎样没试过,我对齐apk以后发现apk的大小变大了
首先cd到签名好的apk文件的目录下
zipalign -f -v 4 app-signed.apk app-publish.apk
app-signed.apk是签名好的文件,app-publish.apk是对齐好后生成的新文件
再来复习一下git指令:
撤销本地某个文件的修改,注意--后面有一个空格
git checkout -- <要撤销的文件完整路径>
git reset --hard <某次commit的SHA码>
git commit --amend -m "我要修改的消息内容"
撤销一个已经push的commit
git revert <待撤销commit的SHA码><pre name="code" class="plain">git push origin HEAD --force
删除未跟踪的文件
git clean -fd
$ git checkout *.java
代码时间:
首先是最核心的文件,也就是执行具体命令行指令的java文件
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.SequenceInputStream;
public class PackageNow {
//记录每个分支git仓库的地址
public static final String[] BRANCH_0 = {"E:\\QA\\master\\app3","master"};//第0个分支的相关信息,第一个是位置,第二个是分支号,第三个是编译器位置
public static final String[] BRANCH_1 = {"E:\\QA\\branch1\\app3","QRAII-6916"};//第0个分支的相关信息,第一个是位置,第二个是分支号,第三个是编译器位置
public static final String[] BRANCH_2 = {"E:\\QA\\branch2\\app3","QRAII-sprint8"};//第0个分支的相关信息,第一个是位置,第二个是分支号,第三个是编译器位置
public static final String[][] BRANCHES = {BRANCH_0,BRANCH_1,BRANCH_2};
public static final String GIT_ROOT = "http://username:[email protected]/AlexZhuo/AlxImageLoader";//外网的git 地址
public static final String APK_PATH = "\\app\\build\\outputs\\apk";//进入项目目录后,gradle编译完成后输出apk的目录
//下面是编译完后生成apk的文件名
public static final String APP_DEBUG = "app-debug.apk";//打了默认签名的apk
public static final String APP_SIGNED = "app-signed.apk";//打了正式签名,但是没有4k对齐的apk名字
public static final String APP_PUBLISH = "app-publish.apk";//打了正式签名,且对齐了的apk名字
//用于签名apk的签名文件的路径
public static final String KEY_PATH = "E:\\QA\\file\\key";
//要根据不同服务器环境替换文件的路径
public static final String LIVE_FILE = "E:\\QA\\file\\live\\Config.java";//记录live环境的java文件的路径,准备用于替换
public static final String STAGING_FILE = "E:\\QA\\file\\staging\\Config.java";
public static final String DEV_FILE = "E:\\QA\\file\\dev\\Config.java<span style="font-size: 12px; font-family: Arial, Helvetica, sans-serif;">";</span>
public static final String ALPHA1_FILE = "E:\\QA\\file\\alpha1\\Config.java";
public static final String ALPHA2_FILE = "E: