DevOps 是一种广为人知的活动,其主要目的是使软件交付自动化。的确,DevOps 的目标是持续测试、代码质量、功能开发和更轻松地进行维护更新。因此,DevOps 的终极目标之一是让开发者可以执行快速可靠、自动化的发布,理想状态下,整个流程都不需要人为操作。这被称为持续交付。撰写本文的目的是展示我们现在也能在安卓上实现这一目标,同时分享笔者的想法和反馈意见。

以持续集成为起点

为了实现持续交付,必须确保强大的持续集成。这已经在安卓环境实行一段时间了,但是为了清楚起见,咱们还是回顾一下吧。

首先,任何安卓应用程序都应具备持续集成。是的,笔者就是这个意思。实际上,这为现代应用程序开发带来了不可忽视的几个好处。在笔者看来,最大的优点是以下几项:

  • 构建自动化:告别“但是在我的机器上可以构建成功”。应用程序在哪里都能构建。

  • 尽早试错:每次推送后都进行构建可以确保尽早发现错误。

  • 测试持续化:确保测试始终进行

  • 持续打包:在打包二进制代码时避免人为错误。

  • 发布速度更快:因为我们对每一步构建都有信心,发布也变得更加简单。

  • 信心增强:终于,我们可以信任自己的代码和流程,并且减少意料之外的错误。

典型的持续集成过程

First, we need an integration server like Jenkins or Travis. The following jobs are my standard configuration:

首先,我们需要一个 Jenkins 或者 Travis 那样的集成服务器。以下作业是笔者的标准配置:

• 一旦源码存储库(Git、SVN等等)中的推送完成,就会开始一个作业。它会查看 dev 分支、编译代码、运行单元测试,并打包调试 APK。

• 第一个作业成功完成后,运行下一个作业。它会运行集成测试(通过Espresso 或 Robotium),通过重现场景和检查图像内容来确保用户体验。你可以使用连接设备(如果你的 CI 服务器不容易获取的话,就有些困难)、Genymotion 或随 Android Studio 2.0 发布的最新内置模拟器(快去试试吧!)来操作。

• 一个作业会运行代码测量(举个例子,通过 Sonarqube)以监测代码质量。例如,笔者会在每天半夜运行这个作业。

• 最后,在我们推送 master 分支或发布分支后运行一个作业。它会编译代码,并生成发布 APK。

好啦!如你所见,操作非常简单,而且能保证笔者之前列举的所有优点。

测试是关键

笔者曾写过一篇关于安卓测试的文章。测试非常重要,因为它是能自动证明我们的应用按计划运行的唯一方法。有很多工具可以帮我们写出优秀的测试代码,所以要明智地进行选择。

同时,在选择集成到应用中的函数库时要实事求是。实际上,你应该明白如果函数库的测试覆盖率较高,测试应用程序就会更轻松。他们已经考虑到如何正确测试和通过测试促进开发的问题了(IMO、OkHttpRetrofit 都是很好的范例)。相当于你在使用的同时就进行了测试。

最后,类似 Dagger 的函数库可以增加可测试性。实际上,它会迫使你遵照单一职责原则,并且将代码正确分离,这样测试就更加容易。

一旦你拥有了强大的持续集成,我们来看看怎么升级吧。

持续交付:无限升级

举个例子,在 Captain Train,我们每6周发布一个新版本,并且对此非常谨慎。目前:

• We have a beta phase.

• We support 4 locales.

• We support 3 types of device (phone, 7 and 9 inches tablets).

• We always check our Play Store listings.

• We create release notes.

• We use the rollout feature.

• We upload our 72 screenshots (6 screenshots * 4 locales * 3 types)

• We have a wear companion.

  • 我们有一个测试阶段。
  • 我们支持4 种语言环境。
  • 我们支持3种设备(手机、7寸和9寸平板电脑)。
  • 我们时刻关注在谷歌电子市场的排名。
  • 我们创建发布说明。
  • 我们采用发布功能。
  • 我们上传72张截图(6种截图X4中语言环境X3中设备类型)。
  • 我们有一个穿戴伴侣。

这个流程需要花时间,而且不止一点儿。最近,我们决定是时候尝试把这个流程自动化了。虽然主要目的是为了减少发布版本需要的时间,但是如果同时也能避免人为错误,保持各个发布版本之间的连贯性,就更好了。这也让我们担负了重大的责任,因为开发者控制了整个发布流程。实际上,市场和传播团队也要跟我们一起看看怎么将他们的变化集成到发布版本中去。

但是坦白说……在安卓,开发者并不能控制所有的事情。谷歌可以。但是,它提供了 HTTP API,使开发者轻易地与谷歌电子商店控制台互动。他们还提供了各种开发语言的客户端,例如 Java(这是必须的!)、Phython、Ruby,等等……

在本文中,笔者将主要讨论 Java 客户端,因为这很可能是安卓开发者最了解的开发语言。

编写你自己的 publisher

让我们看看如何编写定制化的谷歌电子市场 publisher。分为两步:首先,我们要配置控制台,让客户端能够操作,然后探索 API。通常跟谷歌建立连接时最困难的就是配置……相关文档可以在这里找到。请注意,文档也许不是最新版的。

配置

首先,如果没有现成的,你需要在谷歌控制台新建一个项目。接下来,我们需要启用 Google Play Android Developer API



Once it is done, we must create a credential of type Service account key:

完成之后,我们必须创建一个 Service account key 类型的证书:

最后,填写小表,下载 JSON 格式的证书文件。你需要保存三个值:private_key_idprivate_keyclient_email。把 private_key 的值保存到它自己的 secret.pem 文件。

开发者控制台搞定了……现在我们来看第二个控制台吧!

连接到你的电子市场控制台。你需要依次访问 Settings > API access

接下来,你只需要连接你的项目。最后在 Service accounts,授权你在 JSON 文件的 client_email 处填写的邮箱地址。

现在好了。一切搞定!

探索 API

现在让我们通过 Java 客户端访问接口。我们在 publisher 上面创建一个单独的 Java 项目,并且添加以下依赖项(在 maven central 有):

compile 'com.google.apis:google-api-services-androidpublisher:

v2-rev20-1.21.0'

下一步是新建一个 AndroidPublisher。首先,我们通过以下信息来实例化 GoogleCredential:一个客户端连接,一个 JSON factory,一个与 private_key_id 对应的私有关键 ID,一个与 client_email 对应的账户 ID,ANDROIDPUBLISHER 范围,以及与 private_key 对应的、包含私有关键信息的重要文件。是的,所有这些都需要。

然后,我们用应用程序包创建一个 AndroidPublisher 例子。

http = GoogleNetHttpTransport.newTrustedTransport();
json = JacksonFactory.getDefaultInstance(); Set<String> scopes =
Collections.singleton(AndroidPublisherScopes.ANDROIDPUBLISHER); GoogleCredential credential = new GoogleCredential.Builder().
setTransport(http).
setJsonFactory(json).
setServiceAccountPrivateKeyId(KEY_ID).
setServiceAccountId(SERVICE_ACCOUNT_EMAIL).
setServiceAccountScopes(scopes).
setServiceAccountPrivateKeyFromPemFile(secretFile).
build(); publisher = new AndroidPublisher.Builder(http, json, credential).
setApplicationName(PACKAGE).
build();

AndroidPublisher 是谷歌 API 的主要入口。它有一个 edits 方法,可以让我们修改想从控制台获取的数据。

要开始一个新版本,你必须用 insert 请求来开始,然后保存它的 id,接下来每次调用都会使用该 id。

AndroidPublisher.Edits edits = publisher.edits();

AppEdit edit = edits.insert(PACKAGE, null).execute();
String id = edit.getId();

