今天我们来谈一谈用python做Android项目自动化构建的过程。我们知道在常规的Android开发过程中,开发人员打包的时候需要在Android Studio当中进行,或者通过gradle命令,但是这样的过程不够灵活,最起码它难以满足我们的以下几个需求:

1、如果你公司应用有多个代理商,而且每个代理商在logo,启动页等方面有个性化的需求,而且需要经常打包的情况,这个时候开发人员就不得不经常性的更改代码,替换资源,而且还很容易出错。

2、传统的打包的操作必须要由开发人员来执行,每一次改动都要麻烦开发人员来重新打包,并且开发人员必须要一直关注着Android Studio的打包情况,没有个性化的消息提醒机制。

3、一个应用如果需要做多个代理商打包的情况,那么就需要给每一个代理商在app目录下面建立他独有的文件夹,里面包含该代理商的图片资源或者配置信息,会使得整个代码的目录结构看起来很糟糕,如下图所示:

为了解决这些痛点,我们今天要来实现自动化打包,我们先看一下最终的实现效果再来深入讨论该功能的技术实现,首先我们看到的是一个web页面,这个页面你在任何地方都可以登录:

web页面上有提交资料,打包,下载等功能,顺序是这样的:首先用户提交资料,提交的资料都是每个代理商个性化 的内容,如下图所示:

用户资料上传成功后,点击web页面上的打包项目就可以进行Android项目打包过程,ok,然后你就可以去喝咖啡了,等在钉钉上收到消息了再回来下载吧,如下图所示:

至此,这个Android的自动化打包的过程就结束了。

纳尼?我还没反应过来就这么结束了?没错,就是这么简单,这个过程将需要改变应用的用户,测试人员,开发人员都独立开来,在一定程度上提高了协作效率,还是很有借鉴意义,下面我就和大家分享一下我的实现过程。

在这里由于我们摒弃了Android Studio打包,我采用了python来处理中间的逻辑,一是因为python本身是一门非常容易上手的语言,二是因为公司是做文本大数据的,python高手很多,到时候有搞不定的问题可以找他们嘛。说干就干,我花了一天的时间学习了python的基本语法后就开整了。

构建过程全部都是在Mac上面进行,主要是方便执行python和shell命令,在这片文章中我就不再赘述Linux或者Unix服务器上如何安装jdk,Android SDK, gradle的问题了。在这里我可以告诉大家一个最快速的方法。你可以现在如Mac上下载Android Sutido运行一个Android项目,然后再去设置中看这些东西的路径,这样就方便多了。由于Android Studio内置jdk,因此脱离Android Studio运行项目的时候,需要自己安装jdk。

整个自动化的核心流程是这样的:

1、python接收来自前端web页面的数据,包括代理商List,图片路径,微信分享id,QQ分享id等。(下面讨论的过程中我假设web端的数据已经传到python服务中来,图片也放到了Mac机器上,不讨论这个过程的实现原理,这个也不是我们的重点。)

2、从svn服务器checkout代码到mac机器上。

3、遍历代理商List,循环进行打包操作。

4、将每个代理商的图片资源放到指定的目录。

5、动态修改string.xml等配置文件。

6、执行打包命令。

7、打包结果发送到阿里钉钉。

8、打包成功的apk上传到蒲公英,并下载图片链接发送到阿里钉钉中。

这就是自动化打包的整个流程,下面我们来细细分析一下每个都是怎么实现的,如果在阅读下面的过程中有困难的话,建议去看一下python的基础知识。这个应该不会花太多时间,一天时间足矣。

如果要做自动化处理我有这么几个问题需要考虑:

1、多个代理商打包项目代码总共需要多少份呢?首先我必须要从svn服务器上checkout一份代码到本地,为了避免多次下载项目代码的情况,于是我决定只checkout一次,然后其他代理商打包的时候依次覆盖之前的代码和资源。python从svn checkout代码部分截图如下:

2、为了便于理解,代理商的数据我们以JSONArray的形式举一个例子,如下图:

