fastlane-plugin-fastci 0.0.30 → 0.0.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9eadcd995669c5cfd0d4d8a28b68667d0d18cdd710864eed98ed142e285c9b93
4
- data.tar.gz: 2fa4908e62aedb5faa2ad21a5f6d4d5e210bf609848721c621856c84f80e9741
3
+ metadata.gz: 834603cf8a0a78c4fec22ee9f17d84a5f491d25770b2972c3e85b0b5ffcfcc27
4
+ data.tar.gz: a9ded28f219cd9215058581204ac445601479c0978b4e393f99ed0835f6fe461
5
5
  SHA512:
6
- metadata.gz: 1606d02bc136b88b61652ad9218f7a3428ba36a516eb578d738328b12750abeb04b9caa7f30eebe790efae4e4019961c6429089f8d0d247cdc8ebd76e5ad2252
7
- data.tar.gz: 3cf569702228448922d1d20e296900fc2c7594d3c51d3f82ef6ea0e88addc85227f27c3ea050a81ad45ce0630e5a5647aeab82a800b3433e8430eb31fc555d7a
6
+ metadata.gz: ad0be57cc0708ecdf1b920bb1c3ebff28b94a25a10adde0e7be43b4ba967b9bf95a95d3a3946b6c06ba24fec1d05cd84e91a38e8a313d80868d5c4589a0a084e
7
+ data.tar.gz: b17392ce988cc5279ef375a8a474288cb51183d7dd0a4b8ec4191351162cb0bc6204e1a782af7f53b9505aab27832cd4666c33cf39208923869245dcc5c9ed06
data/README.md CHANGED
@@ -25,14 +25,13 @@
25
25
 
26
26
  ## 使用方法
27
27
 
28
- 参考 [` Fastfile `](fastlane/Fastfile) 和 [` .env.default `](fastlane/.env.default) 替换项目内 fastlane 文件夹下文件;
28
+ 参考 [Fastfile](fastlane/Fastfile),将[配置模板](fastlane/.env.default.example)复制为项目中的 `fastlane/.env.default`,再填写项目参数;
29
29
  项目根目录新建 ` PACKAGE_FILE_FOLDER_NAME ` 配置对应名字文件夹,将描述文件、p12 证书、p8 密钥等文件放入该文件夹下;
30
30
  然后终端进入项目根目录即可使用 ` fastlane `
31
31
 
32
- 如果是同一个 xcworkspace 多 xcodeproj 的情况,可以采用多配置文件的方式。同样也是参考 [` .env.default `](fastlane/.env.default) 根据多个 xcodeproj 创建多个配置文件 ` .env.project1 ` 、 ` .env.project2 `,注意文件的隐藏扩展,名字不能是 ` .env.project1.default `;
32
+ 如果是同一个 xcworkspace 多 xcodeproj 的情况,可以采用多配置文件的方式。同样参考[配置模板](fastlane/.env.default.example),根据多个 xcodeproj 创建配置文件 ` .env.project1 `、` .env.project2 `;运行配置不保留 `.example` 后缀,名字也不能是 ` .env.project1.default `;
33
33
  不同的配置文件配置不同的 ` PROJECT_NAME `;
34
- 执行的时候指定环境文件 ` fastlane --env project1 package ` 来运行
35
-
34
+ 使用本仓库示例 Fastfile 时,指定环境文件执行 `bundle exec fastlane ios ipaPackage --env project1`。
36
35
 
37
36
  ### 使用后会在项目根目录生成文件夹
38
37
 
@@ -54,6 +53,7 @@ fastlane_cache/ # 插件缓存文件夹
54
53
  生成完的 ipa 会放在桌面上,非 ` app-store ` 配置了蒲公英或 fir 参数会自动上传蒲公英或 fir。` app-store ` 和 ` testFlight ` 配置了商店参数会自动上传商店。
55
54
  配置了 Sentry 参数会自动上传符号表。
56
55
  配置了 Zealot 参数的非商店包也可自动上传,详见下方 Zealot 配置。