现在,我们可以开始修改控制台数据了。举个例子,如果你想修改排名:

Listings listings = edits.listings();

Listing listing = new Listing().
setFullDescription(description).
setShortDescription(shortDescription).
setTitle(title); listings.update(PACKAGE, id, "en_US", listing).execute();

You can also upload screenshots:

也可以上传截图:

Images images = edits.images();

FileContent content = new FileContent(PNG_MIME_TYPE, file);

images.upload(PACKAGE, id, "en_US", "phone5", content).execute();

最后一个例子,上传一个 APK:

// APK upload
Apks apks = edits.apks();
FileContent apkContent = new FileContent(APK_MIME_TYPE, apkFile);
Apk apk = apks.upload(PACKAGE, id, apkContent).execute();
int version = apk.getVersionCode(); // Assign APK to Track
Tracks tracks = edits.tracks();
List<Integer> versions = Collections.singletonList(version)
Track track = new Track().setVersionCodes(versions);
tracks.update(PACKAGE, id, "production", track).execute(); // Update APK listing
Apklistings apklistings = edits.apklistings();
ApkListing whatsnew = new ApkListing().setRecentChanges(changes);
apklistings.update(PACKAGE, id, version, "en_US", whatsnew).execute();

笔者鼓励你多多探索这个接口。它既强大,又不复杂。

最后一步,你必须提交自己的版本。实际上,谷歌会记录你的每一个更改请求,但是只有在你提交版本之后,这些更改才会被保存。笔者同时建议你在提交之前先验证这些更改。

edits.validate(PACKAGE, id).execute();

edits.commit(PACKAGE, id).execute();

如你所见,你在代码开头找回的 id 可以被当做事务 id。通过调用 insert,update/upload 你的更改以开始事务,validate 以及最终 commit。非常简单。

结论

现在,安卓应用程序也可以呼应 DevOps 活动,拥有强有力的持续交付了。在 Captain Train,我们选择编写自己的 publisher 工具来确保自己控制每个步骤和重要步骤的字节。一旦发布任务成功完成,我们就把它当做一个脚本来运行。不过也有 Jenkins 插件或 Gradle 插件可以帮你完成这些工作。只是要注意了解幕后的运行情况。毕竟你在处理生产。必须小心谨慎。

这样的工具和流程让你只需推送 master 分支即可在生产环境中发布新版本。既简单、快捷,又可靠、节约时间。

显然,在一个应用程序中可行的方法不一定适用于所有的团队、公司和应用程序。还要依靠你的团队以及团队与市场传播团队的关系。不过,在此笔者想要总结的是,持续交付应该成为每个开发团队的目标,往这个目标迈进的每一步都是一种胜利。

OneAPM Mobile Insight以真实用户体验为度量标准进行 Crash 分析,监控网络请求及网络错误,提升用户留存。访问 OneAPM 官方网站感受更多应用性能优化体验,想阅读更多技术文章,请访问 OneAPM 官方技术博客

本文转自 OneAPM 官方博客

