零蚀
目录
🔗 前言
🔗 Android 知识栈
🔗 Android 散装系列
🔗 NO.1 Handler->就这?
🔗 NO.2 Android 垃圾回收机制
🔗 NO.3 Android 测量、排版那点事
🔗 NO.5 EventBus 浅谈
问题出现
-
矛盾出现
-
本来是一个愉快的周五,公司里大家都普遍认为,周五要带着愉快的心情来看看今天有没有小bug,缓一缓最近的工作进度,为这一周做个总结,然后考虑一下,这周末的安排,但是,我还没想好端午节该学点啥时,产品突然来让我打个包,打包一般是一个比较死板的活,只要知道对应的命令即可,当然,打渠道包有时也很麻烦(在没有一件打包的情况下)。
-
公司用的是walle,打包的方式,打包前要先去解注自己要打的渠道,然后,选择自己打包的命令,才能打包,我在网上也搜了很多教程,但是没有一个可以用的一件打包,然后就是因为网上没有一个可用的一键打包,即使可用,也是要很多操作。所以在痛苦的整了1个小时后,没有找到合适的方法,只能手动打包了。具体流程如下所示,我们要现在channel中释放自己的渠道(第一次还打错了)。
-
但是,问题来了,如果产品哪天突然来说,给我来20个包,想必就不快乐了吧,感觉心里满满的不爽,也许你说,我现在的项目有更先进的库,但是如果你要处理一个老项目,像我这样,只能靠一个一个手动来处理怎么办,所以万事不如写脚本。
-
构建思路
-
三步走
-
step 1: 将build的临时文件全部清理掉,这个主要是删除之前的包,防止打包时候还有些我不要的,还要挑。
-
step 2: 将channel里面的渠道进行选择性的注释和释放,这个必须有,相比于手动注释、释放渠道来说,这个必须要解放双手,不然,自己弄着弄着都不知道自己做了啥。打包打一半发现注释的和打包命令对不上,多难过啊,还不知道之前有没有遗漏的错。
-
step 3: 匹配gradle命令,循环进行打包,这个主要通过gradlew来实现
-
-
脚本语言的选择
-
这里我第一个想到的是shell,为什么选择shell脚本,因为mac里一直用的就是shell命令,自来熟,而且这个比较好用,因为设计中是要调用
gradlew
命令的,对于shell这方面我觉得对于我更简单。当然shell有个非常好的有点,就是mac和window可以通用,只要你有git,你就有bash,你就可以用bash。 -
然后我第二个想到的是python,python最大的好处是可以做pyqt的界面控制,但是对于如果想调用
gradlew
这方面就不清楚了。 但是python打包是极为不方便的,window和macos是两种不同的东西,所以我想做一个,大家都方便的脚本,肯定就不能选这玩意了。
-
shell编码
-
遍历用户输入渠道号
-
首先肯定是要解决渠道号这个问题,因为我们要构建一个一次可以输入很多很多渠道号进行轮循打包的,所以要用户自己输入一连串的渠道号,我们便就好。设计思路如下:
if [[ $1 == "" ]] then echo "请输入渠道包的渠道号" exit fi # 循环便利用户输入 for i in $(seq 1 $#) do # 解码渠道号的函数 decodeChannelNum $1 shift done
-
这里我先判断第一个参数是不是为空,如果为空,说明用户没有输入,则没有渠道号,就不用打包了,然后开始遍历
$1 $2 $3
第一个、第二个、第三个参数,这里的shift是摒弃第一个参数,后面的参数位置都向前移一位。所以我们使用第二个参数时还是$1
。
-
-
打包类型
-
第二步我们要知道,我们打得是什么包,是Debug?还是Release包,所以啊,我们需要让用户自己选择。
echo "请输入参数0->打Debug包,输入1->打Release包:" read type_pkg while [[ $type_pkg != 0 && $type_pkg != 1 ]] do echo "你的参数有误,请输入参数0->打Debug包,输入1->打Release包:" read type_pkg done echo "--------------------------开始clean掉build内容--------------------------" ../gradlew clean echo "--------------------------build清理完毕--------------------------"
-
我们这里如果用户输入错误,我们需要循环提醒他,输入正确的参数,来确定打包打什么类型的。
-
-
注释掉channel 渠道号
-
我们的channel文件可能是之前用过的,可能有一些不是我们需要的渠道号被被解开了,我们需要的被注释了。而且有些渠道号后面可能还有一些注解。这样的话我们就要对shell文件操作,并多字符串进行一些处理,这在numpy上叫做洗数据😂。我们来好好洗洗数据。
-
逻辑很简单,读一行,先把所有没注释的注释掉,然后遍历,将我们需要的打开,这里
sed -i '' "$位置行数s/旧数据/新数据/"
,这代码就是将某一行的就数据,变成新数据。这里重新初始化了数据,将所有的数据注释掉。#重新整理渠道号,将没有注释的全注掉 #这里行数从0开始计数,但是命令从1开始计数 resetData(){ index=0 cat channel | while read line do let index=index+1 if [[ ${line:0:1} != "#" ]] then sed -i '' "${index}s/$line/#$line/" channel fi done index=0 }
-
然后我们要开始开放我们的渠道号,方法和上面差不多,然后渠道数据处理完毕,我们就要开始开启打包任务了。
#将对应的渠道号解封 decodeChannelNum(){ resetData index=0 cat channel | while read content do let index=index+1 temp=${content#*#} channelNum=${temp%%#*} # 去空格 if [[ $(echo $channelNum | grep "$1") != "" ]] then echo "" sed -i '' "${index}s/$content/${content:1}/" channel # 开启打包任务 packageTasks $1 fi done index=0 }
-
我们接下来要过滤命令,这步很关键,我也在这里卡了很久,好几个小时吧,不是说逻辑问题,它里面存在一个不明显的bug,一不小心就容易中招,我们先看代码。
# 遍历所有的打包任务,找到对应的打包任务的命令 packageTasks(){ dealNead=0 resultCommond="" echo $re ../gradlew tasks --all | grep -v total > outfile while read commond do if [[ $commond == $task_category ]] then dealNead=1 fi #开始洗数据 if [[ $dealNead == 1 ]] then if [[ $commond == assemble* ]] then originCommod=$(echo ${commond%%-*}) if [[ $originCommod == *Channels ]] then result=$(echo $originCommod | grep "$1") if [[ $result != "" ]] then if [[ $(echo $(packageItem $(echo $originCommod) $1)) != "" ]] then resultCommond=$originCommod fi fi fi fi fi done < outfile rm -f outfile echo "resultCommond=$resultCommond" ../gradlew $resultCommond echo "打包$(echo $resultCommond)完成" dealNead=0 }
-
这里是判断是否命令是我们需要的,首先我判断了这里有没有头部匹配的命令,然后判断了有没有尾部匹配的命令,然后判断有没有包含关键字的命令,这样保证命令的唯一性。但是细心的人会发现我这里没有用管道的方式进行循环,而是用的重定义的方式,为什么呢?
-
首先说一点,我们在遍历所有的task命令时
../gradlew tasks --all
,当这句代码没有结束的时候,我们是不可以打包,如果我们在遍历中间打包了,那么两个task将会死锁,程序就卡壳了,不要问为什么会发生,没深入研究。 -
但是我们还要明白一点,管道(
../gradlew tasks --all | while read commond
)的方式遍历,它内部是将代码放在另一个shell中跑的,不是我们运行的当前的shell,所以里面的所有的变量,不能被拿出来,只能在循环里使用,所以到这一步,gradlew 和 管道 业务逻辑上就发生了死锁,所以我们不能用管道,所以我能用重定义。 -
重定义是将
../gradlew tasks --all
所有的内容先写入一个临时文件outfile中,然后我们将outfile的内容通过重定义方式,注入while循环中,这样就可以拿到我们循环里的参数值了,当然,用完记得删除临时文件。 -
到这里一个简单的脚本就完成了,可以输个命令去喝个茶,等它自己打完。
-
总结
-
当然这个脚本还有很多问题,比如说这里的文件位置都是写死的,文件名也是写死的,当然我们的老项目的文件位置,和渠道的命名方式也是一致的,所以没有必要再优化。所以这个脚本的局限性很强。
-
除了上述问题,我们还有一个问题,就是如果项目很老,但是java版本很新是不能使用gradlew命令的,因为java和gradle版本冲突了,所以我们可以在
vi ~/.zshrc
中做一个开关,可以选择自己需要的java版本(like this)。