前言

提及自动化一词,我想很多同学会想到 CI/CD,这 2 者之间确实是存在必定的联系,能够简略了解成父、子集合之间的关系。

而正如文章标题所言,近期我在研讨 macOS App 自动化分发 App Store 的工作,浅显点讲便是期望把原先手动构建 .xcarchive 文件、导出 .pkg 文件以及上传 App Store 的操作转为用 Shell 脚本自动化完结这些进程。其间,增加的 Shell 脚本会根据现有的 CI/CD 的完结,加入到恰当的位置。

那么,今日本文也会从 CI 基础出发,循序渐进地带着大家知道下 macOS App 自动化分发 App Store 完结的所以然。

1 知道继续集成(CI)基础

继续集成,Continuous Integration,简称 CI。这儿咱们来看下 Wikipedia 上对 CI 的介绍:

—— In software engineering, continuous integration (CI) is the practice of merging all developers’ working copies to a shared mainline several times a day. Grady Booch first proposed the term CI in his 1991 method, although he did not advocate integrating several times a day. Extreme programming (XP) adopted the concept of CI and did advocate integrating more than once per day – perhaps as many as tens of times per day.

一般情况下,这在咱们实践开发场景中,CI 指的是将项目的构建进程集成到某个独自的软件的实践。例如,在前面所说 macOS App 自动化分发 App Store 的 Shell 完结会加入到现有的 CI/CD 进程,它的 CI 的进程会是这样:

  • 开发人员(构建者)触发 Jenkins 的 Job
  • 履行 Job,这会由 Job 地点 Jenkins 的 Slave Node(构建机)履行,生产制品,例如一个 .dmg 或许 .pkg 文件
  • 上传制品到制品库

macOS App 自动化分发 App Store 探索与实践

其间,比较要害的则是构建机(Slave Node),咱们的整个构建进程的脚本完结都会在构建机上履行,例如后边要讲的自动化分发 App Store 的完结。而这儿脚本运用的是 Shell 编写,当然也能够用 Google 的 zx,有爱好的同学能够自行了解,这儿不做打开。

因为,在知道 macOS App 自动化分发 App Store 之前,咱们需求先知道 macOS App 手动分发的进程是怎么样的,以便于后续用自动化脚本一一完结手动分发的进程。

2 手动分发(Distribute)

macOS App 手动分发 App Store 的进程,浅显点讲便是运用 Xcode 供给的 GUI 界面操作完结。但是,在进行正式的操作运用的条件是要有一个能够发布到 App Store 装备齐备的 macOS App,这要求你需求满意以下 3 点:

  • 注册成为 Apple Developer Program,在 Apple Store 中下载 Apple Developer,然后在运用的账户中注册成为一个“尊贵的 688 会员”
  • 在 developer.apple.com/ 后台,别离在 Certificates, Identifiers & Profiles 和 App Store Connect 创立证书相关(Bundle Identifier、Provision Profile、Signing Certificate)和注册 App
  • 本地初始化创立一个简略的 macOS App,并相关上前面创立的 Bundle Identifier、Provision Profile、Signing Certificate

关于第 1 点,我想应该没什么难了解的。下面,咱们从创立一个 macOS App 出发来串联第 2、3 点要做的工作。

2.1 前置准备(创立一个齐备的运用)

创立一个 macOS App 的项目,能够经过 Xcode 快速创立一个,翻开 Xcode ——> Create a new Xcode Project ——> 挑选创立运用的 Platform(macOS)——> 填写项目称号、Team、Organization Identifier 等信息 ——> 在 General 中挑选 App Category 和 App Icons,这儿我创立的运用叫 FEKit。

运用 Xcode 翻开该项目的 .xcodeproj 文件,或许在终端输入,在咱们这个比如则是:

open FEKit.xcodeproj

挑选构建的方针,这儿咱们挑选 macOS 作为协议(Scheme)和方针(Target):

macOS App 自动化分发 App Store 探索与实践

装备运用的 Bundle Identifier、Provision Profile、Signing Certificate,这能够在 Apple Developer 后台或许在 Xcode 的 Preferences 中增加 Apple ID 来创立,不管运用其间哪种方式创立的,都会在 Apple Developer 后台的 Certificates, Identifiers & Profiles 中展现:

macOS App 自动化分发 App Store 探索与实践

其间,假如咱们要分发 App Store,则需求这 2 个证书:

  • Mac App Distribution,用于签名分发 App Store 的运用和装备对应的 Provisioning Profile
  • Mac Installer Distribution,用于签名运用的安装包和提交到 App Store

当然,除开这 2 个证书,咱们还需求在 Certificates, Identifiers & Profiles 页面的 Identifiers 和 Profiles 中别离创立 App ID 和 Provisioning Profile,这 2 个进程比较简略(这儿不做打开)。

在证书、Indentifiers、Profiles 创立完后,则能够下载证书(.cer)和 Provisioning Profile(.provisionprofile)文件到本地,然后别离双击翻开,其间证书则会加载到电脑登录对应的钥匙串(keychain)中,而 Provisioning Profile 则会被 Xcode 运用。而且,值得一提的是每个证书都是加密的,需求配套的密钥来解密运用,也便是一个证书(.cer 文件)对应一个密钥(.p12 文件),这个密钥则是由证书创立者生成的,所以,你在创立证书的时分需求挑选一个 .certSigningRequest 文件:

macOS App 自动化分发 App Store 探索与实践

然后在加载证书(.cer 文件)到本地,而且确保有证书对应的密钥( .p12 文件)后,最终登录的钥匙串中的证书会是这样:

macOS App 自动化分发 App Store 探索与实践

2.2 Xcode 手动分发 App Store

接着,咱们则能够运用 Xcode 的 Production -> Archive 来构建 .xcarchive 文件:

macOS App 自动化分发 App Store 探索与实践

构建完后,Xcode 会弹出窗口让你挑选 Distribute App 或 Validate App:

macOS App 自动化分发 App Store 探索与实践

这儿,咱们挑选 Distribution App -> App Store Connect -> Export -> 挑选 Development Team -> Manually manage signing,此刻会要求咱们挑选前面提及的 Distribution 证书、Installer 证书和 Provisioning Profile:

macOS App 自动化分发 App Store 探索与实践

挑选 Next -> Export 后,需求挑选导出的文件目录,则在该目录下会生成 FEKit.pkg 文件,然后咱们能够经过 Transporter 东西来将该文件上传到 App Store Connect(或许前面 Xcode 挑选 Export 或 Upload 的时分挑选 Upload),之后则能够在 App Store Connect 后台的 TestFlight 检查:

macOS App 自动化分发 App Store 探索与实践

所以,咱们一般所说的上传 App Store,指的是上传到 App Store Connect 的 TestFlight,后续再由这儿的 App Store 中提交上传文件的审阅,审阅经过再进行上架的操作。而且,需求留意的是每次上传的 .pkg 文件的版本号都需求比上一次的版本号大一(类似于 NPM 的 Package Version)。

那么,到这儿整个手动分发 App Store 的进程就介绍结束了,总结起来首要是这 3 个进程:

  • 构建项目生成 .xcarchive 文件
  • 导出 .pkg 文件
  • 上传 .pkg 文件至 App Store Connect

所以,下面咱们需求用 Shell 脚本自动化完结这 3 个进程,也便是 macOS App 自动化分发 App Store。

3 自动化分发(Distribute)

在介绍 macOS App 自动化分发 App Store 完结之前,咱们先来知道这 3 个东西:

  • xcodebuild 是 Xcode 的一个指令行东西包,首要用于构建项目相关
  • altool 是一个内置于 Xcode 中的指令行东西,用于验证 App 的二进制文件并将其上传至 App Store 或许对 App 进行公证(Notarize)
  • xcrun 也是 Xcode 的一个指令行东西包,首要用于履行 Xcode 相关的东西链,例如 xrun altoolxrun xcode-select

而在接下来讲解 macOS App 自动化分发 App Store 进程中,则会别离提及运用这些东西供给的才能来完结前面的手动进程。那么,下面就让咱们开端逐渐知道下自动化的完结进程,首要是构建 .xcarive 文件。

3.1 构建 .xcarchive 文件

咱们能够运用 xcodebuild.xcarchive 指令来构建生成 .xcarchive 文件:

xcodebuild -archive \
-scheme "FEKit (macOS)" \
-configuration Release \
-archivePath ./Output/FEKit

能够看到,这儿咱们运用了 3 个 Option,它们别离的效果:

  • -scheme 构建的协议,不同的方针 Target 一般对应不同的协议,例如 FEKit (iOS)FEKit (macOS),前者是 IOS,后者是 macOS
  • -configuration 构建的装备,例如 Debug 或 Release,不同的装备对应的证书、签名装备会有不同
  • -archivePath 构建 .xcarchive 导出的目录和文件名,这儿则会导出到 Output 目录下并命名为 FEKit.xcarchive

其间,关于项目已有的协议和装备,则能够运用 xcodebuild -list 指令检查。

3.2 导出 .pkg 文件

构建完 .xcarchive 文件后,则需求根据改文件导出 .pkg 文件,这同样能够运用 xcodebuild 供给的 Option 指令完结:

xcodebuild -exportArchive \
-archivePath ./Output/FEKit.xcarchive \
-exportPath ./Output/Pkgs \
-exportOptionsPlist ./Build/ExportOptions.plist

其间,关于 -exportOptionsPlist 则是你导出 .pkg 相关的装备,它会是这样:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>destination</key>
	<string>export</string>
	<key>installerSigningCertificate</key>
	<string>你的 Mac AppStore Install 证书 ID</string>
	<key>manageAppVersionAndBuildNumber</key>
	<true/>
	<key>method</key>
	<string>app-store</string>
	<key>provisioningProfiles</key>
	<dict>
		<key>你的 Bundle ID</key>
		<string>你的 Provisioning Profile 的称号</string>
	</dict>
	<key>signingCertificate</key>
	<string>你的证书 ID</string>
	<key>signingStyle</key>
	<string>manual</string>
	<key>teamID</key>
	<string>你的 Team ID</string>
	<key>uploadSymbols</key>
	<true/>
</dict>
</plist>

当然,假如你不想手动创立或填写这些信息,能够用 Xcode 手动导出 .pkg 操作一次,ExportOptions.plist 文件会自动生成在导出的文件目录下。

履行完前面的指令后,导出的 .pkg 文件则会在 -exportPath 装备的文件途径下,在这儿也便是在 /Outputs/Pkgs/ 文件目录下。

3.3 验证和分发 .pkg 文件

接着,则是最终一步验证和分发 .pkg 文件。这一进程需求运用 xcrunaltool 完结。首要,履行 xcrun altool --validate-app 来验证 .pkg 文件,这个首要用于承认你的运用是否满意上传的条件,例如是否挑选 App Category、App Icon 以及版本号递加等,相应的指令则是:

xcrun altool --validate-app \
-f ./Output/Pkgs/FEKit.pkg \
-t macOS \
-u xxxxx \
-p xxxxx \
--show-progress

能够看到,这儿运用到了 5 个 Options,它们各自的效果:

  • -f 需求验证的 .pkg 文件地点文件目录位置
  • -t 验证的方针类型,例如 macOS 或 IOS
  • -u 用于衔接 App Store Connect 的 Apple Developer 账号(Apple ID)
  • -p 和账号(Apple ID)对应的 App 专用暗码
  • --show-progress 用于输出验证进程的履行情况

其间,关于 -p 的 App 专用暗码则需求去Apple ID 后台请求。而且,为了避免将暗码明文展现在履行的指令中,咱们能够独自保护一个文件来存储账号和暗码:

#!/bin/bash
# App Developer 账号(Apple ID)
user="xxxxxxxx"
# App 专用暗码
pwd="xxxxxx"

