最近我们完成了用 Fastlane 自动化打包上传 iTunes Counnet ,为了将 Fastlane 的功能进一步的使用,后面希望能将 Pod 集成和升级也自动化,我也抽空研究了一下私有 Pod 库的升级、 Fastlane Action的制作和 Fastlane Plugin 的制作。

ok,开始我们的正文。

首先,简单介绍一下 Fastlane ,它是用 Ruby 来实现自动化构建和打包的工具,并且能和 Jenkins 等 CI 平台结合使用。 Fastlane 对于 iOS 开发来说,实在是太友好,从它提供的 actionsplugins 来看,足以满足大部分的自动化任务,如果不够的话,可以自定义 Action,并且可以制作成 Plugin 提交到 RubyGems 上供其他开发者使用。

升级私有 Pod 库

对 Fastlane 的配置这里就不说了,配置好后最简单的文件结构就是只有一个 AppfileFastfile ,Appfile 包含刚才初始化时配置,而 Fastfile 负责执行任务。

首先我们来分析一下我们平时在升级私有 Pod 库时的步骤(看注释部分)

1
2
3
4
5
6
7
8
9
git_pull # 拉取最新代码
ensure_git_branch # 确保当前是 master 分支
pod_spec_lint(allow_warnings: true) # 检查 Podspec 有效性
version_bump_podspec(path: path, version_number: version) # 修改 podspec 中版本
git_commit(path: ".", message: "update version to #{version}") # commit
push_to_git_remote # 提交本地改动到远程分支
add_git_tag(tag: version) # 添加 tag
push_git_tags # push 本地 tags
pod_push(path: path, allow_warnings: true) # push podspec 到仓库

再回到注释对应的 fastlane 命令,实际上 fastlane 的 actions 里都能找到 Pod 对应的命令,我们对照文档填充好参数之后,整个升级的核心功能已经实现了。最后我们考虑命令需要的哪些入参,我们需要知道 Project 的名字和升级到哪一个版本

1
2
version = options[:version]
project = options[:project]

完成之后我们后面升级只需要一行命令

1
fastlane pod_repo_push project:[projectname] version:[version]

详见:Fastfile

自定义 Action

上面升级库中用到了一个命令 pod_spec_lint ,这个并没有在官方提供的 Actions 里,是我自定义的,为什么要用 pod_spec_lint 不用 pod_lib_lint 呢?当时我在在测试升级的时候,把私有库更新传到 Github 上时,pod_lib_lint 验证通过,但是 push 到 remote 的时候就报错源文件找不到,这就让我很纳闷了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
...
[22:46:42]: --------------------------
[22:46:42]: --- Step: pod_lib_lint ---
[22:46:42]: --------------------------
[22:46:42]: $ pod lib lint --allow-warnings
[22:46:52]: ▸ -> FastlanePodspecDemo (0.1.1)
[22:46:52]: ▸ - WARN | summary: The summary is not meaningful.
[22:46:52]: ▸ - WARN | description: The description is equal to the summary.
[22:46:52]: ▸ - WARN | [iOS] license: Unable to find a license file
[22:46:52]: ▸ FastlanePodspecDemo passed validation.
[22:46:52]: Pod lib lint Successfully ⬆️
[22:46:52]: ----------------------------------
...
[22:47:34]: --- Step: pod_push ---
[22:47:34]: ----------------------
[22:47:34]: $ pod trunk push 'FastlanePodspecDemo.podspec' --allow-warnings
[22:47:34]: ▸ Updating spec repo master
[22:49:36]: ▸ CocoaPods 1.3.1 is available.
[22:49:36]: ▸ To update use: sudo gem install cocoapods
[22:49:36]: ▸ For more information, see https://blog.cocoapods.org and the CHANGELOG for this version at https://github.com/CocoaPods/CocoaPods/releases/tag/1.3.1
[22:49:36]: ▸ Validating podspec
[22:49:51]: ▸ -> FastlanePodspecDemo (0.1.2)
[22:49:51]: ▸ - WARN | summary: The summary is not meaningful.
[22:49:51]: ▸ - WARN | description: The description is equal to the summary.
[22:49:51]: ▸ - ERROR | [iOS] file patterns: The source_files pattern did not match any file.
[22:49:51]: ▸ - ERROR | [iOS] file patterns: The resources pattern did not match any file.
[22:49:51]: ▸ - WARN | [iOS] license: Unable to find a license file
[22:49:51]: ▸ [!] The spec did not pass validation, due to 2 errors.
[22:49:51]: ▸ [!] The validator for Swift projects uses Swift 3.0 by default, if you are using a different version of swift you can use a .swift-version file to set the version for your Pod. For example to use Swift 2.3, run:
[22:49:51]: ▸ echo "2.3 " > .swift-version.

然后我看到了这篇解释 What’s the difference between ‘pod spec lint’ and ‘pod lib lint’? ,pod lib lint 只会 lint 你本地的 pod ,以及确保你提供的东西是否正确,但是代码推到远程后如果 lint 不过也还是没用,而 pod spec lint 除了 pod lib lint 的验证步骤之外,还有会 lint 远程的pod ,真正确保 podspec 的有效性。