3�、python提倡以模块和函数的形式构建代码,因此把每一个代理商的打包过程提取成函数:

4、代理商资源图片动态放到drawable和mipmap等目录。在这之前,用户已经在web端上传了相关图片资源,这些图片资源经过一些的处理已经放置在了我们Mac机器上面本地目录下:

在这里我再插播另外一个知识点,我们知道Android Studio项目当中有drawable和mipmap文件夹,都是可以用来放图片的,那么他们有什么区别呢?根据google官方的介绍,google推荐将launcher icon放在mipmap目录中,其他的图片都还是应该放在drawable目录下面的。注意,mipmap对图片进行了很好的优化,只是针对launcher icon的,我们只能在AndroidMainfest.xml才能使用,有兴趣的朋友可以去网上查阅相关资料。

5、动态修改strings.xml的值:

解析xml过程中你看到的ET是这样引入的:

import xml.etree.ElementTree as ET

在这里需要着重注意的一点是:解析完xml后一定要进行保存更改,在这里我将它写回到了原始的xml文件中。

6、执行打包命令,并将到是否成功的消息发送到阿里钉钉上面:

在这里打包命令中的gradle assembleRelease中的gradle我配置的是本地gradle-3.3 bin目录下的可执行文件。在这里有的同学可能要问了,直接调用根项目下面的./gradlew打包不可以么?可以,但是我一开始这样做的时候除了问题,报了如下图所示的错误:

报这个错误的原因我网上查了查之后说是gradle-wrapper.jar所在的位置不正确,我就去看了一下我checkout代码上的结构,果然发现gradle-wrapper.jar外面还多了一层branch ,tag, trunk的目录,如图所示:

但是我们在从svn到checkout代码到Android Studio中去的时候代码结构是正常的,真是奇了怪了,到现在还是一个未解之谜,如果知道情况的朋友还请告知。鉴于此,我就使用了本地gradle-3.3 bin目录下的可执行文件。

此外,如果不熟悉如何通用机器人发消息到阿里钉钉上面的朋友请自行参考钉钉的官方开发文档。

如果你的应有有需要做360加固的需求的话,那么请参考一下我的这篇文章:如何使用python命令行做360应用加固

在这里还需要说明一点,大家看了我代码片段就发现我自己写了很多的配置文件,这些配置文件里面的主要内容是跟app相关的一些信息,如app的版本号,debug还是release版本等,这些信息我在给apk命名的时候需要用到,虽然也可以直接解析build.gradle配置文件,但是感觉太麻烦了,而且build.gradle配置文件也不是规范的文件。为此我就把我需要的,又难以取到的信息写在了xxxxx.properties配置文件当中。而且通过apk命名就可以看到我是通过python命令直接去修改apk的名称,而不是在build.gradle配置文件中采用如下的方式命名的:

applicationVariants.all { variant ->
variant.outputs.each { output ->
def file = output.outputFile
output.outputFile = new File(file.parent,
"myapp-" + defaultConfig.versionName + "-" + buildTime() + ".apk")
//生成的文件名:myapp+版本名+生成日期+.apk
}
}

同理,由于我是循环打包,也就不需要在build.gradle配置文件中配置多渠道的信息,该图片中的名字和你看到的第一张图片中的文件夹是对应关系:

7、上传apk到蒲公英,拽取生成的二维码图片并发送到阿里钉钉中供测试人员下载:

上图中上传apk到蒲公英的命令在蒲公英的官方文档上可以查找到。

8、运行Python脚本,最终会有下图的效果:

通过上图你也看到了不同代理商的apk打成功的时候都有消息提醒和可供下载的连接,非常的方便,至此利用python做Android自动化打包的过程就结束了。

由于以前我没有python基础,学了一天就开始上手做了,可能在python代码的书写规范,异常捕获等方面做得不是很好,但是应该不影响大家理解这其中的内容,有兴趣的朋友赶快来试试吧!

如果文章当中有任何不正确的地方,还请广大读者纠正,非常感谢!