@huoye/app-ship 0.2.0 → 0.3.0
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.
- package/README.md +172 -139
- package/browser-extension/capture-fields.js +195 -0
- package/browser-extension/manifest.json +8 -0
- package/browser-extension/popup.html +152 -0
- package/browser-extension/popup.js +312 -0
- package/dist/browser-native.js +2031 -0
- package/dist/chunk-PUSXETML.js +21041 -0
- package/dist/cli.js +4936 -1632
- package/dist/index.cjs +7457 -4068
- package/dist/index.d.cts +1309 -531
- package/dist/index.d.ts +1309 -531
- package/dist/index.js +7397 -4060
- package/dist/mcp-tools-PTJDFF2T.js +8703 -0
- package/dist/mcp.js +15 -0
- package/dist/stdio-BXBWA2I3.js +514 -0
- package/docs/browser-credentials.md +178 -0
- package/package.json +26 -8
- package/scripts/register-browser-host.mjs +110 -0
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# App Ship
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
本机凭据配置、在线体检与浏览器助手接入见 [发布凭据配置](docs/browser-credentials.md)。凭据仅留本机,上传仍需具体人工确认。
|
|
4
|
+
|
|
5
|
+
多平台应用发布与分发引擎 — CLI 命令行工具 & npm 库,按平台真实动作处理测试分发、商店上传、草稿与送审。
|
|
4
6
|
|
|
5
7
|
[](https://www.npmjs.com/package/@huoye/app-ship)
|
|
6
8
|
[](https://www.npmjs.com/package/@huoye/app-ship)
|
|
@@ -38,24 +40,38 @@ app-ship init
|
|
|
38
40
|
|
|
39
41
|
这会生成 `app-ship.yaml` 配置文件。
|
|
40
42
|
|
|
41
|
-
### 3️⃣
|
|
43
|
+
### 3️⃣ 迁移凭据
|
|
44
|
+
|
|
45
|
+
如果已有包含凭据或环境变量占位符的旧配置,先迁移到 macOS Keychain 与本地加密 vault:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
app-ship credentials migrate -c app-ship.yaml -o app-ship.safe.yaml
|
|
49
|
+
app-ship credentials list
|
|
50
|
+
```
|
|
42
51
|
|
|
43
|
-
|
|
52
|
+
新配置只引用不含秘密的 `credentialProfile`:
|
|
44
53
|
|
|
45
54
|
```yaml
|
|
46
55
|
publish:
|
|
47
56
|
pgyer:
|
|
48
57
|
enable: true
|
|
49
|
-
|
|
58
|
+
credentialProfile: app-ship-pgyer
|
|
59
|
+
access:
|
|
60
|
+
type: public # 必须显式选择 public / password / invite
|
|
50
61
|
```
|
|
51
62
|
|
|
52
63
|
### 4️⃣ 上传应用
|
|
53
64
|
|
|
54
65
|
```bash
|
|
55
|
-
app-ship upload -c app-ship.yaml -f app-release.apk
|
|
66
|
+
app-ship upload -c app-ship.safe.yaml -f app-release.apk
|
|
56
67
|
```
|
|
57
68
|
|
|
58
|
-
|
|
69
|
+
CLI 会先显示绑定产物 SHA-256 的发布计划。需要显式确认的平台应在核对后使用当前计划 ID 重跑:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
app-ship upload -c app-ship.safe.yaml -f app-release.apk \
|
|
73
|
+
--confirm-plan <preview 中的 planId>
|
|
74
|
+
```
|
|
59
75
|
|
|
60
76
|
> 💡 需要上传到特定平台?使用 `--platform` 参数:
|
|
61
77
|
>
|
|
@@ -67,11 +83,14 @@ app-ship upload -c app-ship.yaml -f app-release.apk
|
|
|
67
83
|
|
|
68
84
|
## 特性
|
|
69
85
|
|
|
86
|
+
荣耀、魅族、三星新增渠道已进入开发分支,支持 APK 与本机自动凭据配置,尚待真实账号验收;独立 MCP 默认不接入这三家。火叶原生管理 App 的可信执行包可显式启用已授权的十二渠道合同,新增商店预览必须提供 configPath,并绑定配置中的账号引用、应用 ID 和目标指纹;工具参数不能启用此范围。具体动作边界见[发布凭据配置](docs/browser-credentials.md#flu-cli-新增渠道2026-10-17)。
|
|
87
|
+
|
|
70
88
|
- **8 大平台实测通过** ✅:蒲公英、华为、小米、OPPO、vivo、腾讯应用宝、App Store、鸿蒙
|
|
71
89
|
- **并行上传**:多平台同时上传,可配置并发数
|
|
72
90
|
- **智能分发**:自动路由 APK → Android 商店、IPA → Apple、HAP → 鸿蒙
|
|
91
|
+
- **两类发布目标**:测试分发渠道与正式商店渠道使用同一套产物校验、计划和回执
|
|
73
92
|
- **指数退避重试**:网络波动自动重试,可配置退避策略
|
|
74
|
-
-
|
|
93
|
+
- **安全发布合同**:发布计划绑定平台、动作、包名、版本和产物 SHA-256
|
|
75
94
|
- **三种使用方式**:CLI 命令行、npm 库、VSCode 插件
|
|
76
95
|
- **框架无关**:Flutter、React Native、原生 Android/iOS、鸿蒙均可使用
|
|
77
96
|
- **官方 API**:直接调用各平台官方 API,无第三方转接,透明开源
|
|
@@ -96,10 +115,14 @@ app-ship upload -c app-ship.yaml -f app-release.apk
|
|
|
96
115
|
# 仅上传到指定平台
|
|
97
116
|
app-ship upload -c app-ship.yaml -f app-release.apk --platform pgyer,huawei
|
|
98
117
|
|
|
99
|
-
# Google Play
|
|
118
|
+
# Google Play 必须确认当前产物对应的计划,按配置保存 internal 或 production 草稿,不送审或上线
|
|
100
119
|
app-ship upload -c app-ship.yaml -f app-release.aab \
|
|
101
120
|
--platform google_play \
|
|
102
|
-
--confirm-
|
|
121
|
+
--confirm-plan <planId>
|
|
122
|
+
|
|
123
|
+
# 将旧 YAML 凭据迁移到本机安全存储,并输出不含秘密的新配置
|
|
124
|
+
app-ship credentials migrate -c app-ship.yaml -o app-ship.safe.yaml
|
|
125
|
+
app-ship credentials list
|
|
103
126
|
|
|
104
127
|
# 带元数据上传
|
|
105
128
|
app-ship upload -c app-ship.yaml -f app-release.apk \
|
|
@@ -121,16 +144,16 @@ app-ship --version
|
|
|
121
144
|
|
|
122
145
|
**CLI 参数说明**:
|
|
123
146
|
|
|
124
|
-
| 参数
|
|
125
|
-
|
|
|
126
|
-
| `--config <path>`
|
|
127
|
-
| `--file <path>`
|
|
128
|
-
| `--platform <list>`
|
|
129
|
-
| `--version <ver>`
|
|
130
|
-
| `--build-number <n>`
|
|
131
|
-
| `--changelog <text>`
|
|
132
|
-
| `--confirm-
|
|
133
|
-
| `--verbose`
|
|
147
|
+
| 参数 | 简写 | 说明 |
|
|
148
|
+
| ---------------------- | ---- | ----------------------------- |
|
|
149
|
+
| `--config <path>` | `-c` | 配置文件路径 (YAML) |
|
|
150
|
+
| `--file <path>` | `-f` | 安装包路径 (APK/IPA/AAB/HAP) |
|
|
151
|
+
| `--platform <list>` | `-p` | 逗号分隔的平台列表(可选) |
|
|
152
|
+
| `--version <ver>` | `-v` | 版本号(默认:"1.0.0") |
|
|
153
|
+
| `--build-number <n>` | `-b` | 构建号(默认:"1") |
|
|
154
|
+
| `--changelog <text>` | - | 更新日志 |
|
|
155
|
+
| `--confirm-plan <ids>` | - | 确认预览中的一个或多个计划 ID |
|
|
156
|
+
| `--verbose` | - | 显示详细输出 |
|
|
134
157
|
|
|
135
158
|
上传完成后会自动在 `~/.flu-cli/release-receipts/` 保存项目隔离的结构化回执。回执只记录产物路径、大小、SHA-256、渠道状态和白名单远端标识;不会保存 Token、密钥、服务账号内容或完整平台响应。每个项目最多保留 100 条。
|
|
136
159
|
|
|
@@ -138,68 +161,87 @@ app-ship --version
|
|
|
138
161
|
|
|
139
162
|
### 2️⃣ npm 库(编程集成)
|
|
140
163
|
|
|
141
|
-
|
|
164
|
+
`UploadManager` 与各平台 adapter 是可信进程内的低层能力,不会替调用方生成发布计划或取得用户确认,不能直接暴露给 MCP、Web 请求或其它不可信入口。
|
|
165
|
+
CLI `upload` 和导出的 `executeReleasePlan(s)` 共享同一条可信本机编排:先绑定产物生成每个平台的
|
|
166
|
+
`ReleasePlan`,再校验人工提供的 `ReleaseConfirmation`,二次核对普通文件、SHA-256、包名和版本,随后才解析 Profile 并调用低层上传器。
|
|
167
|
+
MCP 的 `execute_release` 也只通过这条执行边界工作:宿主必须逐平台弹出人工确认,确认结果不会由模型参数传入,执行器仍会重新校验计划、产物和 Profile。
|
|
168
|
+
|
|
169
|
+
**可信本地集成**:
|
|
142
170
|
|
|
143
|
-
|
|
171
|
+
以下展示可信本地发布执行边界。`confirmation` 必须来自用户核对过的当前计划;调用方不得记录或序列化
|
|
172
|
+
解析后的配置,也不得跳过执行器的二次产物校验:
|
|
144
173
|
|
|
145
174
|
```typescript
|
|
146
|
-
import {
|
|
175
|
+
import {
|
|
176
|
+
ConfigValidator,
|
|
177
|
+
createReleasePlan,
|
|
178
|
+
createDefaultCredentialProfileStore,
|
|
179
|
+
executeReleasePlan,
|
|
180
|
+
} from '@huoye/app-ship'
|
|
181
|
+
|
|
182
|
+
const config = ConfigValidator.loadAndValidate('./app-ship.yaml')
|
|
183
|
+
if (!config) throw new Error('配置无效')
|
|
184
|
+
const plan = createReleasePlan({
|
|
185
|
+
platform: 'google_play',
|
|
186
|
+
action: 'create_draft',
|
|
187
|
+
packageName: 'com.example.app',
|
|
188
|
+
versionName: '1.0.0',
|
|
189
|
+
buildNumber: '1',
|
|
190
|
+
artifact: { path: './app-release.aab', sha256: '<sha256>', sizeBytes: 123 },
|
|
191
|
+
credentialProfile: 'play-production',
|
|
192
|
+
})
|
|
193
|
+
const result = await executeReleasePlan({
|
|
194
|
+
plan,
|
|
195
|
+
confirmation: {
|
|
196
|
+
planId: plan.planId,
|
|
197
|
+
platform: plan.platform,
|
|
198
|
+
action: plan.action,
|
|
199
|
+
artifactSha256: plan.artifact.sha256,
|
|
200
|
+
confirmedAt: new Date().toISOString(),
|
|
201
|
+
},
|
|
202
|
+
config,
|
|
203
|
+
projectRoot: process.cwd(),
|
|
204
|
+
dependencies: { credentialStore: createDefaultCredentialProfileStore() },
|
|
205
|
+
})
|
|
206
|
+
console.log(result.receipt.id)
|
|
207
|
+
```
|
|
147
208
|
|
|
148
|
-
|
|
149
|
-
const config = ConfigValidator.loadAndValidate("./app-ship.yaml");
|
|
209
|
+
---
|
|
150
210
|
|
|
151
|
-
|
|
152
|
-
const manager = new UploadManager({
|
|
153
|
-
maxConcurrent: 3, // 最大并发数
|
|
154
|
-
continueOnError: true, // 部分失败后继续
|
|
155
|
-
verbose: true, // 显示详细日志
|
|
156
|
-
});
|
|
211
|
+
### 3️⃣ 本机 MCP(AI 宿主集成)
|
|
157
212
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
console.log(`✅ ${result.platform}: ${result.url || result.consoleUrl}`);
|
|
174
|
-
} else {
|
|
175
|
-
console.log(`❌ ${result.platform}: ${result.message}`);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
213
|
+
App Ship 现在提供独立的 `app-ship-mcp` 本机 MCP 入口,供 OpenHands、Codex 等 MCP 宿主读取并执行发布能力。当前提供十一个工具,分别覆盖五项产物/执行能力与六项账号配置/核验能力:
|
|
214
|
+
|
|
215
|
+
- `inspect_artifact`:读取安装包真实格式、包名、版本、构建号、大小和 SHA-256
|
|
216
|
+
- `preview_release`:生成测试分发或商店发布的 `ReleasePlan`,不读取凭据、不执行远端动作
|
|
217
|
+
- `preview_draft_upload`:生成绑定产物的草稿上传 `ReleasePlan`,不读取凭据、不上传
|
|
218
|
+
- `list_release_receipts`:读取脱敏的本地发布回执摘要
|
|
219
|
+
- `execute_release`:在宿主通过 MCP elicitation 取得逐平台人工确认后,重新校验并执行上传,返回脱敏发布回执
|
|
220
|
+
- `begin_credential_setup`、`credential_setup_status`、`complete_credential_setup`、`cancel_credential_setup`:管理明确项目的本机账号配置任务,不上传安装包
|
|
221
|
+
- `preflight_release`、`verify_credential_profile`:只读核验凭据与目标,不等于实际上传已通过
|
|
222
|
+
|
|
223
|
+
构建并启动:
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
npm run build
|
|
227
|
+
node dist/mcp.js
|
|
178
228
|
```
|
|
179
229
|
|
|
180
|
-
|
|
230
|
+
MCP 入口使用 Node.js 20 或更高版本,SDK 会打包进 MCP 可执行文件;现有 App Ship CLI / npm 库仍保持 Node.js 18 的声明。`execute_release` 需要宿主支持 MCP elicitation;用户拒绝或宿主不支持确认时不会读取凭据或发起上传。
|
|
181
231
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
{ enable: true, apiKey: "YOUR_API_KEY" },
|
|
189
|
-
{ version: "1.0.0", buildNumber: "1", changelog: "首次发布" },
|
|
190
|
-
);
|
|
191
|
-
|
|
192
|
-
if (result.success) {
|
|
193
|
-
console.log(`✅ 下载地址: ${result.url}`);
|
|
194
|
-
console.log(`✅ 二维码: ${result.qrCode}`);
|
|
195
|
-
} else {
|
|
196
|
-
console.log(`❌ 失败: ${result.message}`);
|
|
197
|
-
}
|
|
232
|
+
确认流程兼容 2025 年协议的 `elicitation/create` 与 `2026-07-28` 协议的 `input_required`。确认状态由服务器签名,十分钟内有效且只能使用一次;确认期间修改配置目标、发布参数或产物会阻断执行。宿主取消会在上传开始前阻断执行,已开始的远端请求仍需根据回执判断结果,不能自动重试。
|
|
233
|
+
|
|
234
|
+
Codex 本机接入示例(先构建,再把路径替换为实际绝对路径):
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
codex mcp add app-ship -- /absolute/path/to/node /absolute/path/to/app-ship/dist/mcp.js
|
|
198
238
|
```
|
|
199
239
|
|
|
240
|
+
大文件上传建议在宿主配置的 `[mcp_servers.app-ship]` 中设置 `tool_timeout_sec = 600`。重新加载 MCP 后先检查十一个工具和拒绝确认行为,再执行真实草稿上传;Android APK 与 Harmony App Pack 是不同产物,应分别执行。
|
|
241
|
+
|
|
200
242
|
---
|
|
201
243
|
|
|
202
|
-
###
|
|
244
|
+
### 4️⃣ VSCode 插件(可视化)
|
|
203
245
|
|
|
204
246
|
安装 **Flu CLI** VSCode 插件,在 IDE 内点击操作即可完成构建和上传。
|
|
205
247
|
|
|
@@ -218,30 +260,34 @@ if (result.success) {
|
|
|
218
260
|
|
|
219
261
|
本工具直接调用各平台**官方 API**,所有 API 地址和文档均为平台官方提供。
|
|
220
262
|
|
|
221
|
-
| 平台 | 文件
|
|
222
|
-
| ---------------------- |
|
|
223
|
-
| 🐧 **蒲公英** | APK, IPA
|
|
224
|
-
| 🟥 **华为** | APK, AAB
|
|
225
|
-
| 🔴 **小米** | APK
|
|
226
|
-
| 🟠 **OPPO** | APK
|
|
227
|
-
| 🔵 **vivo** | APK
|
|
228
|
-
| 🐧 **腾讯应用宝** | APK
|
|
229
|
-
| 🍎 **Apple App Store** | IPA
|
|
230
|
-
| 🟣 **鸿蒙** | HAP
|
|
231
|
-
| 🍎 **TestFlight** | IPA
|
|
232
|
-
| 🍎 **Ad Hoc** | IPA
|
|
233
|
-
| 🎮 **Google Play** | AAB
|
|
263
|
+
| 平台 | 文件 | 认证 | 官方 API 文档 | 状态 |
|
|
264
|
+
| ---------------------- | ------------ | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------- |
|
|
265
|
+
| 🐧 **蒲公英** | APK, IPA | API Key | [pgyer.com/api](https://www.pgyer.com/doc/view/api_basic) | ✅ 已实测 |
|
|
266
|
+
| 🟥 **华为** | APK, AAB | OAuth2 | [AppGallery Connect](https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides/publish-app-0000001100974822) | ✅ 已实测 |
|
|
267
|
+
| 🔴 **小米** | APK | RSA 签名 | [小米开放平台](https://dev.mi.com/console/doc/detail?pId=1695) | ✅ 已实测 |
|
|
268
|
+
| 🟠 **OPPO** | APK | HMAC-SHA256 | [OPPO 开发者平台](https://open.oppomobile.com/wiki/doc#id=10106) | ✅ 已实测 |
|
|
269
|
+
| 🔵 **vivo** | APK | HMAC + MD5 | [vivo 开放平台](https://dev.vivo.com.cn/openAbility/interface) | ✅ 已实测 |
|
|
270
|
+
| 🐧 **腾讯应用宝** | APK | HMAC-SHA256 | [应用宝平台](https://open.qq.com/doc/?id=11016) | ✅ 已实测 |
|
|
271
|
+
| 🍎 **Apple App Store** | IPA | Apple ID / API | [App Store Connect API](https://developer.apple.com/app-store-connect/api/) | ✅ 已实测 |
|
|
272
|
+
| 🟣 **鸿蒙** | HAP | OAuth2 | [AppGallery Connect](https://developer.huawei.com/consumer/cn/doc/development/AppGallery-connect-Guides/agcapi-getstarted-0000001111209402) | ✅ 已实测 |
|
|
273
|
+
| 🍎 **TestFlight** | IPA | Apple API | [TestFlight API](https://developer.apple.com/testflight/testers/) | ⚠️ 开发中 |
|
|
274
|
+
| 🍎 **Ad Hoc** | IPA | 证书 | [Apple 文档](https://developer.apple.com/documentation/xcode/distributing-your-app-for-beta-testing) | ⚠️ 开发中 |
|
|
275
|
+
| 🎮 **Google Play** | AAB | Service Account | [Android Publisher API](https://developers.google.com/android-publisher/api-ref/rest) | ✅ internal 草稿已实测 |
|
|
276
|
+
| **荣耀** | APK | Client ID/Secret | [官方发布接口](https://developer.honor.com/cn/doc/guides/101359) | 草稿,待真实账号验收 |
|
|
277
|
+
| **魅族** | APK(64 位) | Client ID/Secret + SHA-256 签名 | [官方开放接口](https://open.flyme.cn/docs?id=333) | 仅文件上传,待真实账号验收 |
|
|
278
|
+
| **Samsung** | APK | Service Account + RS256 | [Galaxy Store API](https://developer.samsung.com/galaxy-store/galaxy-store-developer-api.html) | 草稿,待真实账号验收 |
|
|
234
279
|
|
|
235
280
|
---
|
|
236
281
|
|
|
237
282
|
## 详细配置参考
|
|
238
283
|
|
|
239
|
-
###
|
|
284
|
+
### 安全的 app-ship.yaml 配置
|
|
240
285
|
|
|
241
|
-
|
|
286
|
+
所有凭据从平台官方后台申请,但 YAML 只保存 `credentialProfile` 引用。旧配置用
|
|
287
|
+
`app-ship credentials migrate` 一次性导入;迁移命令拒绝覆盖源文件。
|
|
242
288
|
|
|
243
289
|
```yaml
|
|
244
|
-
version:
|
|
290
|
+
version: '1.0.0'
|
|
245
291
|
|
|
246
292
|
# 重试策略(可选)
|
|
247
293
|
retry:
|
|
@@ -254,94 +300,86 @@ publish:
|
|
|
254
300
|
# ── 蒲公英 (官方 API: https://www.pgyer.com/doc/view/api_basic) ──
|
|
255
301
|
pgyer:
|
|
256
302
|
enable: true
|
|
257
|
-
|
|
258
|
-
description:
|
|
303
|
+
credentialProfile: app-ship-pgyer
|
|
304
|
+
description: '测试版本'
|
|
305
|
+
access:
|
|
306
|
+
type: password
|
|
259
307
|
|
|
260
308
|
# ── 华为 (官方 API: https://developer.huawei.com/consumer/cn/service/josp/agc/index.html) ──
|
|
261
309
|
huawei:
|
|
262
310
|
enable: false
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
appId: "YOUR_APP_ID"
|
|
311
|
+
credentialProfile: app-ship-huawei
|
|
312
|
+
appId: 'YOUR_APP_ID'
|
|
313
|
+
packageName: 'com.example.app'
|
|
267
314
|
releaseType: draft
|
|
268
315
|
|
|
269
316
|
# ── 小米 (官方 API: https://dev.mi.com/console/doc/detail?pId=1695) ──
|
|
270
317
|
xiaomi:
|
|
271
318
|
enable: false
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
privateKey: "${XIAOMI_KEY}"
|
|
275
|
-
packageName: "com.example.app"
|
|
319
|
+
credentialProfile: app-ship-xiaomi
|
|
320
|
+
packageName: 'com.example.app'
|
|
276
321
|
|
|
277
322
|
# ── OPPO (官方 API: https://open.oppomobile.com/wiki/doc#id=10106) ──
|
|
278
323
|
oppo:
|
|
279
324
|
enable: false
|
|
280
|
-
|
|
281
|
-
clientId: "${OPPO_CLIENT_ID}"
|
|
282
|
-
clientSecret: "${OPPO_CLIENT_SECRET}"
|
|
325
|
+
credentialProfile: app-ship-oppo
|
|
283
326
|
|
|
284
327
|
# ── vivo (官方 API: https://dev.vivo.com.cn/openAbility/interface) ──
|
|
285
328
|
vivo:
|
|
286
329
|
enable: false
|
|
287
|
-
|
|
288
|
-
accessKey: "${VIVO_ACCESS_KEY}"
|
|
289
|
-
accessSecret: "${VIVO_ACCESS_SECRET}"
|
|
330
|
+
credentialProfile: app-ship-vivo
|
|
290
331
|
|
|
291
332
|
# ── 腾讯应用宝 (官方 API: https://open.qq.com/doc/?id=11016) ──
|
|
292
333
|
tencent:
|
|
293
334
|
enable: false
|
|
294
|
-
|
|
295
|
-
userId: "${TENCENT_USER_ID}"
|
|
296
|
-
appId: "${TENCENT_APP_ID}"
|
|
297
|
-
accessSecret: "${TENCENT_SECRET}"
|
|
335
|
+
credentialProfile: app-ship-tencent
|
|
298
336
|
|
|
299
337
|
# ── 鸿蒙 (官方 API: https://developer.huawei.com/consumer/cn/doc/development/AppGallery-connect-Guides/agcapi-getstarted-0000001111209402) ──
|
|
300
338
|
harmony:
|
|
301
339
|
enable: false
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
appId: "YOUR_APP_ID"
|
|
340
|
+
credentialProfile: app-ship-harmony
|
|
341
|
+
appId: 'YOUR_APP_ID'
|
|
342
|
+
packageName: 'com.example.app'
|
|
306
343
|
|
|
307
344
|
# ── App Store / TestFlight (官方 API: https://developer.apple.com/app-store-connect/api/) ──
|
|
308
345
|
app_store:
|
|
309
346
|
enable: false
|
|
310
347
|
mode: app_store
|
|
311
|
-
|
|
312
|
-
appleId: "${APPLE_ID}"
|
|
313
|
-
appPassword: "${APP_PASSWORD}"
|
|
348
|
+
credentialProfile: app-ship-app_store
|
|
314
349
|
|
|
315
|
-
# ── Google Play
|
|
350
|
+
# ── Google Play(保存 internal 或 production 草稿,不送审或上线)──
|
|
316
351
|
google_play:
|
|
317
352
|
enable: false
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
packageName: "com.example.app"
|
|
353
|
+
credentialProfile: app-ship-google_play
|
|
354
|
+
packageName: 'com.example.app'
|
|
321
355
|
track: internal
|
|
322
356
|
```
|
|
323
357
|
|
|
324
358
|
Google Play 连接器只从用户本机读取服务账号文件,并直接请求 Android Publisher API。
|
|
325
|
-
应用需已在 Play Console
|
|
326
|
-
|
|
359
|
+
应用需已在 Play Console 创建且包名一致;只接受 AAB,按明确配置保存 internal 或 production 草稿。
|
|
360
|
+
production 在发送 AAB 前原样校验本次未提交事务;失败不发送包、不提交并清理事务。
|
|
361
|
+
服务账号须有目标应用的生产轨道权限,测试轨道权限不能替代;本机工具不自动增加权限。
|
|
362
|
+
当前真实成功证据仍为 internal,production 代码及夹具通过不等于商店实传通过。
|
|
327
363
|
如果应用从未上传过 APK/AAB,需先在 Play Console 手工上传并保存首个版本,之后才能使用
|
|
328
|
-
Edits API;CLI
|
|
364
|
+
Edits API;CLI 上传还必须显式提供预览中的 `--confirm-plan <planId>`。
|
|
329
365
|
|
|
330
366
|
### 环境变量支持
|
|
331
367
|
|
|
332
|
-
|
|
368
|
+
旧配置在迁移时仍可使用 `${VAR_NAME}`。迁移完成后,安全配置只保留 Profile:
|
|
333
369
|
|
|
334
370
|
```yaml
|
|
335
371
|
pgyer:
|
|
336
372
|
enable: true
|
|
337
|
-
|
|
373
|
+
credentialProfile: app-ship-pgyer
|
|
374
|
+
access:
|
|
375
|
+
type: invite
|
|
338
376
|
```
|
|
339
377
|
|
|
340
378
|
在 CI/CD 中设置环境变量即可:
|
|
341
379
|
|
|
342
380
|
```bash
|
|
343
381
|
export PGYER_API_KEY="your-actual-key"
|
|
344
|
-
app-ship
|
|
382
|
+
app-ship credentials migrate -c app-ship.legacy.yaml -o app-ship.yaml
|
|
345
383
|
```
|
|
346
384
|
|
|
347
385
|
---
|
|
@@ -382,28 +420,15 @@ app-ship upload -c app-ship.yaml -f app.apk
|
|
|
382
420
|
|
|
383
421
|
### Q: 支持 Windows / Mac 吗?
|
|
384
422
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
- Windows 10+
|
|
388
|
-
- macOS 10.15+
|
|
389
|
-
- Linux (Ubuntu 18+, Fedora, etc.)
|
|
423
|
+
上传适配器仍可在 Node.js 支持的平台运行,但本批安全凭据存储只完成 macOS Keychain
|
|
424
|
+
垂直切片。CLI 在 Linux / Windows 会明确停止,不会退回 YAML 明文凭据。
|
|
390
425
|
|
|
391
426
|
---
|
|
392
427
|
|
|
393
428
|
### Q: 可以在 CI/CD 中使用吗?
|
|
394
429
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
**GitHub Actions 示例**:
|
|
398
|
-
|
|
399
|
-
```yaml
|
|
400
|
-
- name: Upload App
|
|
401
|
-
run: app-ship upload -c app-ship.yaml -f app.apk
|
|
402
|
-
env:
|
|
403
|
-
PGYER_API_KEY: ${{ secrets.PGYER_API_KEY }}
|
|
404
|
-
HUAWEI_CLIENT_ID: ${{ secrets.HUAWEI_CLIENT_ID }}
|
|
405
|
-
# ... 其他平台凭证
|
|
406
|
-
```
|
|
430
|
+
当前不把无界面 CI Keychain 会话声明为已验证能力。CI 专用凭据提供器及身份边界完成后再开放;
|
|
431
|
+
不要通过回退到 YAML 明文或命令行参数绕过限制。
|
|
407
432
|
|
|
408
433
|
---
|
|
409
434
|
|
|
@@ -411,10 +436,14 @@ app-ship upload -c app-ship.yaml -f app.apk
|
|
|
411
436
|
|
|
412
437
|
### 🔐 密钥管理
|
|
413
438
|
|
|
414
|
-
-
|
|
439
|
+
- **目标边界**:项目 YAML、Git、日志、回执、MCP 参数和模型上下文不得包含原始凭据
|
|
440
|
+
- **本地保管**:普通 Secret 进入操作系统安全存储,JSON / `.p8` 进入本地加密凭据库或经检查的外部路径
|
|
441
|
+
- **MCP 脱敏**:MCP 只能读取 `credentialProfile`、`configured`、`verified` 等元数据,不能读取或导出秘密
|
|
415
442
|
- **本地处理**:所有认证和签名操作都在你的机器本地执行
|
|
416
443
|
- **官方渠道**:直接调用各平台官方 API,无第三方转接
|
|
417
444
|
|
|
445
|
+
> 当前安全存储垂直切片只验证 macOS Keychain。Linux / Windows 会明确停止,待对应系统安全存储完成验证后再开放。旧 YAML / 环境变量只允许作为 `credentials migrate` 的迁移输入,`upload` 要求使用 `credentialProfile`。
|
|
446
|
+
|
|
418
447
|
### 🛡️ 最佳实践
|
|
419
448
|
|
|
420
449
|
1. **保护配置文件** - 将 `app-ship.yaml` 加入 `.gitignore`:
|
|
@@ -535,3 +564,7 @@ npm run dev
|
|
|
535
564
|
## License
|
|
536
565
|
|
|
537
566
|
MIT | Copyright © 2025-2026 火叶工作室
|
|
567
|
+
|
|
568
|
+
### 按语言提供版本说明
|
|
569
|
+
|
|
570
|
+
可在配置根级使用 `releaseNotes` 按 BCP-47 提供各语言正文,适配器负责与商店实际语言匹配和回读。详细边界与定向检查见 [本地化发行说明](docs/localized-release-notes.md)。
|