所以我基于原来的 pod_lib_lint 命令做了简单的修改,通过运行 fatslant new_action 生成action/pod_sepc_lint.rb 文件,详见:pod_spec_lint.rb ,写好之后可以运行 bundle exec rspec 跑一下测试是否能通过,也可以运行 bundle exec rubocop -a 检查一下代码是否符合 fastlane action的规范。最后我试着提交一个 PR 看看能否给官方加上,后来官方回应已经不能在加 actions 了,只能添加到 plugin 里。

后来使用自定义的 pod_spec_lint 命令之后就解决了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
[22:58:00]: Get started using a Gemfile for fastlane https://docs.fastlane.tools/getting-started/ios/setup/#use-a-gemfile
...
[22:58:06]: --- Step: pod_spec_lint ---
[22:58:06]: ---------------------------
[22:58:06]: $ pod spec lint --allow-warnings
[22:58:19]: ▸ -> FastlanePodspecDemo (0.1.2)
[22:58:19]: ▸ - WARN | summary: The summary is not meaningful.
[22:58:19]: ▸ - WARN | description: The description is equal to the summary.
[22:58:19]: ▸ - WARN | [iOS] license: Unable to find a license file
[22:58:19]: ▸ Analyzed 1 podspec.
[22:58:19]: ▸ FastlanePodspecDemo.podspec passed validation.
[22:58:19]: Pod spec lint Successfully ⬆️
[22:58:19]: ----------------------------------
...
[22:58:40]: --- Step: pod_push ---
[22:58:40]: ----------------------
[22:58:40]: $ pod trunk push 'FastlanePodspecDemo.podspec' --allow-warnings
[22:58:41]: ▸ Updating spec repo master
[23:04:01]: ▸ CocoaPods 1.3.1 is available.
[23:04:01]: ▸ To update use: sudo gem install cocoapods
[23:04:01]: ▸ For more information, see https://blog.cocoapods.org and the CHANGELOG for this version at https://github.com/CocoaPods/CocoaPods/releases/tag/1.3.1
[23:04:01]: ▸ Validating podspec
[23:04:29]: ▸ -> FastlanePodspecDemo (0.1.3)
[23:04:29]: ▸ - WARN | summary: The summary is not meaningful.
[23:04:29]: ▸ - WARN | description: The description is equal to the summary.
[23:04:29]: ▸ - WARN | [iOS] license: Unable to find a license file
[23:04:29]: ▸ Updating spec repo master
[23:05:45]: ▸ CocoaPods 1.3.1 is available.
[23:05:45]: ▸ To update use: sudo gem install cocoapods
[23:05:45]: ▸ For more information, see https://blog.cocoapods.org and the CHANGELOG for this version at https://github.com/CocoaPods/CocoaPods/releases/tag/1.3.1
[23:05:46]: ▸ --------------------------------------------------------------------------------
[23:05:46]: ▸ 🎉 Congrats
[23:05:46]: ▸ 🚀 FastlanePodspecDemo (0.1.3) successfully published
[23:05:46]: ▸ 📅 September 3rd, 09:04
[23:05:46]: ▸ 🌎 https://cocoapods.org/pods/FastlanePodspecDemo
[23:05:46]: ▸ 👍 Tell your friends!
[23:05:46]: ▸ --------------------------------------------------------------------------------
[23:05:46]: Successfully pushed Podspec ⬆️
[23:05:46]: push success, current version is 0.1.3

+------+-------------------------------------+-------------+
| fastlane summary |
+------+-------------------------------------+-------------+
| Step | Action | Time (in s) |
+------+-------------------------------------+-------------+
| 1 | Verifying required fastlane version | 0 |
| 2 | default_platform | 0 |
| 3 | git_pull | 3 |
| 4 | ensure_git_branch | 0 |
| 5 | pod_spec_lint | 13 |
| 6 | version_bump_podspec | 0 |
| 7 | git_add | 0 |
| 8 | git_commit | 5 |
| 9 | push_to_git_remote | 7 |
| 10 | add_git_tag | 0 |
| 11 | push_git_tags | 7 |
| 12 | pod_push | 425 |
+------+-------------------------------------+-------------+

[23:05:46]: fastlane.tools just saved you 8 minutes! 🎉

制作 Plugin

这一部分我并没有实现通,我在注册 RubyGems 的账号时邮箱验证过之后还是不能登录,提示未验证….不知道什么原因,有遇到解决了的,麻烦留言告诉我一下。下面是对官方的 Plugin 制作的解释:

创建好目录之后,运行

1
fastlane new_plugin [plugin_name]

fastlane 会创建一个有效的 Ruby gem 的文件结构,然后你编辑 lib/fastlane/plugin/[plugin_name]/actions/[plugin_name].rb 去实现你的 action ,把上面自定义的 action 的内容拷贝到里面,然后把创建出来的文件推到你的 Github 仓库,更新 fastlane-plugin-[plugin_name].gemspec 文件来指向你的仓库,最后运行

1
2
3
bundle install
rake install
rake release

ok~大功告成,现在你可以运行 fastlane add_plugin [plugin_name] 安装使用你的 Plugin 了。