fastlane supply 上传到 Google Play 全流程指南:APK/AAB、元数据、截图与 Track 发布
【免费下载链接】fastlane🚀 The easiest way to automate building and releasing your iOS and Android apps项目地址: https://gitcode.com/GitHub_Trending/fa/fastlane
本文以 upload_to_play_store.md 为骨架,结合仓库中 supply 模块的完整源码(
supply/lib/supply/options.rb、uploader.rb、setup.rb、reader.rb等),系统讲解如何在 Google Play Store 上更新 Android 应用:从配置 Service Account 凭据、supply init初始化本地元数据目录,到上传 APK/AAB、扩展文件(.obb)、多语言图片与截图、发布说明(changelog)、灰度发布与 Track 提升,以及并行上传与supply相关的所有配置参数、默认值与校验逻辑。
supply 是 fastlane 生态中面向 Google Play 的命令行发布工具(对应 iOS 侧的 deliver)。它的核心价值在于把「上传二进制 + 维护多语言商店元数据 + 发布说明 + 截图素材」全部沉淀为仓库内可版本化的文件,并把发布流程接入 fastlane lane。读完本文,你将掌握 supply 的完整命令行用法、本地 metadata 目录规范、灰度与 Track 提升机制,以及从源码层面理解每个参数的默认值与约束。
一、supply 是什么:功能总览
supply 的自我描述是 "Command line tool for updating Android apps and their metadata on the Google Play Store"(见 supply.rb 中DESCRIPTION常量)。它能帮助你:
- 通过命令行更新 Google Play 上已有的 Android 应用;
- 上传新构建产物(APK 与 AAB);
- 读取并编辑多种语言的元数据(如标题、简介等);
- 上传应用图标、推广图与多语言截图;
- 在本地 git 仓库中维护一份元数据的本地副本;
- 从 Google Play 既有 Track 中读取 version code。
在代码层面,supply 由 supply/lib/supply 下的一组 Ruby 文件组成,核心入口是supply.rb中定义的常量和四个发布轨道(Track):
module Tracks PRODUCTION = "production" BETA = "beta" ALPHA = "alpha" INTERNAL = "internal" end同时 supply.rb 定义了 Google Play V3 API 支持的发布状态:completed、draft、halted、inProgress。后面讲到的release_status、track_promote_release_status参数都会对取值做白名单校验,其合法值正是来自这个ReleaseStatus::ALL。
二、Setup:配置 Google Developers Service Account
在一切开始之前,需要先在 Google Play Console 中完成开发者账号与 Service Account 的配置(本仓库文档中对应的就是 Google Developers Service Account 的设置章节,仓库以占位形式引入 google-credentials 说明)。核心产出物是一份 JSON 格式的密钥文件,供 supply 调用 Google Play Publisher API 认证使用。
2.1 JSON 与 p12 凭据的演进
在旧版 supply 中,凭据以.p12文件形式存放;自版本 0.4.0 起 supply 支持官方推荐的.jsonService Account 密钥文件。若要从旧格式升级:
- 重新执行一次 Setup 流程,生成正确的 JSON 文件;
- 相应更新 fastlane 配置或命令行参数以使用新参数(
json_key/json_key_data); - 升级后不再需要记录或传递
issuer参数。
旧的 p12 配置目前仍然受支持(在 options.rb 中:key与:issuer两个参数仍存在,但都已被标记为deprecated,提示文案为Use --json_key instead)。
2.2 三种凭据传参方式(源码级细节)
options.rb 中与凭据相关的参数定义如下,注意它们之间通过conflicting_options互相排斥:
| 参数 | 短选项 | 说明 | 默认值 |
|---|---|---|---|
json_key(-j) | SUPPLY_JSON_KEY | Google 凭据 JSON 文件路径(Application Default / Workload Identity / Service Account) | 取Appfile中json_key_file的值 |
json_key_data(-c) | SUPPLY_JSON_KEY_DATA | 直接传入 Google 凭据 JSON 的原始内容 | 取Appfile中json_key_data_raw的值 |
key(-k,已废弃) | SUPPLY_KEY | 用于认证的 p12 文件路径 | 目录下第一个*.p12 |
issuer(-i,已废弃) | SUPPLY_ISSUER | p12 对应的 Service Account 邮箱 | 取Appfile中issuer |
json_key有两个verify_block校验:文件必须真实存在,且必须能被解析为 JSON(调用FastlaneCore::Helper.json_file?)。json_key_data则会尝试用JSON.parse解析传入的字符串,解析失败直接报错。因此「文件名拼写错误」「内容不是合法 JSON」这两种最典型的配置错误,在参数校验阶段就会被拦截。
三、Quick Start:5 分钟上手
前提:在使用 supply 连接 Google Play Store 之前,需要先在 Play Console 手动上传至少一个构建版本,让应用完成初始创建。
快速开始四步走:
cd [your_project_folder]fastlane supply init—— 从 Google Play 拉取已有应用的元数据到本地- 修改下载下来的元数据,添加图片、截图和/或 APK
fastlane supply—— 执行发布
从源码看,fastlane supply init走的是 commands_generator.rb 中的init命令,最终调用Supply::Setup.new.perform_download;而fastlane supply走默认命令run,最终调用Supply::Uploader.new.perform_upload(见同文件default_command(:run))。
3.1 三条可用命令
fastlane supply:用本地元数据、构建产物、图片和截图更新一个应用;fastlane supply init:把一个已有应用的元数据下载到本地目录;fastlane action supply:查看 supply 的可用命令、参数与相关环境变量。
supply 既可以单独交互式运行,也可以通过传参或环境变量一次性提供所有选项以跳过问答。
3.2 下载逻辑的两个细节
阅读 setup.rb 的perform_download可以发现两个容易被忽略的行为:
- 若目标 metadata 目录已存在,
init会提示 "Metadata already exists" 并直接返回,不会覆盖你本地已有内容; - 下载时按语言把
title.txt、short_description.txt、full_description.txt、video.txt等文本逐文件写盘(AVAILABLE_METADATA_FIELDS定义于 supply.rb),并把截图按1_en-US.png这样的递增前缀命名以保持排序(截图在商店中的展示顺序依赖文件名排序)。
四、上传 APK
上传一个新的二进制到 Google Play,直接运行:
fastlane supply --apk path/to/app.apk如果你之前执行过fastlane supply init,这条命令还会同时上传本地元数据。
4.1 灰度(rollout)发布
要让新版本逐步放量,指定轨道与用户比例:
fastlane supply --apk path/app.apk --track beta --rollout 0.5在源码中,rollout的值域校验为(0.0, 1.0](见 options.rb),即必须大于 0 且不超过 1;设为1即代表完成全量放量。uploader 中 update_track 的逻辑是:当rollout介于 0 与 1 之间时,release 状态会被自动设为inProgress并携带user_fraction;否则 release 状态取release_status参数值(默认completed)。如果你上传的就是最终全量版本,可以不传rollout。
注意:track 参数曾允许 "rollout" 名称,现已废弃。若仍传入,options.rb 会直接报错 "rollout is no longer a valid track name - please use 'production' instead"。
4.2 设置应用内更新优先级
supply 支持用in_app_update_priority为版本设置应用内更新的优先级(0 到 5 的整数):
fastlane supply --apk path/app.apk --track beta --in_app_update_priority 3options.rb 对该值做了(0..5).member?校验,越界会直接 user_error。它最终被写入AndroidPublisher::TrackRelease的in_app_update_priority字段(见 uploader.rb),控制用户在安装该版本时收到的更新提示强度。
4.3 APK 默认搜索路径
如果你省略--apk参数,supply 会按默认值自动查找:当前目录下最后一个*.apk,或app/build/outputs/apk/app-Release.apk(见 options.rb)。同时apk与apk_paths、aab、aab_paths互斥,verify_block还会检查文件存在性与.apk扩展名。
4.4 扩展文件(.obb)
大体积游戏常用扩展文件。supply 会自动上传与 APK 同目录下的.obb文件,条件是:
- 文件名包含
main或patch,据此识别为 "main" 或 "patch" 类型; - 每种类型最多一个(多于一个时整次 obb 上传会被跳过并给出警告,见 uploader.rb)。
实现细节:find_obbs在 APK 所在目录用*.obbglob 查找,obb_expansion_file_type根据文件名是否含main/patch归类。
如果只想更新 APK、同时保留 Google Play 上旧版本已有的扩展文件,可显式引用旧扩展文件(分别对应 main / patch 类型,参数需成对使用):
fastlane supply --apk path/app.apk --obb_main_references_version 21 --obb_main_file_size 666154207fastlane supply --apk path/app.apk --obb_patch_references_version 21 --obb_patch_file_size 666154207其中references_version指旧扩展文件关联的版本,file_size是旧扩展文件的字节大小。对应参数见 options.rb,上传主流程在 upload_binary_data:只有「references_version 与 file_size 成对出现」时才调用update_obb。
五、上传 AAB(Android App Bundle)
上传 Android App Bundle 同样简单:
fastlane supply --aab path/to/app.aab同样地,若之前执行过supply init,会一并上传本地元数据。灰度与更新优先级用法与 APK 一致:
fastlane supply --aab path/app.aab --track beta --rollout 0.5fastlane supply --aab path/app.aab --track beta --in_app_update_priority 3AAB 的默认查找路径是当前目录最后一个*.aab或app/build/outputs/bundle/release/bundle.aab(见 options.rb)。上传由upload_bundles完成(uploader.rb),上传成功后返回 Google 分配的 version code。
源码还隐式限制:同一轮不能既传 APK 又传 AAB。verify_config! 中若检测到 APK 与 AAB 同时可上传,会直接报错并提示用skip_upload_apk/skip_upload_aab排除,或删除不再需要的本地.apk/.aab文件。这是新手最常踩的坑——工作目录里残留了旧的 APK,同时又指定了--aab。
六、多语言图片与截图
执行fastlane supply init后,会生成一个 metadata 目录,其中包含一个或多个语言目录(如en-US、en-GB),目录内有title.txt、short_description.txt这样的纯文本文件。
6.1 单张宣传图片
在某个语言目录的images文件夹里,可以放置以下固定命名的图片(扩展名支持 png、jpg、jpeg):
featureGraphiciconpromoGraphictvBanner
与文档相印证,supply.rb 中IMAGES_TYPES定义了featureGraphic、icon、tvBanner,并设置了IMAGES_FOLDER_NAME = "images"、扩展名通配{png,jpg,jpeg}。uploader.rb 用Dir.glob(search, File::FNM_CASEFOLD)查找时是不区分扩展名大小写的。
6.2 多张截图目录
在images目录下用以下子目录名组织截图,内容为 PNG 或 JPEG:
phoneScreenshots/sevenInchScreenshots/(7 英寸平板)tenInchScreenshots/(10 英寸平板)tvScreenshots/wearScreenshots/
对应源码常量SCREENSHOT_TYPES(supply.rb)。图片本身可以随意命名,但截图在 Play Store 中会按文件名字母数字顺序展示,所以建议用01_...、02_...之类的前缀控制排序。
6.3 替换而非追加(重要语义)
上传时会替换Play Store 当前页面的图片和截图,而不是在其基础上追加:upload_screenshots(uploader.rb)在默认模式下会先调用client.clear_screenshots清空对应类型的远端截图,再逐个上传本地文件。
如果你的仓库里图片频繁变动,建议开启sync_image_upload选项(SUPPLY_SYNC_IMAGE_UPLOAD,默认 false)。开启后 supply 会先对每个图片计算 sha256 并与远端比对,完全一致的跳过上传,从而避免「每次全量替换」带来的多余流量与远端图片 ID 抖动(见 uploader.rb)。
七、Changelog(What's new / 新版本特性)
每个语言目录下可建changelogs/子目录,其中每个文件的文件名必须与它所对应的 APK version code 完全一致。同时支持放一个default.txt作为兜底——当找不到与 version code 匹配的文件时,就使用这份默认文案。fastlane supply init在本地不存在metadata/目录时,会把 Google Play 上已有的 changelog 数据填充下来。
典型目录结构如下:
└── fastlane └── metadata └── android ├── en-US │ └── changelogs │ ├── default.txt │ ├── 100000.txt │ └── 100100.txt └── fr-FR └── changelogs ├── default.txt └── 100100.txt阅读 uploader.rb 的upload_changelog可确认查找优先级:先找<version_code>.txt,找不到再退而求其次用default.txt,两者都不存在则跳过该语言(不会报错)。changelog 只有在拿到具体 version code 时才会写入 release(uploader.rb的perform_upload_meta会为每次上传得到的 version code 处理 release notes)。
注意:在 Android Publisher V2 迁移到 V3 后,changelog 上传已从skip_upload_metadata中独立出来,由skip_upload_changelogs单独控制(详见后文第十节)。
八、Track Promotion:把测试版提升到生产
一个常见的 Play 发布场景是:先上传 APK 到测试 Track 验证,验证通过后把该版本提升(promote)到 production。
这由--track_promote_to参数完成。它与--track参数配合,命令 Play API 把「当前--track上处于激活状态的版本」提升到目标 Track(--track_promote_to的值)。典型用法:
fastlane supply --track beta --track_promote_to production如果 beta 上只有一个 release,该命令即可完成提升;若目标源 Track 有多个 release,需要用version_code指定要提升的版本。源码 promote_track 展示了更完整的语义:
- 在「只有
track_promote_to、没有新上传二进制」时(见 perform_upload 分支逻辑),uploader 才会走promote_track; - 可用
--version_code过滤要提升的特定 release,否则按release_status(默认completed)过滤; - 提升时的灰度行为:若同时给出
rollout(0 < rollout < 1),release 状态被置为inProgress并设置user_fraction;否则状态取track_promote_release_status(默认completed)。
提升相关参数在 options.rb 中有完整定义,包括track_promote_release_status(SUPPLY_TRACK_PROMOTE_RELEASE_STATUS)。另外文档强调:现在 Google Play 会在提升时自动把 release 从其原 Track 停用,因此旧的deactivate_on_promote选项已被标记为废弃。
九、读取 Track 的 Release Name 与 Version Code
在新版本上传前,你可能想先看看现有 Track 的 version code 或 release name;或者只是想要一个展示 production 当前线上版本号的资讯 lane。supply 提供两个读取动作:
google_play_track_version_codes:读取某个 package + track 现有的全部 version code;google_play_track_release_names:读取某个 package + track 现有的 release name。
更完整的帮助信息可运行fastlane action google_play_track_version_codes与fastlane action google_play_track_release_names查看。两个 action 在仓库中的实现分别位于 google_play_track_version_codes.rb 与 google_play_track_release_names.rb,底层复用 reader.rb 的Reader类:
track_version_codes读取后打印 "Found 'xxx' version codes in track 'yyy'";track_release_names返回该 track 下所有 release 的name数组。
与version_name的关系:version_name是在上传新 APK/AAB 时设置的 release 名称(见下文第十节),而google_play_track_release_names用于读取既有 release 的名称。二者配合可以做到「先读、比对、再发」的幂等发布流程。
十、AndroidPublisher V2 → V3 迁移(fastlane 2.135.0 起)
supply 从 Android Publisher V2 API 迁移到了 V3 API(引入于 fastlane 2.135.0),涉及一批选项的新增与废弃。这些选项在 options.rb 中均有对应实现。
10.1 新增选项
| 选项 | 环境变量 | 用途与默认值 |
|---|---|---|
version_name(-n) | SUPPLY_VERSION_NAME | 仅在通过apk_path/apk_paths/aab_path/aab_paths上传时使用,可传任意字符串(如 "October Release");默认取app/build.gradle或AndroidManifest.xml中的 versionName |
release_status(-e) | SUPPLY_RELEASE_STATUS | 上传 APK/AAB 时的 release 状态;可设为draft以便稍后再完成发布;默认completed,合法值为completed/draft/halted/inProgress |
version_code(-C) | SUPPLY_VERSION_CODE | 类型为 Integer;用于update_rollout、track_promote_to,以及元数据和截图的更新定位 |
skip_upload_changelogs | SUPPLY_SKIP_UPLOAD_CHANGELOGS | changelog 之前被包含在skip_upload_metadata内,现在独立成新选项(默认 false) |
其中release_status设为draft时,若同时给了rollout,verify_config! 会报错 "Cannot specify rollout percentage when the release status is set to 'draft'"——草稿状态的 release 不允许按比例灰度。
10.2 废弃选项
| 选项 | 说明 |
|---|---|
check_superseded_tracks(SUPPLY_CHECK_SUPERSEDED_TRACKS) | 检查其它 track 是否存在已被取代的版本并停用;现在 Google Play 会自动移除被取代的 release,故废弃 |
deactivate_on_promote(SUPPLY_DEACTIVATE_ON_PROMOTE) | promote 时停用原 track 中的二进制;Google Play 现在会在 promote 时自动停用旧 release,故废弃 |
在 options.rb 中这两个选项均带有deprecated: "Google Play does this automatically now"标记,只是为了保证旧配置兼容而保留。
十一、并行上传与线程控制
默认情况下,supply 会起 10 个线程并发上传元数据(图片、截图、文本)。若想调整,可设置环境变量DELIVER_NUMBER_OF_THREADS或FL_NUMBER_OF_THREADS,取值为 1 到 10 之间。
如果希望用超过 10 个线程并行上传,需要额外设置FL_MAX_NUMBER_OF_THREADS为期望的最大并发线程数。文档给出的警告是:这超出了官方默认设计,自行承担风险(⚠️)。
源码实现在 fastlane_core/lib/fastlane_core/queue_worker.rb:
NUMBER_OF_THREADS = ... [ENV["DELIVER_NUMBER_OF_THREADS"], ENV["FL_NUMBER_OF_THREADS"], 10] .map(&:to_i).find(&:positive?) .clamp(1, ENV.fetch("FL_MAX_NUMBER_OF_THREADS", 10).to_i)即默认取 10,DELIVER_NUMBER_OF_THREADS/FL_NUMBER_OF_THREADS可以下调或上调线程数,但最终被clamp到[1, FL_MAX_NUMBER_OF_THREADS]区间。不设置FL_MAX_NUMBER_OF_THREADS时上限恒为 10。线程模型的使用见 uploader.rb:create_meta_upload_worker中每个 job 负责某个语言目录的元数据、图片、截图与 changelog 组装,任务通过Queue收集 changelog 后再统一提交。
十二、在 fastlane lane 中集成 supply
12.1upload_to_play_storeaction
supply 在 fastlane 中的正式 action 是upload_to_play_store,定义于 upload_to_play_store.rb,并且把supply作为别名(见其example_code中的supply # alias for "upload_to_play_store")。它的关键实现是运行时用 lane context 自动回填构建产物路径:
- 若没传
apk/apk_paths,会读取 lane context 中的GRADLE_ALL_APK_OUTPUT_PATHS与GRADLE_APK_OUTPUT_PATH,多 APK 走数组、单 APK 走单文件; - 若没传
aab,会回退到GRADLE_ALL_AAB_OUTPUT_PATHS/GRADLE_AAB_OUTPUT_PATH。
这意味着你可以在 Fastfile 里先跑gradleaction 打包,再直接upload_to_play_store(track: "internal"),无需手动写产物路径。该 action 仅支持:android平台(is_supported?判断),归类于:production。
12.2 Supplyfile 与配置来源优先级
supply 也支持配置文件:run/init命令创建配置后都会调用load_supplyfile,即Supply.config.load_configuration_file('Supplyfile')(见 commands_generator.rb)。因此一个典型项目中,配置的最终生效顺序是:命令行参数 >Supplyfile(若在 fastlane 目录内)> 环境变量 >Appfile中的默认值(如package_name、json_key_file)>options.rb中的内置默认值。
Fastfile 中的常见集成示例(示意,具体值请替换为你项目的信息):
lane :beta do gradle(task: "bundle", build_type: "Release") upload_to_play_store( track: "beta", release_status: "completed", aab: "app/build/outputs/bundle/release/app-release.aab" ) end12.3 校验模式与安全发布
options.rb 提供validate_only(SUPPLY_VALIDATE_ONLY,默认 false):开启后 perform_upload 只调用client.validate_current_edit!校验改动而不会真正提交发布,适合 CI 前的演练。另有changes_not_sent_for_review(默认 false)与rescue_changes_not_sent_for_review(默认 true)控制「改动是否送审」相关行为——当 Play 要求显式送审而配置未跟上时,后者会依据错误信息自动重试调整。
十三、常用参数速查与最佳实践小结
下表汇总本文涉及参数的关键信息(均为 options.rb 中的正式定义,含环境变量名与默认值):
| 参数 | 环境变量 | 默认值 / 约束 |
|---|---|---|
package_name(-p) | SUPPLY_PACKAGE_NAME | 默认取Appfile的package_name |
track(-a) | SUPPLY_TRACK | production(默认),可选beta/alpha/internal |
rollout(-r) | SUPPLY_ROLLOUT | 无;值域(0, 1],1 表示完成灰度 |
metadata_path(-m) | SUPPLY_METADATA_PATH | ./fastlane/metadata/android或./metadata(取先存在者) |
json_key(-j) | SUPPLY_JSON_KEY | 无;文件须存在且为合法 JSON |
apk(-b) | SUPPLY_APK | 目录下最后一个*.apk,或app/build/outputs/apk/app-Release.apk |
aab(-f) | SUPPLY_AAB | 目录下最后一个*.aab,或app/build/outputs/bundle/release/bundle.aab |
apk_paths(-u)/aab_paths(-z) | SUPPLY_APK_PATHS/SUPPLY_AAB_PATHS | 数组,一次上传多个产物 |
version_name(-n) | SUPPLY_VERSION_NAME | 默认取 gradle/Manifest 的 versionName |
version_code(-C) | SUPPLY_VERSION_CODE | Integer,用于 rollout/提升/定位 changelog |
release_status(-e) | SUPPLY_RELEASE_STATUS | completed |
in_app_update_priority | SUPPLY_IN_APP_UPDATE_PRIORITY | 0–5 整数 |
obb_main_*/obb_patch_* | SUPPLY_OBB_MAIN_*/SUPPLY_OBB_PATCH_* | references_version + file_size 成对使用 |
skip_upload_apk/aab/metadata/changelogs/images/screenshots | 对应SUPPLY_SKIP_UPLOAD_* | 全部默认 false |
sync_image_upload | SUPPLY_SYNC_IMAGE_UPLOAD | false;开启后基于 sha256 跳过未变化图片 |
track_promote_to | SUPPLY_TRACK_PROMOTE_TO | 无 |
track_promote_release_status | SUPPLY_TRACK_PROMOTE_RELEASE_STATUS | completed |
validate_only | SUPPLY_VALIDATE_ONLY | false |
mapping(-d)/mapping_paths(-s) | SUPPLY_MAPPING/SUPPLY_MAPPING_PATHS | 上传混淆映射或 native debug symbols 文件 |
timeout | SUPPLY_TIMEOUT | 300 秒 |
version_codes_to_retain | — | 发布新 APK 时要保留的既有 version code 数组 |
ack_bundle_installation_warning | ACK_BUNDLE_INSTALLATION_WARNING | false;大于 150MB 的 bundle 需置 true |
几条可以沉淀进团队规范的实践建议(均由上文源码逻辑支撑):
- 凭据走 JSON:新项目一律用
json_key/json_key_data,不要再创建 p12; - 本地元数据入版本库:
supply init生成的fastlane/metadata/android纳入 git,让商店文案可评审、可回滚、可多人协作编辑; - 截图用数字前缀命名保证商店展示顺序,且上传是"全量替换"语义,务必保证本地目录与远端期望一致;
- 发布节奏:先
--track internal/beta内测,验证通过后用--track_promote_to production提升;要灰度就传rollout,全量则传 1 或不传; - APK 与 AAB 不要同时出现在工作目录(uploader 会直接拒绝),CI 中建议显式传
apk或aab参数。
相关源码与文档便于继续深挖:options.rb(全部参数)、uploader.rb(上传主流程)、setup.rb(init下载)、reader.rb(Track 信息读取)、queue_worker.rb(并行线程)、upload_to_play_store.rb(lane 内集成入口)。
【免费下载链接】fastlane🚀 The easiest way to automate building and releasing your iOS and Android apps项目地址: https://gitcode.com/GitHub_Trending/fa/fastlane
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考