安卓 DevOps:从一次推送命令到生产的更多相关文章

  1. 推送测试,生产环境无法打印log获取deviceToken,可以通过弹窗获取deviceToken

    z- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:( ...

  2. 在Unity3D中实现安卓平台的本地通知推送

    [前言] 对于手游来说,什么时候需要推送呢?玩过一些带体力限制的游戏就会发现,我的体力在恢复满后,手机会收到一个通知告诉我体力已完全恢复了.这类通知通常是由本地的客户端发起的,没有经过服务端. 在安卓 ...

  3. Azure DevOps (九) 通过流水线推送镜像到Registry

    上一篇文章我们研究了如何通过流水线编译出一个docker的镜像,本篇我们来研究一下,如何把编译好的镜像推送到镜像仓库去. 平时如果我们是单机部署,我们的docker本身就装在部署的机器上,我们在本机直 ...

  4. git强制推送命令

    git push -f origin master 注释: origin远程仓库名,master分支名,-f为force,意为:强行.强制. 这行命令的意思就是强制用本地的代码去覆盖掉远程仓库的代码, ...

  5. git命令合集及github的克隆推送

    安装git 初始化仓库 提交相关 撤销相关 远程推送 分支相关 其他 遇到的错误 github的克隆上传 此文章只是对命令的一个统计,起备忘和复习git只是的作用,不建议从没接触过git的同学通过它来 ...

  6. 安卓统一推送联盟融云成唯一IM云服务企业

    10月16日,安卓统一推送联盟在北京正式成立,来自中国信息通信研究院,华为.小米.OPPO等手机厂商,BAT等互联网巨头公司等75家机构及企业代表参加了联盟成立大会,融云也受邀参会并成为首批成员单位中 ...

  7. 手把手教你搞定个推iOS推送SDK集成

    以下是一位开发者在集成个推iOS推送SDK过程中的真实经历. 作者:Ezreallp 一次偶然的机会,公司的项目要用到推送,我自己本来就很懒,不愿意去弄整套APNS的流程,刚好之前跟朋友聊起过他们的产 ...

  8. 【经验】ansible 批量推送公钥

    1.使用 ssh-keygen -t rsa生成密钥对 ssh-keygen -t rsa 2.推送单个公钥到远程机器 格式: ssh-copy-id -i ~/.ssh/id_rsa.pub use ...

  9. iOS百度推送的基本使用

    一.iOS证书指导 在 iOS App 中加入消息推送功能时,必须要在 Apple 的开发者中心网站上申请推送证书,每一个 App 需要申请两个证书,一个在开发测试环境下使用,另一个用于上线到 App ...

随机推荐

  1. Quartz 第三课 More About Jobs & JobDetails(官方文档翻译)

    当学完第二课之后,你欣喜的发现,让jobs工作起来是还是相当简单的.虽然让jobs运行起来很简单,对于其执行的关键内容还是需要知道的.它们是IJob接口中的Execute和JobDetails. 当你 ...

  2. 1.6建造者模式(生成器模式) Builder

    1.概念:将一个复杂对象的构建和他的表示分离,使得同样的构件可以创建不同的表示. 2.实例:肯德基和中餐,肯德基抽象了整个做菜的复杂过程(相同的构建),然后在不同的店铺进行实现(不同的表示).中餐往往 ...

  3. spring junit参数

    备忘,以后有时间再写点东西吧.其实自己就没有开始写过. blog地址:http://www.cnblogs.com/shizhongtao/p/3342174.html //spring 配置的路径, ...

  4. UvaLive7362 Fare(欧拉函数)

    题意:求1~n的素因子之和. 分析:欧拉函数 #include<cstdio> #include<cstring> #include<cctype> #includ ...

  5. 百度云管家-V4.6.1-单文件版绿色版

    转载说明 本篇文章可能已经更新,最新文章请转:http://www.sollyu.com/baidu-is-clouds-butler-v4-6-1-single-file-green-edition ...

  6. MySQL定时检查是否宕机并邮件通知

    我们有时候需要一些检查MySQL是否宕机,如果宕机了应自动重新启动应用并通知运维人员!此脚本用来简单的实现MySQL宕机后自动重启并邮件通知运维,此为SHELL脚本,当然也有一些朋友喜欢用Python ...

  7. google map 点击获取经纬度

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  8. php 时间转化总结

    iQuery插件datepicker获取的时间函数为"月月/天天/年年年年"(以04/21/2015为例)的形式 (1)转化为2015-21-04形式:$start = date( ...

  9. Pandas简易入门(四)

    本节主要介绍一下Pandas的另一个数据结构:DataFrame,本文的内容来源:https://www.dataquest.io/mission/147/pandas-internals-dataf ...

  10. 1087. All Roads Lead to Rome (30)

    时间限制 200 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue Indeed there are many different ...