使用 Github Action 打包IOS项目踩坑

折腾了好些天, 最终成功编译打包 IOS应用 上传到 TestFlight , 记录下中途踩的坑.

题外话:

Github Action 官方给到的 MacOS 的 Per-minute rate 是 Linux 的10倍, 老大说把闲置的一台 Mac mini 用上, 所以后面改用了 self-hosted runner. 省了笔琐碎银子, 也方便了 Debug…..

主要的坑是两步验证 和 KeyChain问题.

两步验证

苹果官方强制要求两步验证登录 Apple 开发者帐号, 但是使用 Github actions 在非交互模式下, 你是无法输入验证码的, Fastlane 官方提供了解决方法: App Store Connect API

按照文档提示配置下, 没啥问题. 这里简单提下我的做法.

在App Store Connect 中获取到 key_id, issuer_id, key(.p8文件的内容)

在Fastlane文件中添加如下代码:

lane :beta do |options|
  app_store_connect_api_key(
    key_id: ENV['ASCAPI_KEY_ID'],
    issuer_id: ENV['ASCAPI_ISSUER_ID'],
    key_filepath: 'authkey.p8',
    duration: 1200, # optional (maximum 1200)
    in_house: false # optional but may be required if using match/sigh
  )
  match(type: "appstore")

  enable_automatic_code_signing
  gym(scheme: "Leaf") # Build your app
  pilot
  .....
end

调用 app_store_connect_api_key 后, 需要认证的 Action, 比如pilot, 会自动加载 Actions.lane_context[SharedValues::APP_STORE_CONNECT_API_KEY]. 所以务必将 app_store_connect_api_key 放在所有需认证的 Action 之前.

这里 ENV 的变量 ASCAPI_KEY_ID, ASCAPI_ISSUER_ID 都可以设置在 Github 的 secrets 中.

而文件 authkey.p8 可以使用 gpg 加密解密.

本地终端执行:

gpg -c --armor authkey.p8

会要求输入 passphrase, 最后生成文件 authkey.p8.asc. 这个 passphrase 需要添加到 secrets 中, 后续解密要用到.

.gitignore 中添加 authkey.p8, 忽略该文件, 将 authkey.p8.asc 文件提交.

然后在 github action 的 Workflow 配置文件中解密:

- name: decrypt auth file
  run: |
    gpg -d --passphrase ${{ secrets.DEPLOY_ENC_KEY }} --batch authkey.p8.asc > authkey.p8

这里 secrets 的 DEPLOY_ENC_KEY 就是刚刚加密时用的 passphrase .

如果觉得麻烦, 也可以将 key_filepath 改成 key 参数, 把 authkey.p8 中的内容贴到 secrets 中也可以. 具体可参看官方文档:

  app_store_connect_api_key(
    key_id: ENV['ASCAPI_KEY_ID'],
    issuer_id: ENV['ASCAPI_ISSUER_ID'],
    key: ENV['ASCAPI_KEY'],
    duration: 1200, # optional (maximum 1200)
    in_house: false # optional but may be required if using match/sigh
  )

Keychain 问题

这个是花时间最久的地方, 遇到坑了.

首先在 Self-hosted runner 中, 跑一次编译打包, 一路下来, 成功发布到了TestFlight.

但使用 Github Action 时, 报错:

▸ Running script '[CP] Embed Pods Frameworks'
** ARCHIVE FAILED **


The following build commands failed:
    PhaseScriptExecution [CP]\ Embed\ Pods\ Frameworks /Users/***/Library/Developer/Xcode/DerivedData/Leaf-acuongxlhifqldeauyqugojdtjev/Build/Intermediates.noindex/ArchiveIntermediates/Leaf/IntermediateBuildFilesPath/Leaf.build/Release-iphoneos/Leaf.build/Script-46D1B8D72193B7966B5CC35AB1794FCF.sh
(1 failure)
[17:40:06]: Exit status: 65

match 通过, 但 build app 报错.

改用 SSH 远程执行命令, 去打包, 报了同样的错误. 也就是在非交互模式下, build 失败, 交互模式下,build 成功.

Google 了半天, 基本都说是 key-chain 的问题.

有的解决方法中, 提到了使用 Fastlane 官方的 setup_ci action, 可以创建临时的key-chain. 尝试了下, 没有效果.

最后的解决方法参考了远程终端登录下如何解锁 macOS Keychain .

Self-hosted runner 需要运行 ./run.sh 来监听Workflow, tmux 建 Session , 开两个Window, 一个跑 ./run.sh , 另一个Window中, 执行

security unlock-keychain login.keychain

会提示输入用户的登录密码, 输入即可.

在 Github Action 中再次执行 Workflow, OK.

当然, 也可以直接在 Workflow配置文件中添加如下步骤 [ 在跑 fastlane 步骤之前]:

- run: security unlock-keychain -p ${{ secrets.PASSWD }} ~/Library/Keychains/login.keychain

PASSWD 为用户的登录密码.

OK.

参考: