ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

fastlane 全流程指南:用 upload_to_testflight(pilot)上传构建并管理 TestFlight 测试员

fastlane 全流程指南:用 upload_to_testflight(pilot)上传构建并管理 TestFlight 测试员 fastlane 全流程指南用 upload_to_testflightpilot上传构建并管理 TestFlight 测试员【免费下载链接】fastlane The easiest way to automate building and releasing your iOS and Android apps项目地址: https://gitcode.com/GitHub_Trending/fa/fastlaneupload_to_testflight 是 fastlane 提供的 TestFlight 集成 action底层由pilot工具驱动。它让你在终端中完成「上传 beta 构建 → 等待处理 → 提交内/外部测试员 → 批量管理测试员与设备」的整套发布流程。读完本文你将掌握 fastlane pilot 的全部命令、两种认证方式、关键参数与常见坑并能在 Fastfile 中用pilot/testflight别名一键执行测试发布。本文以仓库内 upload_to_testflight.md 为主线结合 pilot 子工具源码展开属于 iOS/macOS/tvOS 的 beta 分发最佳实践模块。一、pilot 与 upload_to_testflight 是什么pilot是从终端管理 Apple TestFlight 测试与构建的工具支持上传并分发构建Upload distribute builds添加、移除测试员Add remove testers查询测试员与设备信息Retrieve information about testers devices导入 / 导出全部可用测试员Import/export all available testers在 Fastfile 中upload_to_testflightaction 会调用Pilot::BuildManager#upload完成实际上传。从 upload_to_testflight.rb 可以看到它的核心逻辑非常薄读取 lane 上下文中的 IPA/PKG 输出路径与 changelog然后委托给 pilot。并且它提供了三个等价的调用名——示例代码 中明确列出upload_to_testflight testflight # upload_to_testflight 的别名 pilot # upload_to_testflight 的别名同时 is_supported? 表明该 action 只支持:ios、:mac、:tvos三个平台。也就是说以独立 CLI 使用fastlane pilot 子命令以 Fastfile action 使用upload_to_testflight/testflight/pilot两者共享同一套参数定义 pilot/lib/pilot/options.rb 和同一套执行器build_manager.rb、tester_manager.rb底层通过spaceship与 App Store Connect API 交互完成构建元数据提交通过 iTunes Transporter 上传二进制。二、认证方式API Key推荐与 Apple ID无论执行哪个子命令都需要先认证。pilot 支持两种方式可通过命令参数指定也可从项目已有 fastlane 配置中自动继承。2.1 App Store Connect API Key官方推荐只要条件允许App Store Connect API Key 是首选认证方式理由如下使用官方 App Store Connect API链路稳定无需 2FA 二次验证适合 CI 场景相比 Apple ID 登录性能更好。指定方式有两种。使用 JSON 文件fastlane pilot upload --api_key_path ./path/to/api_key_info.json或直接内联 JSON 字符串fastlane pilot upload --api_key {\key_id\: \D83848D23\, \issuer_id\: \227b0bbf-ada8-458c-9d62-3d8022b7d07f\, \key_filepath\: \D83848D23.p8\}从 options.rb 可以看出api_key_path同时支持环境变量PILOT_API_KEY_PATH与APP_STORE_CONNECT_API_KEY_PATH且会verify_block校验文件确实存在api_key支持环境变量PILOT_API_KEY/APP_STORE_CONNECT_API_KEY类型为 Hash 且标记sensitive: true不会打印到日志两者都与username互相conflicting_options即 API Key 认证和 Apple ID 认证只能二选一。在 Fastfile 中也可以先通过app_store_connect_api_key拿到密钥并放入 lane 上下文SharedValues::APP_STORE_CONNECT_API_KEY此时 upload_to_testflight.rb 会自动读取无需再传api_key除非显式传了api_key_path。登录链路对应 manager.rb优先Spaceship::ConnectAPI::Token.from生成 JWT token已有 token 则直接复用否则退回 Apple ID 账号密码登录。2.2 Apple ID传统方式使用-u指定 Apple IDfastlane pilot upload -u felixkrausefx.com如果你在已有 fastlane 配置的项目中执行username与 app identifier 会被自动推导——options.rb 会依次尝试从AppfileConfig读取:itunes_connect_id或:apple_id作为username默认值。三、上传构建Uploading builds上传新构建只需一行命令fastlane pilot upload它会自动在当前目录查找ipa文件options.rb 中default_value取目录下最新的*.ipa并尝试从 fastlane setup 中获取登录凭据。缺少的信息会交互式询问所有可用参数可通过fastlane action pilot查看。3.1 常用上传参数携带更新日志fastlane pilot upload --changelog Something that is new here只上传二进制、不触发分发相当于先只入库之后再用distribute分发给测试员fastlane pilot upload --skip_submission--skip_submission对应 options.rb 中的:skip_submission短选项-s环境变量PILOT_SKIP_SUBMISSION默认false。它会中止「提交分发」这一步但仍会尝试更新 beta 元信息。pilot 自动完成两件「魔法」从ipa文件中自动检测 bundle identifier基于 bundle identifier 自动获取 App Store Connect 上的 AppID。对应实现见 manager.rbfetch_app_identifier依次取config[:app_identifier]→ 用FastlaneCore::IpaFileAnalyser/PkgFileAnalyser从包里分析 → 最后交互询问fetch_app_platform同理支持appletvos、ios、osx、xros四种平台app_platform参数在 options.rb 中校验。3.2 上传的内部流程与「等处理」机制真正的上传在 build_manager.rb 的upload方法中完成可以概括为 5 步参数就绪检查 ipa/pkg 是否给出若同时存在两者会UI.important告警并以ipa优先强制上传pkg需将app_platform设为osx校验 changelog当distribute_external: true且既无changelog也无localized_build_info[:whats_new]时交互模式会要求输入 changelog非交互模式直接报错check_for_changelog_or_whats_new!构造上传包FastlaneCore::IpaUploadPackageBuilder或PkgUploadPackageBuilder在临时目录生成 Transporter 所需包结构Transporter 上传transporter_for_selected_team根据是否使用 JWT 分别构造ItunesTransporterbuild_manager.rb失败时输出 Transporter 错误详情等待处理并分发wait_for_build_processing_to_be_complete通过FastlaneCore::BuildWatcher轮询 App Store Connect等待构建处理完成后再调用distribute。其中等待行为受几个参数控制wait_processing_interval-k默认 30 秒——轮询间隔wait_processing_timeout_duration——超时后强制停止等待并抛出异常skip_waiting_for_build_processing-z——若设为 true 且未提供 changelog上传完成即返回完全跳过等待适合 CI 按分钟计费的场景若提供了 changelog则只等到构建出现在 App Store Connect、写入 changelog 后就提前返回见 build_manager.rb 的分支逻辑。注意skip_waiting_for_build_processing开启时distribute_external不生效构建不会分发给测试员。3.3 从 Linux 上传无 macOS/Xcode 环境也可以在 Linux 上完成上传前提是把包文件.ipa或.pkg与AppStoreInfo.plist放在磁盘同一位置如何生成可参考gym相关流程已安装 Apple 提供的 Linux 版 Transporter设置环境变量export FASTLANE_ITUNES_TRANSPORTER_USE_SHELL_SCRIPTtrue export FASTLANE_ITUNES_TRANSPORTER_PATH/usr/local/itms # 或你安装 Transporter 的路径另外要注意fastlane 会临时把上传凭证保存在$HOME/.appstoreconnect/private_keys/上传完成后该目录中的其他文件会被清理删除请勿在其中存放重要资料。四、列出所有构建pilot builds查看某个 app 的全部构建fastlane pilot builds输出会同时包含正在处理processing的构建与已激活active的构建。文档示例中的表格大致形如------------------------------ | Great App Builds | ------------------------------ | Version # | Build # | Installs | ------------------------------ | 0.9.13 | 1 | 0 | | 0.9.13 | 2 | 0 | | 0.9.20 | 3 | 0 | | 0.9.20 | 4 | 3 | ------------------------------实现上build_manager.rb 的list方法分别拉取「Processing Builds」get_build_deliveries只有 Version/Build 两列与「Builds」带betaBuildMetrics的安装数统计再用terminal-table渲染。builds子命令在 commands_generator.rb 中注册并复用与上传相同的参数集。五、分发既有构建pilot distribute如果你之前用--skip_submission只上传不分发后续可以单独执行fastlane pilot distribute它对应:distribute_only参数-D环境变量PILOT_DISTRIBUTE_ONLY。在 Fastfile 里用upload_to_testflight(distribute_only: true)也会进入纯分发分支——upload_to_testflight.rb 会先等待处理完成除非设置skip_waiting_for_build_processing再调用BuildManager#distribute。分发逻辑在 build_manager.rb未指定构建时自动拉取最近上传的构建也可用app_version/build_number精确定位分发前先更新 Beta 元信息update_beta_app_metademo account、本地化 app 信息、本地化 build 信息whats new、notify_external_testers等reject_build_waiting_for_review-b若已有构建处于「等待审核」先将其过期expire!再提交新构建expire_previous_builds过期除当前构建外的所有历史构建向外部分发要求groups参数distribute_external: true但没给groups会直接报错内部分发则默认提交给内部测试员。六、管理 Beta 测试员Managing beta testers测试员管理全部由 tester_manager.rb 负责命令注册见 commands_generator.rb。6.1 列出测试员pilot listfastlane pilot list列出该 app 下所有内部与外部测试员示例输出----------------------------------------------------- | Internal Testers | ----------------------------------------------------- | First | Last | Email | # Devices | ----------------------------------------------------- | Felix | Krause | felixkrausefx.com | 2 | ----------------------------------------------------- ----------------------------------------------------------- | External Testers | ----------------------------------------------------------- | First | Last | Email | # Devices | ----------------------------------------------------------- | Max | Manfred | emailemail.com | 0 | | Detlef | Müller | detlefkrausefx.com | 1 | -----------------------------------------------------------实际列表至少需要app_identifiercommands_generator.rb 会在缺失时直接报错实现通过Spaceship::ConnectAPI::App#get_beta_testers查询并展示各 tester 所在 group。6.2 添加测试员pilot addpilot add会把新测试员创建到 App Store Connect 账号下并关联到 app 的至少一个测试组若测试员已存在则仅完成关联fastlane pilot add emailinvite.com -g group-1,group-2如当前上下文无法自动判定 app可显式传 app identifier-afastlane pilot add emailemail.com -a com.krausefx.app -g group-1,group-2groups-g支持 group 名称或 group ID可传多个。从 tester_manager.rb 可以看到add_tester会要求必须提供 apple_id 或 app_identifier且必须提供至少一个 group随后group.post_bulk_beta_tester_assignments批量添加。tester 名与邮箱可用--first_name/--last_name/--email指定。6.3 查找测试员pilot find按邮箱查找某个 testerfastlane pilot find felixkrausefx.com输出形如------------------------------------------ | felixkrausefx.com | ------------------------------------------ | First name | Felix | | Last name | Krause | | Email | felixkrausefx.com | | Latest Version | 0.9.14 (23 | | Latest Install Date | 03/28/15 19:00 | | 2 Devices | • iPhone 6, iOS 8.3 | | | • iPhone 5, iOS 7.0 | ------------------------------------------find_tester 通过app.get_beta_testers(filter: { email: ... }, includes: apps,betaTesterMetrics,betaGroups)查询describe_tester借助beta_tester_metrics展示其最近安装版本与日期。6.4 移除测试员pilot remove移除某个测试员会同时从所有内/外部组移除fastlane pilot remove felixkrausefx.com只想把它从特定组移除时加groupsfastlane pilot remove felixkrausefx.com -g group-1,group-2从 remove_tester 的实现可见不带groups时调用tester.delete_from_apps(apps: [app])从整个 app 移除带groups时只对匹配的 group 执行delete_from_beta_groups。add/find/remove都支持一次处理多个邮箱把多个邮箱作为位置参数传入见handle_multiple。6.5 导出测试员pilot export把全部外部测试员导出为 CSV便于迁移到其他系统或新账号fastlane pilot export自定义导出路径fastlane pilot export -c ~/Desktop/testers.csvCSV 默认路径为./testers.csvtesters_file_path参数-c见 options.rb。实际导出的表头在 tester_exporter.rbFirst, Last, Email, Groups, Installed Version, Install Date。6.6 导入测试员pilot import从 CSV 批量添加外部测试员。先创建testers.csv格式为「名, 姓, 邮箱, 组1;组2」John,Appleseed,appleseed_johnmac.com,group-1;group-2再执行fastlane pilot import或指定文件fastlane pilot import -c ~/Desktop/testers.csv导入实现在 tester_importer.rb逐行读取 CSV第 4 列的分组用;分隔并映射到groups参数每行都会复用add_tester逻辑最终统计成功导入数量。导出 CSV 中由pilot export生成的Groups列同样以;连接因此可以「export → 修改 → import」完成跨账号迁移。七、在 Fastfile 中集成 upload_to_testflight除了 CLI更常见的做法是写进 Fastfile。以下是 upload_to_testflight.rb 官方示例代码整理出的几种典型写法lane :beta do # 一行上传并分发自动从 lane 上下文 / 目录探测 ipa 与凭据 upload_to_testflight # 只上传不分发 upload_to_testflight(skip_submission: true) # 显式指定账号、app 与 iTC provider upload_to_testflight( username: felixkrausefx.com, app_identifier: com.krausefx.app, itc_provider: abcde12345 # 传给 iTMSTransporter 的 -itc_provider ) # 设置 beta 描述信息与通知策略 upload_to_testflight( beta_app_feedback_email: emailemail.com, beta_app_description: This is a description of my app, demo_account_required: true, notify_external_testers: false, changelog: This is my changelog of things that have changed in a log ) end7.1 提供 Beta 审核信息beta_app_review_infoTestFlight 外测需要填写 Beta App 审核的联系方式与 demo 账号等信息可用 Hash 传入upload_to_testflight( beta_app_review_info: { contact_email: emailemail.com, contact_first_name: Connect, contact_last_name: API, contact_phone: 5558675309, demo_account_name: demoemail.com, demo_account_password: connectapi, notes: this is review note for the reviewer 3 thank you for reviewing } )该 Hash 的合法 key 在 options.rb 中限定为contact_email、contact_first_name、contact_last_name、contact_phone、demo_account_required、demo_account_name、demo_account_password、notes其他 key 会被直接拒绝。底层 update_review_detail 会把这些字段映射为 App Store Connect 的 Beta App Review Detail 属性如contactEmail、demoAccountRequired等。7.2 本地化 beta 文案localized_app_info / localized_build_info不同语言地区的测试员看到的「反馈邮箱、宣传页、隐私政策、描述、Whats New」可以分别配置upload_to_testflight( beta_app_review_info: { ... }, # 见上文 localized_app_info: { default: { feedback_email: defaultemail.com, marketing_url: https://example.com/marketing-default, privacy_policy_url: https://example.com/privacy-default, description: Default description }, en-GB: { feedback_email: en-gbemail.com, marketing_url: https://example.com/marketing-en-gb, privacy_policy_url: https://example.com/privacy-en-gb, description: en-gb description } }, localized_build_info: { default: { whats_new: Default changelog }, en-GB: { whats_new: en-gb changelog } } )localized_app_info的合法 keyfeedback_email、marketing_url、privacy_policy_url、tv_os_privacy_policy_url、descriptionlocalized_build_info的合法 keywhats_new。这些校验同样定义在 options.rb。若未使用本地化 Hashbeta_app_description/beta_app_feedback_email会被当作defaultlocale 的信息写入见update_localized_app_review。写入 build 的whats_new内容会先经过 sanitize_changelog移除 emoji 与字符Apple 不允许并截断超过 4000 字节的文本末尾追加...。7.3 导出合规与 App Clip / Routing App如需自定义的导出合规Export Compliance设置upload_to_testflight(uses_non_exempt_encryption: true)当 App Store Connect 上尚未记录加密状态uses_non_exempt_encryption.nil?时set_export_compliance_if_needed会通过patch_builds写入该字段并等待重新处理更快的做法是在Info.plist中预先设置ITSAppUsesNonExemptEncryption。此外还支持 App Clip 的app_clip_invocations、overwrite_app_clip_invocations以及路由类 App 的routing_app_coverage_file需为.geojson。八、常见问题与实用技巧Tips8.1 打开 verbose 调试输出遇到问题时用 verbose 模式拿到更详细的日志fastlane pilot upload --verbose8.2 防火墙环境与 Transporter 协议pilot 通过 iTunes Transporter 上传元数据与二进制。若身处防火墙之后可强制指定 Transporter 传输协议DELIVER_ITMSTRANSPORTER_ADDITIONAL_UPLOAD_PARAMETERS-t DAV pilot ...在 Fastfile 的 action 场景下则先设置环境变量再调用ENV[DELIVER_ITMSTRANSPORTER_ADDITIONAL_UPLOAD_PARAMETERS] -t DAV pilot两个注意点Apple 官方建议不要指定-t让 Transporter 自动探测最优传输模式。因此一旦检测到传入了t选项pilot 会发出警告-t只是可用附加参数之一该环境变量中的整段字符串都会透传给 Transporter其余参数可查阅 Transporter 用户手册按需配置。8.3 密码含特殊字符导致的凭证报错如果你的 Apple ID 密码包含特殊字符pilot 可能抛出令人困惑的 Your Apple ID or password was entered incorrectly 错误。最简单的解决办法是改用不含特殊字符的密码。8.4 密码存储在哪里pilot 使用 fastlane 的 CredentialsManager 管理登录凭据本仓库对应 credentials_manager 目录密钥会被安全地保存在系统钥匙串中。遇到密钥库问题时也可关注 account_manager.rb 的实现。8.5 多团队Provider Short Name 与 Provider Public IDProvider Short Name若账号属于多个 App Store Connect 团队Transporter 可能需要itc_providerprovider short name才能确定上传目标。pilot 默认尝试用所选团队的 long name 反查 provider short name如需覆盖自动检测值显式传入itc_provider即可。用 Transporter 查询 short name 的命令为xcrun iTMSTransporter -m provider -u USERNAME -p PASSWORD -account_type itunes_connect -v off结果第二列即 short names见 options.rbProvider Public IDprovider_public_id用于 altool 的--provider-public-id。当账号关联多个 provider、并使用用户名/App 专用密码认证时Xcode 26 之后该值为必填且会覆盖自动检测结果见 options.rb。其余团队相关参数还有team_id-q、team_name-r与dev_portal_team_id都可在多团队环境下限定目标账号。8.6 使用 App 专用密码上传当skip_waiting_for_build_processing与apple_id两个选项同时设置时pilot/upload_to_testflight可通过环境变量FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD提供的 App 专用密码完成上传。只要缺其中一个选项就会走常规 Apple 登录流程可能需要 2FA。8.7 账号角色要求构建处理完成后pilot/upload_to_testflight会更新构建信息与测试员信息。App Store Connect 要求账号具备 App Manager 或 Admin 角色才能执行这些更新Developer 角色可以上传构建但无法更新构建信息与测试员。若你的 CI 账号是 Developer 角色建议提升权限或改用 App Store Connect API Key。九、完整参数速查核心以下为 pilot/lib/pilot/options.rb 中定义的核心参数节选含短选项、环境变量与默认值可在fastlane pilot 子命令或 Fastfile 中混用参数短选项环境变量默认值说明api_key_path—PILOT_API_KEY_PATH/APP_STORE_CONNECT_API_KEY_PATH—App Store Connect API Key JSON 路径api_key—PILOT_API_KEY/APP_STORE_CONNECT_API_KEY—API Key Hash敏感信息username-uPILOT_USERNAMEAppfile 推导Apple ID 用户名app_identifier-aPILOT_APP_IDENTIFIER目录 ipa / Appfile 推导目标 App 的 bundle idapp_platform-mPILOT_PLATFORM包内推导ios/appletvos/osx/xrosapple_id-pPILOT_APPLE_IDTESTFLIGHT_APPLE_IDApp Store Connect「App 信息」中的 Apple ID数字会校验不能是邮箱或 bundle idipa-iPILOT_IPA目录最新*.ipa待上传 ipa 路径与pkg互斥pkg-PPILOT_PKG目录最新*.pkg待上传 pkg 路径与ipa互斥changelog-wPILOT_CHANGELOG—“What to Test” 文案skip_submission-sPILOT_SKIP_SUBMISSIONfalse只上传不分发skip_waiting_for_build_processing-zPILOT_SKIP_WAITING_FOR_BUILD_PROCESSINGfalse跳过或部分跳过处理等待适合 CIdistribute_only-DPILOT_DISTRIBUTE_ONLYfalse只分发既有构建distribute_external—PILOT_DISTRIBUTE_EXTERNALfalse是否分发外部测试员需groupsnotify_external_testers—PILOT_NOTIFY_EXTERNAL_TESTERSApp Store Connect 默认是否通知外部测试员beta_app_description-dPILOT_BETA_APP_DESCRIPTION—Beta App 描述beta_app_feedback_email-nPILOT_BETA_APP_FEEDBACK—Beta App 反馈邮箱beta_app_review_info—PILOT_BETA_APP_REVIEW_INFO—审核联系人/demo 账号 Hashlocalized_app_info—PILOT_LOCALIZED_APP_INFO—按语言分组的 App 信息 Hashlocalized_build_info—PILOT_LOCALIZED_BUILD_INFO—按语言分组的 build 信息 Hashdemo_account_required—DEMO_ACCOUNT_REQUIRED—Beta 审核是否需要 demo 账号uses_non_exempt_encryption-XPILOT_USES_NON_EXEMPT_ENCRYPTIONfalse导出合规声明app_version/build_number—PILOT_APP_VERSION/PILOT_BUILD_NUMBER—定位待分发构建expire_previous_builds—PILOT_EXPIRE_PREVIOUS_BUILDSfalse过期历史构建reject_build_waiting_for_review-bPILOT_REJECT_PREVIOUS_BUILDfalse过期「等待审核」的旧构建email/first_name/last_name-e/-f/-lPILOT_TESTER_*—测试员信息add/find/remove 用testers_file_path-cPILOT_TESTERS_FILE./testers.csv测试员导入/导出 CSV 路径groups-gPILOT_GROUPS—测试组名或组 ID外部分发/加组必填team_id/team_name-q/-rPILOT_TEAM_ID/PILOT_TEAM_NAMEAppfile 推导多团队选择itc_provider—PILOT_ITC_PROVIDER自动探测Transporter 的 provider short nameprovider_public_id—PILOT_PROVIDER_PUBLIC_ID自动探测altool 的 provider public IDXcode 26 多 provider 场景wait_processing_interval-kPILOT_WAIT_PROCESSING_INTERVAL30处理轮询间隔秒wait_processing_timeout_duration—PILOT_WAIT_PROCESSING_TIMEOUT_DURATION—处理等待超时秒超时抛异常app_clip_invocations—PILOT_APP_CLIP_INVOCATIONS—为构建添加 App Clip 调用点routing_app_coverage_file—PILOT_ROUTING_APP_COVERAGE_FILE—routing app 的.geojson覆盖文件submit_beta_review—PILOT_DISTRIBUTE_EXTERNALtrue是否送审十、相关源码与测试线索如需深入理解各命令行为可按如下路径继续阅读仓库Action 入口与示例fastlane/lib/fastlane/actions/upload_to_testflight.rb全部参数定义pilot/lib/pilot/options.rb上传 / 等待 / 分发主流程pilot/lib/pilot/build_manager.rb登录与 App/平台探测pilot/lib/pilot/manager.rb测试员增删查pilot/lib/pilot/tester_manager.rb测试员导入导出pilot/lib/pilot/tester_importer.rb、pilot/lib/pilot/tester_exporter.rbCLI 子命令注册pilot/lib/pilot/commands_generator.rb测试覆盖可参考 pilot/spec如 build_manager_spec.rb、commands_generator_spec.rb、tester_importer_spec.rb 等结合文档与源码可以看到upload_to_testflight的价值在于把「二进制上传、处理等待、元信息更新、分组分发」这条原本依赖 Xcode Organizer 或网页手动操作的链路收敛为可脚本化、可进 CI、可参数化的一个 action——这正是 fastlane「自动化测试版发布」理念在 TestFlight 上的落点。【免费下载链接】fastlane The easiest way to automate building and releasing your iOS and Android apps项目地址: https://gitcode.com/GitHub_Trending/fa/fastlane创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表