相应地,还需求根据 xcrun altool --validate-app 指令履行的成果(成功或失利)做不同的后续处理:

#!/bin/bash
# app_store_user_pwd.sh 能够独自放到一个躲藏目录,这儿只是作为比如所以没有放到躲藏目录
source "./app_store_user_pwd.sh"
echo "Run xcrun altool --validate-app..."
xcrun altool --validate-app --f ./FEKit.pkg -t macOS -u $user -p $pwd --show-progress
if [ $? -eq 0 ]; then
    echo "validate-app success"
    # 履行上传的指令
else
    echo "validate-app fail"
    exit -1;
fi

其间,$? 表明上个指令履行成果,0 表明成功,1 表明失利,所以这儿咱们运用 if [ $? -eq 0 ]; then 判别验证指令履行成果是否等于 0,是则进行后续上传的处理,不是则输出验证失利的信息并退出。

那么,假如在验证经过 .pkg 文件后,咱们则能够上传 .pkg 文件至 App Store Connect,这需求履行 xcrun altool --upload-app 指令:

xcrun altool --upload-app \
-f ./Output/Pkgs/FEKit.pkg \
-t macOS \
-u xxxxx \
-p xxxxx \
--show-progress

能够看到上传的指令和验证的指令运用上大同小异,只有第一个 Option 不同。那么,到这儿整个完结自动化分发 App Store 的进程现已介绍完了,因为前面都是分进程讲解的,所以 Shell 脚本的完结都是分开的,这儿咱们把上面讲到的 Shell 完结都合并到一个 .sh 文件中:

#!/bin/bash
echo "Run xcodebuild archive..."
xcodebuild archive \
-scheme "FEKit (macOS)" \
-configuration Release \
-archivePath ./Output/FEKit
ARCHIVE_FILE=./Output/FEKit.xcarchive
if [ ! -e "$ARCHIVE_FILE" ]; then
    echo ".xarchive doesn't exist";
    exit -1;
fi
echo "Run xcodebuild -exportArchive..."
xcodebuild -exportArchive \
-archivePath ./Output/FEKit.xcarchive \
-exportPath ./Output/Pkgs \
-exportOptionsPlist ./Build/ExportOptions.plist
PKG_FILE=./Output/Pkgs/FEKit.pkg
if [ ! -e "$PKG_FILE" ]; then
    echo ".pkg doesn't exist";
    exit -1;
fi
source "./Build/app_store_user_pwd.sh"
xcrun altool --validate-app --f $PKG_FILE -t macOS -u $user -p $pwd --show-progress
if [ $? -eq 1 ]; then
    echo "altool validate-app fail"
    exit -1;
fi
echo "altool validate-app success"
xcrun altool --upload-app --f $PKG_FILE -t macOS -u $user -p $pwd --show-progress
if [ $? -eq 0 ]; then
    echo "altool --upload-app success"
else
    echo "altool --upload-app fail"
fi

结语

最终,这儿咱们用一个流程图再回顾下整个自动化分发 App Store 的进程:

macOS App 自动化分发 App Store 探索与实践

而且,我想可能有同学会问,作为前端咱们需求懂这个吗?个人认为是需求的,因为在一些场景下,比如说做 React Native 或 Electron 开发的时分,不可避免地就会接触到原生运用的签名、构建、公证(Notarize)和分发 App Store 的概念,所以,经过亲自地体验一番原生运用完结这些的进程还是有必定收益的(知其然使其然)。此外,社区中也有支持开箱即用的完结前面进程的东西 fastlane,有爱好的同学能够了解下。

假如,文中存在表达不妥或过错的地方,欢迎各位同学提 Issue ~

点赞

经过阅览本篇文章,假如有收获的话,能够点个赞,这将会成为我继续分享的动力,感谢~

我是五柳,喜欢创新、捣鼓源码,专心于源码(Vue 3、Vite)、前端工程化、跨端等技能学习和分享,欢迎重视我的微信公众号 Code center 或 GitHub