fastlane 实现 iOS全流程自动化脚本实战指南
fastlane 作为移动开发领域的自动化工具集,能将构建、分发、错误监控等重复性工作转化为可执行脚本,极大提升开发效率。本文基于 iOS 项目场景,详解从环境搭建到全流程自动化的实现方案。
1. 安装 fastlane
fastlane 支持 macOS、Linux、Windows 系统,推荐在 macOS 环境下使用,以下为完整安装流程:
1.1 前置环境准备
-
安装Xcode
-
Ruby 环境:要求 Ruby 2.7 + 版本,验证命令:
ruby -v # 输出示例:ruby 3.2.2p53 (2023-03-30 revision e51014f9c0)
若版本过低,可通过gem update --system升级 RubyGems。
1.2 安装 Bundler
gem install bundler
1.3 安装 fastlane
推荐使用 bundle 方式安装 fastlane,因为项目中有 Gemfile,这样可以统一和管理依赖,避免全局依赖冲突。
在项目根目录下执行:
bundle install
初始化过程中需完成:
- 选择用途(推荐选 "4. 🛠️ Automate App Store distribution")
- 输入 App Store Connect 账号
- 等待依赖安装完成
初始化后生成核心文件:
fastlane/Fastfile:工作流配置核心文件fastlane/Appfile:应用元数据配置(Bundle ID、团队 ID 等)Gemfile:Ruby 依赖管理文件
2. 使用 build_app 构建 App
build_app是 fastlane 的核心构建动作(底层封装 xcodebuild),支持自定义构建参数,满足不同环境需求。
2.1 基础构建配置
在Fastfile中定义构建 lane,包含清理缓存、指定 scheme、输出路径等配置:
default_platform(:ios)
platform :ios do
# 开发环境构建
lane :dev_build do
# 清理之前的构建产物
clean
# 构建核心配置
build_app(
scheme: "MyApp-Dev", # Xcode中的scheme名称
workspace: "MyApp.xcworkspace", # 若使用CocoaPods需指定
export_method: "development", # 导出方式(开发环境)
output_directory: "./builds/dev", # 构建产物存放路径
output_name: "MyApp_Dev_#{Time.now.strftime('%Y%m%d_%H%M')}", # 带时间戳的文件名
clean: true, # 构建前清理项目
include_bitcode: false # 开发环境无需Bitcode
)
puts "✅ 开发环境构建完成,路径:./builds/dev"
end
end
2.2 执行构建
终端执行以下命令触发构建:
fastlane dev_build
构建成功后,在./builds/dev目录下生成.ipa文件。
2.3 进阶配置
- 指定设备与配置:
build_app(
configuration: "Release", # 构建配置(Release/Debug)
device: "iPhone 15", # 模拟设备
xcargs: "ARCHS=x86_64 ONLY_ACTIVE_ARCH=NO" # 额外编译参数
)
-
版本号自增:
在
build_app前添加版本号管理动作:
increment_build_number # 自增构建号
increment_version_number(version_number: "1.2.0") # 指定版本号
3. upload_to_app_store 上传包到 App Store
upload_to_app_store可一键上传构建产物至 App Store Connect,支持自动提交审核。
3.1 前置准备
- 在
Appfile中配置应用元数据:
app_identifier "com.example.myapp" # 应用Bundle ID
apple_id "developer@example.com" # App Store Connect账号
team_id "AB12XYZ345" # 开发团队ID(Apple开发者后台获取)
-
配置 App Store Connect 认证:
推荐使用 API 密钥认证(替代账号密码),在 Apple 开发者后台创建密钥后,在项目根目录创建
.env文件存储密钥:
APP_STORE_CONNECT_KEY_ID=ABC123
APP_STORE_CONNECT_ISSUER_ID=def456
APP_STORE_CONNECT_KEY_FILEPATH=./AuthKey_ABC123.p8
3.2 上传配置
在Fastfile中添加发布 lane:
lane :appstore_release do
# 1. 构建生产环境包
build_app(
scheme: "MyApp",
export_method: "app-store", # 生产环境导出方式
output_directory: "./builds/release",
include_bitcode: true, # App Store必须开启Bitcode
export_options: {
signingStyle: "automatic", # 自动签名
uploadBitcode: true,
uploadSymbols: true
}
)
# 2. 上传至App Store Connect
upload_to_app_store(
submit_for_review: false, # 暂不提交审核
automatic_release: false, # 不自动发布
skip_screenshots: true, # 跳过截图上传
skip_metadata: true # 跳过元数据上传
)
puts "✅ 已上传至App Store Connect"
end
3.3 执行上传
fastlane appstore_release
上传成功后可在 App Store Connect 的 "测试 Flight" 或 "构建版本" 中查看。
4. 使用 fastlane-plugin-pgyer 上传到蒲公英
蒲公英作为国内常用的测试分发平台,通过 fastlane 插件可实现自动上传与分发。
4.1 安装蒲公英插件
终端执行插件安装命令:
fastlane add_plugin pgyer
安装过程中若提示 "是否允许修改 Gemfile",输入y确认。
4.2 获取蒲公英密钥
登录蒲公英平台,在 "应用管理 - API 设置" 中获取:
-
api_key:接口密钥 -
user_key:用户密钥
将密钥存入.env文件:
PGYER_API_KEY=your_api_key
PGYER_USER_KEY=your_user_key
4.3 配置上传 lane
在Fastfile中添加蒲公英分发 lane:
lane :pgyer_upload do
# 先执行开发环境构建
dev_build
# 上传至蒲公英
res = pgyer(
api_key: ENV["PGYER_API_KEY"],
user_key: ENV["PGYER_USER_KEY"],
ipa: "path/name.ipa", # 读取构建产物路径
update_description: "✅ 测试版本更新\n- 修复登录bug\n- 新增支付功能", # 更新描述
password: "123456" # 安装密码(可选)
)
end
4.4 执行分发
fastlane pgyer_upload
执行完成后,可通过输出的链接或二维码下载测试包。
5. upload_symbols_to_crashlytics 上传 dSYM 文件
dSYM 文件包含符号表信息,是 Firebase Crashlytics 解析崩溃日志的关键,通过 fastlane 可实现自动上传。
5.1 前置配置
-
集成 Firebase Crashlytics:按官方文档在 Xcode 项目中集成 SDK
-
获取 Google 服务配置:下载
GoogleService-Info.plist放入项目目录 -
安装 Crashlytics 插件(部分版本需手动安装):
fastlane add_plugin crashlytics
5.2 配置 dSYM 上传
在构建 lane 中添加上传动作,确保构建后自动执行:
lane :dev_build do
# 构建动作(同上)
build_app(...)
# 上传dSYM至Crashlytics
upload_symbols_to_crashlytics(
dsym_path: lane_context[SharedValues::DSYM_OUTPUT_PATH] # 读取dSYM路径
binary_path: "path/upload_symbols", #指定工具路径
)
end
5.3 验证上传
上传成功后,可在 Firebase 控制台的 "Crashlytics" 页面查看 "符号表状态",显示 "已处理" 即为成功。若失败,可检查:
-
dSYM 文件路径是否正确
-
GoogleService-Info.plist 配置是否完整
-
网络连接是否正常
6. 添加 Webhook 实现飞书机器人通知
通过 Webhook 可将构建、分发结果自动推送至飞书群,支持自定义消息格式。
6.1 创建飞书机器人
-
打开飞书群聊,进入 "设置 - 群机器人 - 添加机器人 - 自定义机器人"
-
填写机器人名称(如 "构建通知机器人"),复制 "Webhook 地址"
-
将 Webhook 地址存入
.env文件:
FEISHU_WEBHOOK_URL=https://open.feishu.cn/open-apis/bot/v2/hook/xxx
6.2 配置通知脚本
在Fastfile中定义通知方法,支持构建成功 / 失败两种场景:
# 飞书通知工具方法
def send_feishu_notification(title, content, is_success = true)
# 消息颜色:成功(绿色),失败(红色)
color = is_success ? "green" : "red"
# 消息图标:成功(✅),失败(❌)
icon = is_success ? "✅" : "❌"
# 构建飞书消息体(支持Markdown)
payload = {
msg_type: "interactive",
card: {
config: { wide_screen_mode: true },
header: {
title: { content: "#{icon} #{title}", tag: "plain_text" },
color: color
},
elements: [
{ tag: "div", text: { content: content, tag: "lark_md" } },
{ tag: "div", text: { content: "⏰ 时间:#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}", tag: "plain_text" } }
]
}
}
# 发送POST请求
response = HTTParty.post(
ENV["FEISHU_WEBHOOK_URL"],
body: payload.to_json,
headers: { "Content-Type" => "application/json" }
)
puts response.success? ? "📨 飞书通知发送成功" : "❌ 飞书通知发送失败"
end
6.3 集成到工作流
在构建、分发 lane 中添加通知逻辑,包含错误捕获:
lane :pgyer_upload do
begin
# 执行构建与上传
dev_build
pgyer(...)
# 构建成功通知
content = <<\~MARKDOWN
\*\*构建信息\*\*:
- 应用名称:MyApp-测试版
- 构建号:#{lane_context[SharedValues::BUILD_NUMBER]}
- 版本号:#{lane_context[SharedValues::VERSION_NAME]}
\*\*分发信息\*\*:
- 下载链接:[点击下载]\(#{lane_context[:PGYER_APP_URL]})
- 安装密码:123456
MARKDOWN
send_feishu_notification("测试版本分发完成", content)
rescue => ex
# 构建失败通知
send_feishu_notification("测试版本构建失败", "错误信息:#{ex.message}", false)
raise ex # 保留错误状态
end
end
6.4 扩展:钉钉 / 邮件通知
-
钉钉通知:替换飞书 Webhook 为钉钉机器人 Webhook,调整消息体格式(支持 Markdown)
-
邮件通知:使用 fastlane 的
mail动作,配置 SMTP 信息:
mail(
to: "team@example.com",
subject: "构建通知",
body: content,
smtp: {
address: "smtp.example.com",
port: 465,
user_name: "notifier@example.com",
password: "smtp_password",
enable_starttls_auto: true
}
)
7. 完整工作流示例
整合上述所有功能,最终Fastfile完整配置如下:
default_platform(:ios)
require "httparty" # 用于HTTP请求
platform :ios do
# 环境变量加载
dotenv_load(".env")
# 飞书通知工具方法
def send_feishu_notification(title, content, is_success = true)
color = is_success ? "green" : "red"
icon = is_success ? "✅" : "❌"
payload = {
msg_type: "interactive",
card: {
config: { wide_screen_mode: true },
header: {
title: { content: "#{icon} #{title}", tag: "plain_text" },
color: color
},
elements: [
{ tag: "div", text: { content: content, tag: "lark_md" } },
{ tag: "div", text: { content: "⏰ 时间:#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}", tag: "plain_text" } }
]
}
}
HTTParty.post(
ENV["FEISHU_WEBHOOK_URL"],
body: payload.to_json,
headers: { "Content-Type" => "application/json" }
)
end
# 开发环境构建
lane :dev_build do
clean
build_app(
scheme: "MyApp-Dev",
workspace: "MyApp.xcworkspace",
export_method: "development",
output_directory: "./builds/dev",
output_name: "MyApp_Dev_#{Time.now.strftime('%Y%m%d_%H%M')}",
clean: true,
include_bitcode: false
)
# 上传dSYM
upload_symbols_to_crashlytics(
gsp_path: "./MyApp/GoogleService-Info.plist",
dsym_path: lane_context[SharedValues::DSYM_OUTPUT_PATH]
)
end
# 蒲公英分发
lane :pgyer_upload do
begin
dev_build
pgyer(
api_key: ENV["PGYER_API_KEY"],
user_key: ENV["PGYER_USER_KEY"],
ipa: lane_context[SharedValues::IPA_OUTPUT_PATH],
update_description: "✅ 测试版本更新\n- 修复登录bug\n- 新增支付功能",
install_type: 1,
password: "123456"
)
content = <<\~MARKDOWN
\*\*构建信息\*\*:
\- 应用名称:MyApp-测试版
\- 构建号:#{lane_context[SharedValues::BUILD_NUMBER]}
\- 版本号:#{lane_context[SharedValues::VERSION_NAME]}
\*\*分发信息\*\*:
\- 下载链接:[点击下载]\(#{lane_context[:PGYER_APP_URL]})
\- 安装密码:123456
MARKDOWN
send_feishu_notification("测试版本分发完成", content)
rescue => ex
send_feishu_notification("测试版本构建失败", "错误信息:#{ex.message}", false)
raise ex
end
end
# App Store发布
lane :appstore_release do
begin
build_app(
scheme: "MyApp",
export_method: "app-store",
output_directory: "./builds/release",
include_bitcode: true,
export_options: {
signingStyle: "automatic",
uploadBitcode: true,
uploadSymbols: true
}
)
upload_to_app_store(
submit_for_review: false,
automatic_release: false,
price_tier: 1
)
send_feishu_notification(
"App Store构建上传完成",
"\*\*版本\*\*:#{lane_context[SharedValues::VERSION_NAME]}\n\*\*构建号\*\*:#{lane_context[SharedValues::BUILD_NUMBER]}"
)
rescue => ex
send_feishu_notification("App Store上传失败", "错误信息:#{ex.message}", false)
raise ex
end
end
end
8. 最佳实践与问题排查
8.1 安全规范
-
敏感信息(密钥、账号)务必存入
.env文件,切勿硬编码 -
将
.env添加到.gitignore,避免提交至代码仓库 -
使用 fastlane 的
match工具管理证书,实现团队共享
8.2 常见问题解决
- 安装失败:
- 网络问题:替换 Gem 源为国内镜像(如 Ruby China)
- 构建失败:
-
签名问题:检查
export_method与证书类型是否匹配 -
Scheme 问题:确保 Xcode 中 Scheme 已勾选 "Shared"
- 上传失败:
-
网络问题:配置代理或使用 VPN
-
权限问题:检查 App Store Connect 账号是否有上传权限
8.3 持续集成扩展
可将 fastlane 脚本集成到 Jenkins、GitHub Actions 等 CI/CD 平台,示例 GitHub Actions 配置(.github/workflows/build.yml):
name: Build and Deploy
on: [push]
jobs:
build:
runs-on: macos-latest
steps:
\- uses: actions/checkout@v3
\- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.2'
bundler-cache: true
\- name: Install dependencies
run: |
bundle install
pod install
\- name: Run fastlane
env:
PGYER_API_KEY: \${{ secrets.PGYER_API_KEY }}
FEISHU_WEBHOOK_URL: \${{ secrets.FEISHU_WEBHOOK_URL }}
run: bundle exec fastlane pgyer_upload
(注:文档部分内容可能由 AI 生成)