56
+ App Store 元数据、截图和更新说明默认不上传,必须单独开启商店资源总开关并配置资源 JSON;详见 [App Store 元数据与截图](#app-store-resources)。TestFlight 不使用商店资源配置。
57
57
 
58
58
  ` build `: 不指定的话内部有递增逻辑,格式为 ` 20250905.15(日期+当天包的次数) `
59
59
 
@@ -71,8 +71,10 @@ package(
71
71
  is_detect_duplicity_code: false, # 是否检测重复代码
72
72
  is_detect_unused_code: false, # 是否检测未使用代码
73
73
  is_detect_unused_image: false, # 是否检测未使用图片
74
- changelog: options[:changelog], # fir 更新日志
75
- release_notes: options[:release_notes], # 配合 jenkins 传参上传 appstore 格式为 { \"zh-Hans\": \"修复问题\", \"en-US\": \"bugfix\"} JSON 字符串
74
+ changelog: options[:changelog], # fir / Zealot 更新日志,也是各平台钉钉通知的更新说明
75
+ app_store_resources_enabled: options[:app_store_resources_enabled], # 总开关;未传时读取 APP_STORE_RESOURCES_ENABLED,默认 false
76
+ app_store_resources_config_path: options[:app_store_resources_config_path], # 未传时读取 APP_STORE_RESOURCES_CONFIG_PATH
77
+ release_notes: options[:release_notes], # JSON 字符串,例如 '{"zh-Hans":"修复问题","en-US":"Bug fixes"}';仅资源功能开启且上传 metadata 时生效
76
78
  is_notice_dingding: options[:is_notice_dingding] # 配置钉钉token了,通过该参数控制是否发送通知
77
79
  )
78
80
  ```
@@ -125,7 +127,225 @@ detect_unused_image(
125
127
 
126
128
  ---
127
129
 
128
- ### 6. Zealot(仅 iOS)
130
+ <a id="app-store-resources"></a>
131
+
132
+ ### 6. App Store 元数据与截图(配置驱动,仅 iOS)
133
+
134
+ 通过独立 `app_store_resources` Action 管理商店名称、副标题、描述、关键词、更新说明、宣传文本、支持/隐私链接、分类、审核信息及截图,沿用 Fastlane 的 metadata 目录格式。也可以接入现有 `package` / `upload_store` 流程:先上传 IPA,再上传配置指定的资源,最后按需选择 Build、提交审核。
135
+
136
+ **商店资源总开关默认关闭,必须设置 `APP_STORE_RESOURCES_ENABLED=true`,或显式传入 `app_store_resources_enabled: true` 才能使用。** 只配置 JSON 路径、资源目录、`metadata_changed` 或 `release_notes` 均不会开启功能。关闭时,`package` / `upload_store` 仅上传 IPA,明确跳过元数据、截图和更新说明;独立 `app_store_resources` 直接跳过,不读取资源配置、不认证、不上传下载、不选择构建或提交审核。TestFlight 和测试包不使用商店资源流程。
137
+
138
+ | 入口 | 用途 | 开启后的配置要求 |
139
+ | --- | --- | --- |
140
+ | `package` | 打包并上传 IPA,再执行资源流程 | 必须提供 `app_store_resources_config_path`;自动传入本次 Bundle ID、版本和 Build |
141
+ | `upload_store` | 上传已有 gym 产物,再执行资源流程 | 必须提供 `app_store_resources_config_path`;需要选择构建时自行提供版本与 Build |
142
+ | `app_store_resources` | 独立更新商店资源,不上传 IPA | 使用 `config_path` 或直接传入资源参数 |
143
+
144
+ #### 配置与认证
145
+
146
+ 将 [`fastlane/app_store_resources.example.json`](fastlane/app_store_resources.example.json) 复制到业务项目,例如 `fastlane/app_store_resources.json`,修改 Bundle ID、版本和资源路径。使用**扁平 JSON**;项目自有的嵌套 Jenkins 配置需要先转换为模板中的字段。
147
+
148
+ ```dotenv
149
+ # 总开关,未设置或 false 时均不能使用商店资源功能。
150
+ APP_STORE_RESOURCES_ENABLED=true
151
+ # 相对路径以执行 Action 时的项目根目录为基准,不以 JSON 所在目录为基准。
152
+ APP_STORE_RESOURCES_CONFIG_PATH=fastlane/app_store_resources.json
153
+
154
+ # 认证方式一:App Store Connect API Key JSON(本机或 CI 密钥文件)。
155
+ APP_STORE_CONNECT_API_KEY_PATH=/secure/app-store-connect.json
156
+
157
+ # 认证方式二:沿用 CONNECT_KEY_ID、CONNECT_ISSUER_ID 和证书目录下的 P8。
158
+ # 可选 APP_STORE_CONNECT_P8_PATH=/secure/AuthKey_KEYID.p8 覆盖默认路径。
159
+ ```
160
+
161
+ | 环境变量 | 默认值 | 说明 |
162
+ | --- | --- | --- |
163
+ | `APP_STORE_RESOURCES_ENABLED` | `false` | 商店资源总开关;未设置与关闭效果相同 |
164
+ | `APP_STORE_RESOURCES_CONFIG_PATH` | 未设置 | 资源 JSON 路径;`package` / `upload_store` 开启资源功能后必填 |
165
+ | `APP_STORE_CONNECT_API_KEY_PATH` | 未设置 | 认证用 API Key JSON 路径,与资源 JSON 是两个不同文件 |
166
+ | `APP_STORE_CONNECT_P8_PATH` | 未设置 | 自定义 P8 路径,配合 `CONNECT_KEY_ID`、`CONNECT_ISSUER_ID` 使用;不配置时从 `PACKAGE_FILE_FOLDER_NAME/AuthKey_<KEY_ID>.p8` 读取 |
167
+
168
+ 认证方式二的环境配置示例:
169
+
170
+ ```dotenv
171
+ CONNECT_KEY_ID=your-key-id
172
+ CONNECT_ISSUER_ID=your-issuer-id
173
+ APP_STORE_CONNECT_P8_PATH=/secure/AuthKey_your-key-id.p8
174
+ ```
175
+
176
+ 使用 P8 方式时不设置 `APP_STORE_CONNECT_API_KEY_PATH`。资源 JSON 或显式参数中的认证优先,其次是环境中的 API Key JSON、已有 lane 的 API Key,最后使用 P8 配置。已有 API Key 可直接复用,无需每次重新创建。
177
+
178
+ 资源配置示例:
179
+
180
+ ```json
181
+ {
182
+ "app_identifier": "com.example.app",
183
+ "app_version": "1.0.0",
184
+ "metadata_path": "fastlane/metadata",
185
+ "screenshots_path": "fastlane/screenshots",
186
+ "metadata_changed": true,
187
+ "screenshots_changed": false,
188
+ "upload_metadata_on_new_version": true,
189
+ "select_build": false,
190
+ "submit_for_review": false,
191
+ "automatic_release": false
192
+ }
193
+ ```
194
+
195
+ #### 元数据与截图目录
196
+
197
+ 元数据内容存放于文本文件,语言目录名与 App Store Connect 语言代码对应,例如:
198
+
199
+ ```text
200
+ fastlane/metadata/
201
+ ├── copyright.txt
202
+ ├── primary_category.txt
203
+ ├── review_information/notes.txt
204
+ ├── zh-Hans/
205
+ │ ├── name.txt
206
+ │ ├── subtitle.txt
207
+ │ ├── description.txt
208
+ │ ├── keywords.txt
209
+ │ ├── promotional_text.txt
210
+ │ ├── support_url.txt
211
+ │ ├── privacy_url.txt
212
+ │ └── release_notes.txt
213
+ └── en-US/
214
+ ├── description.txt
215
+ └── release_notes.txt
216
+ fastlane/screenshots/zh-Hans/1.png
217
+ ```
218
+
219
+ 只更新文案时设置 `metadata_changed=true`、`screenshots_changed=false`;只更新截图时设置 `metadata_changed=false`、`screenshots_changed=true`。如果还要禁止新版本自动补传文案,需同时设置 `upload_metadata_on_new_version=false`。上传的资源类别必须有非空目录,截图支持 `.png`、`.jpg`、`.jpeg`,图片格式和设备尺寸由 deliver 校验。
220
+
221
+ #### Action 与命令行调用
222
+
223
+ 总开关开启后,在已有打包 lane 中配置资源路径即可使用;也可以显式传入开关和路径:
224
+
225
+ ```ruby
226
+ package(
227
+ export_method: "app-store",
228
+ app_store_resources_enabled: true,
229
+ app_store_resources_config_path: "fastlane/app_store_resources.json"
230
+ )
231
+
232
+ # 只更新商店资源,不重新构建、不上传 IPA。
233
+ app_store_resources(
234
+ app_store_resources_enabled: true,
235
+ config_path: "fastlane/app_store_resources.json"
236
+ )
237
+
238
+ # 已有 gym 产物时,上传 IPA 后更新资源。
239
+ upload_store(
240
+ app_store_resources_enabled: true,
241
+ app_store_resources_config_path: "fastlane/app_store_resources.json"
242
+ )
243
+ ```
244
+
245
+ 总开关只通过环境变量或 Action 参数配置,不放在资源 JSON 中;显式 Action 参数优先于环境变量,因此传 `app_store_resources_enabled: false` 可以关闭环境中已开启的功能。`package` / `upload_store` 开启后必须同时提供资源配置路径,否则报错;独立 Action 开启后也可直接传入资源参数。
246
+
247
+ 使用本仓库示例 [Fastfile](fastlane/Fastfile) 时,可以在业务项目根目录运行以下命令。命令会执行实际上传,运行前应替换配置中的示例值并准备对应资源和认证文件。
248
+
249
+ ```bash
250
+ # 打包、上传 App Store IPA,再更新资源;开关、资源路径和认证读取环境文件。
251
+ bundle exec fastlane ios ipaPackage export_method:app-store
252
+
253
+ # 只更新商店资源;开关、资源路径和认证读取环境文件。
254
+ bundle exec fastlane ios appStoreResources
255
+
256
+ # 也可以在调用时明确开启,并为独立资源 lane 指定配置文件。
257
+ bundle exec fastlane ios appStoreResources app_store_resources_enabled:true config_path:fastlane/app_store_resources.json
258
+
259
+ # 本次仅上传 IPA,即使环境文件已开启资源功能也不更新资源。
260
+ bundle exec fastlane ios ipaPackage export_method:app-store app_store_resources_enabled:false
261
+ ```
262
+
263
+ 多项目环境可在命令后追加 `--env project1`。示例 lane 名是 `ipaPackage` 和 `appStoreResources`;已有项目使用自定义 lane 时,在对应 lane 中调用上面的 Action 即可。
264
+
265
+ #### 资源 JSON 参数
266
+
267
+ | JSON 参数 | 默认值 | 用途 |
268
+ | --- | --- | --- |
269
+ | `app_identifier` | `BUNDLE_ID` | 应用的 Bundle ID,最终不能为空 |
270
+ | `app_version` | 未设置 | 目标商店版本;选择构建或提交审核时必填 |
271
+ | `build_number` | 未设置 | 精确 Build 号;选择构建或提交审核时必填,使用字符串 |
272
+ | `metadata_path` / `screenshots_path` | `fastlane/metadata` / `fastlane/screenshots` | 相对路径以项目根目录为基准;未启用的资源类别不要求目录存在 |
273
+ | `metadata_changed` | `true` | 上传 metadata;设为 `false` 可跳过 |
274
+ | `screenshots_changed` | `false` | 上传截图,需显式开启 |
275
+ | `upload_metadata_on_new_version` | `true` | 指定 `app_version` 且目标可编辑版本不存在时补传 metadata,即使 `metadata_changed=false` |
276
+ | `download_missing_metadata` / `download_missing_screenshots` | `false` | 从 App Store Connect 初始化空的资源目录;不覆盖已有本地资源 |
277
+ | `use_live_version` | `false` | 初始化截图时使用线上版本 |
278
+ | `sync_screenshots` / `overwrite_screenshots` | `false` | 同步或替换远端截图,仅 `screenshots_changed=true` 时生效;同步还需 `FASTLANE_ENABLE_BETA_DELIVER_SYNC_SCREENSHOTS=true` |
279
+ | `select_build` | `false` | 按 `app_version` + `build_number` 选择处理完成的精确构建 |
280
+ | `wait_for_build_processing` | `true` | 选择构建前等待 Apple 处理 |
281
+ | `build_processing_timeout` / `build_processing_poll_interval` | `3600` / `30` | 等待超时和轮询间隔,单位秒 |
282
+ | `build_processing_retry_limit` / `build_processing_retry_interval` | `3` / `15` | 临时网络错误的重试次数和间隔,仍受总超时约束 |
283
+ | `submit_for_review` / `automatic_release` | `false` | 显式开启审核提交、审核通过后自动发布 |
284
+ | `release_notes` | 未设置 | 按语言提供更新说明的 JSON 对象,覆盖对应 `release_notes.txt` |
285
+ | `submission_information` | 未设置 | 提交审核所需的出口合规等信息 |
286
+ | `api_key_path` / `api_key` | 未设置 | API Key JSON 路径或 Key Hash,二者互斥 |
287
+ | `username` | 未设置 | 使用 Apple ID 登录时的用户名 |
288
+ | `platform` | `ios` | 当前资源 Action 仅支持 iOS |
289
+ | `force` | `true` | 跳过 deliver 的 HTML 预览确认 |
290
+
291
+ 配置优先级为**显式 Action 参数 > JSON > 默认值**。`package` 会用本次实际的 Bundle ID、版本号和 Build 号覆盖 JSON,避免选择旧构建;独立调用需要自行填写目标版本和构建号。开启 `select_build` 或 `submit_for_review` 时,两者均为必填。传给 `package` / `upload_store` 的 `release_notes` 仍沿用原 JSON 字符串格式,仅在上传 metadata 时生效。
292
+
293
+ #### 常见使用场景
294
+
295
+ 以下资源操作均以总开关已开启为前提。资源的变更开关由项目或 CI 设置,插件不自行运行 Git 差异检测。
296
+
297
+ | 场景 | 关键配置 |
298
+ | --- | --- |
299
+ | 只上传 IPA | 总开关关闭;不执行资源流程 |
300
+ | 只修改文案 | `metadata_changed=true`,`screenshots_changed=false`,调用独立资源 Action |
301
+ | 只更新截图 | `metadata_changed=false`,`screenshots_changed=true`,`upload_metadata_on_new_version=false` |
302
+ | 上传 IPA 后绑定本次构建 | 调用 `package`,资源 JSON 中配置 `select_build=true`;版本和 Build 使用本次产物值 |
303
+ | 仅选择已有构建 | 独立调用时提供 `app_version`、`build_number`,设置 `select_build=true`、两个 `*_changed=false`、`upload_metadata_on_new_version=false` |
304
+ | 提交审核 | 设置 `submit_for_review=true` 并提供版本与 Build;先确认构建处理成功并绑定,再提交审核 |
305
+
306
+ `select_build`、`submit_for_review`、`automatic_release` 均默认关闭。等待处理超时、构建处理失败或可编辑版本不匹配时会报错,不会改选其他构建。`automatic_release` 只控制本次审核通过后的发布方式,需配合 `submit_for_review=true` 使用。
307
+
308
+ 首次只下载资源时,可以直接调用:
309
+
310
+ ```ruby
311
+ app_store_resources(
312
+ app_store_resources_enabled: true,
313
+ app_identifier: "com.example.app",
314
+ metadata_path: "fastlane/metadata",
315
+ screenshots_path: "fastlane/screenshots",
316
+ metadata_changed: false,
317
+ screenshots_changed: false,
318
+ upload_metadata_on_new_version: false,
319
+ download_missing_metadata: true,
320
+ download_missing_screenshots: true,
321
+ use_live_version: true,
322
+ select_build: false,
323
+ submit_for_review: false,
324
+ automatic_release: false
325
+ )
326
+ ```
327
+
328
+ 此例的认证仍读取环境配置,截图使用已有线上版本;尚无线上版本时,需使用可编辑版本并设置 `use_live_version=false`。下载只初始化空的资源类别,不覆盖本地已有文案或截图。
329
+
330
+ #### 旧用法与失败处理
331
+
332
+ - 旧 lane 仅传 `release_notes` 时,现在只上传 IPA;要上传更新说明,必须开启总开关并提供资源配置,且允许上传 metadata。
333
+ - 总开关关闭时,资源路径和资源子开关不会生效,`Deliverfile` 中开启截图同步也不会绕过 IPA 上传阶段的禁用设置。
334
+ - `package` 开启资源功能但未配置路径时,会在构建前报错;`upload_store` 会在认证或上传前报错。
335
+ - 开启后的 JSON 格式错误、未知字段、无效参数类型或空资源目录会终止任务。若资源上传失败,后续构建选择和审核提交不会继续;已成功上传的 IPA 不会回滚。
336
+ - TestFlight、Zealot、Fir 和蒲公英不使用商店资源总开关。
337
+
338
+ 仅查看参数说明、不会触发上传的命令:
339
+
340
+ ```bash
341
+ bundle exec fastlane action package
342
+ bundle exec fastlane action upload_store
343
+ bundle exec fastlane action app_store_resources
344
+ ```
345
+
346
+ 目录格式和字段遵循 [Fastlane deliver 文档](https://docs.fastlane.tools/actions/deliver/)。
347
+
348
+ ### 7. Zealot(仅 iOS)
129
349
 
130
350
  通过官方 [fastlane-plugin-zealot](https://github.com/tryzealot/fastlane-plugin-zealot) 封装以下独立 Action:
131
351
 
@@ -136,7 +356,7 @@ detect_unused_image(
136
356
  | `check_zealot_version` | 按 Bundle ID、版本号或 commit 查询版本 |
137
357
  | `sync_zealot_devices` | 将 Apple 开发者账号中的 iOS 设备同步到 Zealot |
138
358
 
139
- 在本机环境文件或 CI 密钥中配置,真实 token 不要提交到仓库:
359
+ 在环境文件或 CI 环境变量中配置:
140
360
 
141
361
  ```dotenv
142
362
  ZEALOT_ENDPOINT=https://zealot.example.com
@@ -181,6 +401,155 @@ sync_zealot_devices(api_key_path: "./app_store_connect_api_key.json")
181
401
 
182
402
  依赖兼容:Zealot 的 `debug_file` 依赖 `ruby-macho < 3`,不能与 CocoaPods 1.17(依赖 4.x)放在同一 bundle。此类工程应将 CocoaPods 放入独立 Gemfile;使用 Faraday 1 的 Fastlane 工程还应将 `faraday-net_http` 限制为 `~> 1.0`。
183
403
 
404
+ ### 8. 钉钉通知
405
+
406
+ `package` 使用统一的 Markdown 模板发送分发结果、失败及检查结果。配置 `DINGDING_TOKEN` 后默认开启,传入 `is_notice_dingding: false` 可关闭本次流程的全部通知。机器人配置参考[钉钉自定义机器人文档](https://open.dingtalk.com/document/robots/custom-robot-access),关键词可设为 `iOS`。
407
+
408
+ ```dotenv
409
+ DINGDING_TOKEN=
410
+ DINGDING_INCLUDE_INSTALL_PASSWORD=true
411
+ DINGDING_TESTFLIGHT_URL=
412
+ DINGDING_APP_STORE_URL=
413
+ ```
414
+
415
+ | 配置 | 默认值 | 用途 |
416
+ | --- | --- | --- |
417
+ | `DINGDING_TOKEN` | 未设置 | 群机器人的 `access_token`;未配置时不发送 |
418
+ | `is_notice_dingding` | `true` | `package` 参数;`false` 优先于 Token 配置 |
419
+ | `DINGDING_INCLUDE_INSTALL_PASSWORD` | `true` | 是否展示蒲公英 / fir 的安装密码;`false` 时隐藏 |
420
+ | `DINGDING_TESTFLIGHT_URL` | 未设置 | TestFlight 公开测试邀请链接,配置后展示 |
421
+ | `DINGDING_APP_STORE_URL` | 未设置 | App Store 线上应用页面,配置后展示 |
422
+
423
+ #### 统一内容与发送时机
424
+
425
+ 标题为 `应用 Scheme iOS · 平台 · 状态`。各平台均包含应用、Bundle ID、分发平台、状态、实际版本、Build、打包方式、构建配置、累计耗时和通知时间;时间包含构建机器的时区偏移。`changelog` 有值时追加更新说明,最多展示 1,000 个字符。缺失的可选字段与链接不展示。
426
+
427
+ 更新说明保留输入的逐行内容,LF / CRLF 换行会转换为 Markdown 强制换行,避免多条 Git 提交显示成一段;该格式转换仅用于钉钉展示,不修改上传平台收到的日志原文。
428
+
429
+ 二维码由构建机下载后,以 `data:image/...;base64,...` 内嵌到同一条 Markdown 通知,保留「打开二维码」链接。接受 PNG / JPEG / GIF,单图上限 8 KB,连接超时 5 秒、下载总超时 15 秒;下载失败、格式不符或超过上限时只展示链接,不中断打包。Base64 展示采用当前使用环境已验证的方式;[钉钉官方消息类型文档](https://open.dingtalk.com/document/orgapp/custom-bot-send-message-type)未明确承诺 Data URL 的跨客户端支持。
430
+
431
+ - IPA 构建并复制完成后仅记录终端日志,不发送钉钉成功通知。
432
+ - 蒲公英、fir、Zealot、TestFlight 和 App Store 在各自上传结束后发送一次平台结果;同时上传多个平台时,每个平台各一条。
433
+ - 商店包缺少上传配置时发送「未上传」,说明 IPA 已生成;未配置测试分发平台且未执行检查时,构建成功不发送通知。
434
+ - 构建、分发、符号上传或检查抛出异常时,发送当前平台和失败阶段,随后保留原有异常处理。原始异常详情仍在构建日志中。
435
+ - Zealot 关闭 `fail_on_error` 后未返回发布结果时,发送「上传未完成」,按原配置继续流程。
436
+ - 只有实际执行了代码检查,才发送检查项目清单;这表示检查执行完成,问题详情查看报告。App Store / TestFlight 跳过检查时不发送检查完成通知。
437
+ - 钉钉发送超时、HTTP 失败或机器人拒绝消息时,只记录提示,不改变打包结果。不再发送「测试一下」。
438
+
439
+ 发送使用系统 `/usr/bin/curl`,保留 HTTPS 证书校验,连接超时 5 秒、整个请求超时 15 秒;Token 与正文通过标准输入传入,不出现在命令参数中。终端会记录发送开始及成功,失败时区分 curl 退出码、HTTP 状态码和钉钉 `errcode`,不打印凭据或原始响应。
440
+
441
+ 通知由 `package` 统一编排;直接调用 `upload_pgy`、`upload_fir`、`upload_zealot`、`upload_store` 或 `app_store_resources` 不额外发送这套通知。
442
+
443
+ #### 各分发平台内容
444
+
445
+ 下面五份示例使用同一套公共字段;安装密码、链接、二维码只在配置或上传结果提供时出现。示例中的更新说明来自 `package(changelog: "修复问题,优化体验")`,不会自动读取 metadata 目录中的文案。
446
+
447
+ **蒲公英**:安装页面、安装二维码、安装密码。地址使用上传接口返回的实际地址。
448
+
449
+ ```text
450
+ 📦 ExampleApp iOS · 蒲公英 · 上传完成
451
+ 应用:ExampleApp
452
+ Bundle ID:com.example.app
453
+ 分发平台:蒲公英
454
+ 状态:上传完成
455
+ 版本:1.2.3
456
+ Build:42
457
+ 打包方式:ad-hoc
458
+ 构建配置:Release
459
+ 安装密码:example-password
460
+ 累计耗时:180 秒
461
+ 通知时间:2026-11-03 12:00:00 +08:00
462
+ [安装页面]
463
+ [安装二维码]
464
+ 更新说明:修复问题,优化体验
465
+ ```
466
+
467
+ **fir**:安装页面、安装密码。当前上传接口不提供二维码,因此不生成二维码链接。
468
+
469
+ ```text
470
+ 📦 ExampleApp iOS · fir · 上传完成
471
+ 应用:ExampleApp
472
+ Bundle ID:com.example.app
473
+ 分发平台:fir
474
+ 状态:上传完成
475
+ 版本:1.2.3
476
+ Build:42
477
+ 打包方式:ad-hoc
478
+ 构建配置:Release
479
+ 安装密码:example-password
480
+ 累计耗时:190 秒
481
+ 通知时间:2026-11-03 12:00:10 +08:00
482
+ [安装页面]
483
+ 更新说明:修复问题,优化体验
484
+ ```
485
+
486
+ **Zealot**:Release ID、版本详情、安装页面、安装二维码,以及 dSYM 是否上传。开启 dSYM 上传后,等待该步骤结束再发送此平台的结果。
487
+
488
+ ```text
489
+ 📦 ExampleApp iOS · Zealot · 上传完成
490
+ 应用:ExampleApp
491
+ Bundle ID:com.example.app
492
+ 分发平台:Zealot
493
+ 状态:上传完成
494
+ 版本:1.2.3
495
+ Build:42
496
+ 打包方式:ad-hoc
497
+ 构建配置:Release
498
+ Release ID:42
499
+ dSYM:已上传
500
+ 累计耗时:200 秒
501
+ 通知时间:2026-11-03 12:00:20 +08:00
502
+ [版本详情] [安装页面]
503
+ [安装二维码]
504
+ 更新说明:修复问题,优化体验
505
+ ```
506
+
507
+ **TestFlight**:App Store Connect 入口、可选测试邀请;明确区分 IPA 上传和 Apple 后续处理。邀请链接不会因为本次上传而保证新构建已可测试。
508
+
509
+ ```text
510
+ 📦 ExampleApp iOS · TestFlight · 上传完成
511
+ 应用:ExampleApp
512
+ Bundle ID:com.example.app
513
+ 分发平台:TestFlight
514
+ 状态:上传完成
515
+ 版本:1.2.3
516
+ Build:42
517
+ 打包方式:testFlight
518
+ 构建配置:Release
519
+ 说明:IPA 已上传,尚未等待 Apple 处理完成;测试可用性请在 App Store Connect 确认。
520
+ 累计耗时:240 秒
521
+ 通知时间:2026-11-03 12:01:00 +08:00
522
+ [App Store Connect] [TestFlight 测试邀请]
523
+ 更新说明:修复问题,优化体验
524
+ ```
525
+
526
+ **App Store**:App Store Connect 入口、可选线上页面,以及本次元数据、截图、构建选择、提交审核的执行结果。资源总开关关闭时显示「商店资源:未开启,仅上传 IPA」;开启时如下例。
527
+
528
+ ```text
529
+ 📦 ExampleApp iOS · App Store · 上传完成
530
+ 应用:ExampleApp
531
+ Bundle ID:com.example.app
532
+ 分发平台:App Store
533
+ 状态:上传完成
534
+ 版本:1.2.3
535
+ Build:42
536
+ 打包方式:app-store
537
+ 构建配置:Release
538
+ 说明:上传完成不代表审核通过或已上线;线上页面可能仍为旧版本。
539
+ 元数据:已上传
540
+ 截图:未上传
541
+ 构建选择:已选择本次 Build
542
+ 提交审核:已提交
543
+ 累计耗时:360 秒
544
+ 通知时间:2026-11-03 12:03:00 +08:00
545
+ [App Store Connect] [App Store 线上页面]
546
+ 更新说明:修复问题,优化体验
547
+ ```
548
+
549
+ 商店资源流程失败时不会发送上述成功消息,而是发送「执行失败」,注明失败阶段和 IPA 是否已经上传;通知本身不会开启商店资源功能。
550
+
551
+ ---
552
+
184
553
  ## 发布到 RubyGems
185
554
 
186
555
  工作流位于 [`.github/workflows/release.yml`](.github/workflows/release.yml)。使用 `1.0.0` 这样的纯版本标签,无需 `v` 前缀。推送数字开头的标签后,自动校验标签与 `lib/fastlane/plugin/fastci/version.rb` 中的 `VERSION` 完全一致,检查 Ruby 语法、构建 gem 并发布到 RubyGems。
@@ -198,12 +567,12 @@ sync_zealot_devices(api_key_path: "./app_store_connect_api_key.json")
198
567
 
199
568
  工作流使用官方 OIDC 短期凭据,不需要配置 `RUBYGEMS_API_KEY` 或创建 GitHub Environment。工作流文件在当前仓库内,Workflow Repository 两项留空。若以后设置 Environment,RubyGems 配置与工作流的 `environment` 必须保持一致。
200
569
 
201
- 每次发布先修改 `VERSION`,执行 `bundle install` 同步 `Gemfile.lock`,并提交本次拟发布的代码和工作流。然后推送对应标签,例如版本更新为 `0.0.30` 后:
570
+ 每次发布先修改 `VERSION`,执行 `bundle install` 同步 `Gemfile.lock`,并提交本次拟发布的代码和工作流。然后推送对应标签,例如版本更新为 `0.0.41` 后:
202
571
 
203
572
  ```bash
204
573
  git push origin main
205
- git tag -a 0.0.30 -m "Release 0.0.30"
206
- git push origin 0.0.30
574
+ git tag -a 0.0.41 -m "Release 0.0.41"
575
+ git push origin 0.0.41
207
576
  ```
208
577
 
209
578
  到 GitHub **Actions → Release to RubyGems** 查看结果。已发布版本不能覆盖;失败重跑前先确认该版本是否已经发布。只有打入标签提交的文件会被发布,本地未提交改动不会包含在内。