react-native-update-cli 1.46.1 → 2.0.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 +578 -1
- package/README.zh-CN.md +576 -0
- package/cli.json +18 -0
- package/lib/api.js +5 -5
- package/lib/app.js +1 -1
- package/lib/bundle.js +43 -29
- package/lib/exports.js +65 -0
- package/lib/index.js +100 -9
- package/lib/module-manager.js +125 -0
- package/lib/modules/app-module.js +223 -0
- package/lib/modules/bundle-module.js +188 -0
- package/lib/modules/index.js +42 -0
- package/lib/modules/package-module.js +16 -0
- package/lib/modules/user-module.js +402 -0
- package/lib/modules/version-module.js +16 -0
- package/lib/package.js +16 -6
- package/lib/provider.js +340 -0
- package/lib/user.js +3 -3
- package/lib/utils/app-info-parser/apk.js +1 -1
- package/lib/utils/app-info-parser/ipa.js +2 -2
- package/lib/utils/app-info-parser/resource-finder.js +35 -35
- package/lib/utils/app-info-parser/xml-parser/manifest.js +2 -2
- package/lib/utils/app-info-parser/zip.js +3 -6
- package/lib/utils/check-plugin.js +1 -1
- package/lib/utils/git.js +1 -1
- package/lib/utils/i18n.js +3 -1
- package/lib/utils/index.js +4 -4
- package/lib/utils/latest-version/cli.js +3 -3
- package/lib/utils/latest-version/index.js +4 -4
- package/lib/versions.js +2 -2
- package/package.json +4 -4
- package/src/api.ts +7 -7
- package/src/app.ts +2 -2
- package/src/bundle.ts +57 -32
- package/src/exports.ts +30 -0
- package/src/index.ts +118 -16
- package/src/module-manager.ts +149 -0
- package/src/modules/app-module.ts +205 -0
- package/src/modules/bundle-module.ts +202 -0
- package/src/modules/index.ts +19 -0
- package/src/modules/package-module.ts +11 -0
- package/src/modules/user-module.ts +406 -0
- package/src/modules/version-module.ts +8 -0
- package/src/package.ts +29 -16
- package/src/provider.ts +341 -0
- package/src/types.ts +125 -0
- package/src/user.ts +4 -3
- package/src/utils/app-info-parser/apk.js +62 -52
- package/src/utils/app-info-parser/app.js +5 -5
- package/src/utils/app-info-parser/ipa.js +69 -57
- package/src/utils/app-info-parser/resource-finder.js +50 -54
- package/src/utils/app-info-parser/utils.js +59 -54
- package/src/utils/app-info-parser/xml-parser/binary.js +366 -354
- package/src/utils/app-info-parser/xml-parser/manifest.js +145 -137
- package/src/utils/app-info-parser/zip.js +1 -1
- package/src/utils/check-plugin.ts +4 -2
- package/src/utils/dep-versions.ts +13 -6
- package/src/utils/git.ts +1 -1
- package/src/utils/i18n.ts +3 -1
- package/src/utils/index.ts +8 -10
- package/src/utils/latest-version/cli.ts +4 -4
- package/src/utils/latest-version/index.ts +17 -17
- package/src/utils/plugin-config.ts +3 -3
- package/src/versions.ts +3 -3
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,576 @@
|
|
|
1
|
+
# React Native Update CLI
|
|
2
|
+
|
|
3
|
+
这是一个统一的React Native Update CLI,同时支持传统命令和模块化架构以及自定义发布流程。
|
|
4
|
+
|
|
5
|
+
## 🚀 特性
|
|
6
|
+
|
|
7
|
+
- **统一CLI**: 使用单个`pushy`命令提供所有功能
|
|
8
|
+
- **向后兼容**: 所有现有命令都能正常工作
|
|
9
|
+
- **模块化架构**: 将CLI功能拆分为独立的模块
|
|
10
|
+
- **自定义工作流**: 支持创建自定义的发布流程
|
|
11
|
+
- **可扩展性**: 用户可以导入和注册自定义模块
|
|
12
|
+
- **类型安全**: 完整的TypeScript类型支持
|
|
13
|
+
|
|
14
|
+
## 📦 安装
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install react-native-update-cli
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## 🎯 快速开始
|
|
21
|
+
|
|
22
|
+
### 基本使用
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# 使用统一CLI
|
|
26
|
+
npx pushy help
|
|
27
|
+
|
|
28
|
+
# 列出所有可用命令和工作流
|
|
29
|
+
npx pushy list
|
|
30
|
+
|
|
31
|
+
# 执行内置的工作流
|
|
32
|
+
npx pushy workflow setup-app
|
|
33
|
+
|
|
34
|
+
# 执行自定义工作流
|
|
35
|
+
npx pushy workflow custom-publish
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### 编程方式使用
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import { moduleManager, CLIProviderImpl } from 'react-native-update-cli';
|
|
42
|
+
|
|
43
|
+
// 获取CLI提供者
|
|
44
|
+
const provider = moduleManager.getProvider();
|
|
45
|
+
|
|
46
|
+
// 执行打包
|
|
47
|
+
const bundleResult = await provider.bundle({
|
|
48
|
+
platform: 'ios',
|
|
49
|
+
dev: false,
|
|
50
|
+
sourcemap: true
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// 发布版本
|
|
54
|
+
const publishResult = await provider.publish({
|
|
55
|
+
name: 'v1.2.3',
|
|
56
|
+
description: 'Bug fixes and improvements',
|
|
57
|
+
rollout: 100
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## 🔧 创建自定义模块
|
|
62
|
+
|
|
63
|
+
### 1. 定义模块
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
import type { CLIModule, CommandDefinition, CustomWorkflow } from 'react-native-update-cli';
|
|
67
|
+
|
|
68
|
+
export const myCustomModule: CLIModule = {
|
|
69
|
+
name: 'my-custom',
|
|
70
|
+
version: '1.0.0',
|
|
71
|
+
|
|
72
|
+
commands: [
|
|
73
|
+
{
|
|
74
|
+
name: 'custom-command',
|
|
75
|
+
description: 'My custom command',
|
|
76
|
+
handler: async (context) => {
|
|
77
|
+
console.log('Executing custom command...');
|
|
78
|
+
return {
|
|
79
|
+
success: true,
|
|
80
|
+
data: { message: 'Custom command executed' }
|
|
81
|
+
};
|
|
82
|
+
},
|
|
83
|
+
options: {
|
|
84
|
+
param: { hasValue: true, description: 'Custom parameter' }
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
],
|
|
88
|
+
|
|
89
|
+
workflows: [
|
|
90
|
+
{
|
|
91
|
+
name: 'my-workflow',
|
|
92
|
+
description: 'My custom workflow',
|
|
93
|
+
steps: [
|
|
94
|
+
{
|
|
95
|
+
name: 'step1',
|
|
96
|
+
description: 'First step',
|
|
97
|
+
execute: async (context, previousResult) => {
|
|
98
|
+
console.log('Executing step 1...');
|
|
99
|
+
return { step1Completed: true };
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
name: 'step2',
|
|
104
|
+
description: 'Second step',
|
|
105
|
+
execute: async (context, previousResult) => {
|
|
106
|
+
console.log('Executing step 2...');
|
|
107
|
+
return { ...previousResult, step2Completed: true };
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
]
|
|
111
|
+
}
|
|
112
|
+
],
|
|
113
|
+
|
|
114
|
+
init: (provider) => {
|
|
115
|
+
console.log('Custom module initialized');
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
cleanup: () => {
|
|
119
|
+
console.log('Custom module cleanup');
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### 2. 注册模块
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
import { moduleManager } from 'react-native-update-cli';
|
|
128
|
+
import { myCustomModule } from './my-custom-module';
|
|
129
|
+
|
|
130
|
+
// 注册自定义模块
|
|
131
|
+
moduleManager.registerModule(myCustomModule);
|
|
132
|
+
|
|
133
|
+
// 执行自定义命令
|
|
134
|
+
const result = await moduleManager.executeCommand('custom-command', {
|
|
135
|
+
args: [],
|
|
136
|
+
options: { param: 'value' }
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// 执行自定义工作流
|
|
140
|
+
const workflowResult = await moduleManager.executeWorkflow('my-workflow', {
|
|
141
|
+
args: [],
|
|
142
|
+
options: {}
|
|
143
|
+
});
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## 🔄 工作流系统
|
|
147
|
+
|
|
148
|
+
### 工作流步骤
|
|
149
|
+
|
|
150
|
+
每个工作流步骤包含:
|
|
151
|
+
|
|
152
|
+
- `name`: 步骤名称
|
|
153
|
+
- `description`: 步骤描述
|
|
154
|
+
- `execute`: 执行函数
|
|
155
|
+
- `condition`: 可选的条件函数
|
|
156
|
+
|
|
157
|
+
### 条件执行
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
{
|
|
161
|
+
name: 'conditional-step',
|
|
162
|
+
description: 'Only execute in production',
|
|
163
|
+
execute: async (context, previousResult) => {
|
|
164
|
+
// 执行逻辑
|
|
165
|
+
},
|
|
166
|
+
condition: (context) => {
|
|
167
|
+
return context.options.environment === 'production';
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### 工作流验证
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
{
|
|
176
|
+
name: 'validated-workflow',
|
|
177
|
+
description: 'Workflow with validation',
|
|
178
|
+
steps: [...],
|
|
179
|
+
validate: (context) => {
|
|
180
|
+
if (!context.options.requiredParam) {
|
|
181
|
+
console.error('Required parameter missing');
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## 📋 内置模块
|
|
190
|
+
|
|
191
|
+
### Bundle模块 (`bundle`)
|
|
192
|
+
- `bundle`: 打包JavaScript代码并可选发布
|
|
193
|
+
- `diff`: 生成两个PPK文件之间的差异
|
|
194
|
+
- `hdiff`: 生成两个PPK文件之间的hdiff
|
|
195
|
+
- `diffFromApk`: 从APK文件生成差异
|
|
196
|
+
- `hdiffFromApk`: 从APK文件生成hdiff
|
|
197
|
+
- `hdiffFromApp`: 从APP文件生成hdiff
|
|
198
|
+
- `diffFromIpa`: 从IPA文件生成差异
|
|
199
|
+
- `hdiffFromIpa`: 从IPA文件生成hdiff
|
|
200
|
+
|
|
201
|
+
### Version模块 (`version`)
|
|
202
|
+
- `publish`: 发布新版本
|
|
203
|
+
- `versions`: 列出所有版本
|
|
204
|
+
- `update`: 更新版本信息
|
|
205
|
+
- `updateVersionInfo`: 更新版本元数据
|
|
206
|
+
|
|
207
|
+
### App模块 (`app`)
|
|
208
|
+
- `createApp`: 创建新应用
|
|
209
|
+
- `apps`: 列出所有应用
|
|
210
|
+
- `selectApp`: 选择应用
|
|
211
|
+
- `deleteApp`: 删除应用
|
|
212
|
+
|
|
213
|
+
### Package模块 (`package`)
|
|
214
|
+
- `uploadIpa`: 上传IPA文件
|
|
215
|
+
- `uploadApk`: 上传APK文件
|
|
216
|
+
- `uploadApp`: 上传APP文件
|
|
217
|
+
- `parseApp`: 解析APP文件信息
|
|
218
|
+
- `parseIpa`: 解析IPA文件信息
|
|
219
|
+
- `parseApk`: 解析APK文件信息
|
|
220
|
+
- `packages`: 列出包
|
|
221
|
+
|
|
222
|
+
### User模块 (`user`)
|
|
223
|
+
- `login`: 登录
|
|
224
|
+
- `logout`: 登出
|
|
225
|
+
- `me`: 显示用户信息
|
|
226
|
+
|
|
227
|
+
## 🛠️ CLI提供者API
|
|
228
|
+
|
|
229
|
+
### 核心功能
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
interface CLIProvider {
|
|
233
|
+
// 打包
|
|
234
|
+
bundle(options: BundleOptions): Promise<CommandResult>;
|
|
235
|
+
|
|
236
|
+
// 发布
|
|
237
|
+
publish(options: PublishOptions): Promise<CommandResult>;
|
|
238
|
+
|
|
239
|
+
// 上传
|
|
240
|
+
upload(options: UploadOptions): Promise<CommandResult>;
|
|
241
|
+
|
|
242
|
+
// 应用管理
|
|
243
|
+
getSelectedApp(platform?: Platform): Promise<{ appId: string; platform: Platform }>;
|
|
244
|
+
listApps(platform?: Platform): Promise<CommandResult>;
|
|
245
|
+
createApp(name: string, platform: Platform): Promise<CommandResult>;
|
|
246
|
+
|
|
247
|
+
// 版本管理
|
|
248
|
+
listVersions(appId: string): Promise<CommandResult>;
|
|
249
|
+
getVersion(appId: string, versionId: string): Promise<CommandResult>;
|
|
250
|
+
updateVersion(appId: string, versionId: string, updates: Partial<Version>): Promise<CommandResult>;
|
|
251
|
+
|
|
252
|
+
// 包管理
|
|
253
|
+
listPackages(appId: string, platform?: Platform): Promise<CommandResult>;
|
|
254
|
+
getPackage(appId: string, packageId: string): Promise<CommandResult>;
|
|
255
|
+
|
|
256
|
+
// 工具函数
|
|
257
|
+
getPlatform(platform?: Platform): Promise<Platform>;
|
|
258
|
+
loadSession(): Promise<Session>;
|
|
259
|
+
saveToLocal(key: string, value: string): void;
|
|
260
|
+
question(prompt: string): Promise<string>;
|
|
261
|
+
|
|
262
|
+
// 工作流
|
|
263
|
+
registerWorkflow(workflow: CustomWorkflow): void;
|
|
264
|
+
executeWorkflow(workflowName: string, context: CommandContext): Promise<CommandResult>;
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### 自定义命令
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
// 执行自定义打包命令
|
|
272
|
+
const bundleResult = await moduleManager.executeCommand('custom-bundle', {
|
|
273
|
+
args: [],
|
|
274
|
+
options: {
|
|
275
|
+
platform: 'android',
|
|
276
|
+
validate: true,
|
|
277
|
+
optimize: true
|
|
278
|
+
}
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
// 生成差异文件
|
|
282
|
+
const diffResult = await moduleManager.executeCommand('diff', {
|
|
283
|
+
args: [],
|
|
284
|
+
options: {
|
|
285
|
+
origin: './build/v1.0.0.ppk',
|
|
286
|
+
next: './build/v1.1.0.ppk',
|
|
287
|
+
output: './build/diff.patch'
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
// 从APK文件生成差异
|
|
292
|
+
const apkDiffResult = await moduleManager.executeCommand('diffFromApk', {
|
|
293
|
+
args: [],
|
|
294
|
+
options: {
|
|
295
|
+
origin: './build/app-v1.0.0.apk',
|
|
296
|
+
next: './build/app-v1.1.0.apk',
|
|
297
|
+
output: './build/apk-diff.patch'
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## 🔧 配置
|
|
303
|
+
|
|
304
|
+
### 环境变量
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
# 设置API端点
|
|
308
|
+
export PUSHY_REGISTRY=https://your-api-endpoint.com
|
|
309
|
+
|
|
310
|
+
# 设置非交互模式
|
|
311
|
+
export NO_INTERACTIVE=true
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### 配置文件
|
|
315
|
+
|
|
316
|
+
创建 `update.json` 文件:
|
|
317
|
+
|
|
318
|
+
```json
|
|
319
|
+
{
|
|
320
|
+
"ios": {
|
|
321
|
+
"appId": "your-ios-app-id",
|
|
322
|
+
"appKey": "your-ios-app-key"
|
|
323
|
+
},
|
|
324
|
+
"android": {
|
|
325
|
+
"appId": "your-android-app-id",
|
|
326
|
+
"appKey": "your-android-app-key"
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
## 🚨 注意事项
|
|
332
|
+
|
|
333
|
+
1. **向后兼容**: 新的模块化CLI保持与现有CLI的兼容性
|
|
334
|
+
2. **类型安全**: 所有API都有完整的TypeScript类型定义
|
|
335
|
+
3. **错误处理**: 所有操作都返回标准化的结果格式
|
|
336
|
+
4. **资源清理**: 模块支持清理函数来释放资源
|
|
337
|
+
5. **模块分离**: 功能按逻辑分离到不同模块中,便于维护和扩展
|
|
338
|
+
|
|
339
|
+
## 🤝 贡献
|
|
340
|
+
|
|
341
|
+
欢迎提交Issue和Pull Request来改进这个项目!
|
|
342
|
+
|
|
343
|
+
## 🚀 Provider API 使用指南
|
|
344
|
+
|
|
345
|
+
Provider提供了简洁的编程接口,适合在应用程序中集成React Native Update CLI功能。
|
|
346
|
+
|
|
347
|
+
### 📋 核心API方法
|
|
348
|
+
|
|
349
|
+
#### 核心业务功能
|
|
350
|
+
```typescript
|
|
351
|
+
// 打包应用
|
|
352
|
+
await provider.bundle({
|
|
353
|
+
platform: 'ios',
|
|
354
|
+
dev: false,
|
|
355
|
+
sourcemap: true
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
// 发布版本
|
|
359
|
+
await provider.publish({
|
|
360
|
+
name: 'v1.0.0',
|
|
361
|
+
description: 'Bug fixes',
|
|
362
|
+
rollout: 100
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
// 上传文件
|
|
366
|
+
await provider.upload({
|
|
367
|
+
filePath: 'app.ipa',
|
|
368
|
+
platform: 'ios'
|
|
369
|
+
});
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
#### 应用管理
|
|
373
|
+
```typescript
|
|
374
|
+
// 创建应用
|
|
375
|
+
await provider.createApp('MyApp', 'ios');
|
|
376
|
+
|
|
377
|
+
// 列出应用
|
|
378
|
+
await provider.listApps('ios');
|
|
379
|
+
|
|
380
|
+
// 获取当前应用
|
|
381
|
+
const { appId, platform } = await provider.getSelectedApp('ios');
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
#### 版本管理
|
|
385
|
+
```typescript
|
|
386
|
+
// 列出版本
|
|
387
|
+
await provider.listVersions('app123');
|
|
388
|
+
|
|
389
|
+
// 更新版本
|
|
390
|
+
await provider.updateVersion('app123', 'version456', {
|
|
391
|
+
name: 'v1.1.0',
|
|
392
|
+
description: 'New features'
|
|
393
|
+
});
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
#### 工具函数
|
|
397
|
+
```typescript
|
|
398
|
+
// 获取平台
|
|
399
|
+
const platform = await provider.getPlatform('ios');
|
|
400
|
+
|
|
401
|
+
// 加载会话
|
|
402
|
+
const session = await provider.loadSession();
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
### 🎯 使用场景
|
|
406
|
+
|
|
407
|
+
#### 1. 自动化构建脚本
|
|
408
|
+
```typescript
|
|
409
|
+
import { moduleManager } from 'react-native-update-cli';
|
|
410
|
+
|
|
411
|
+
async function buildAndPublish() {
|
|
412
|
+
const provider = moduleManager.getProvider();
|
|
413
|
+
|
|
414
|
+
// 1. 打包
|
|
415
|
+
const bundleResult = await provider.bundle({
|
|
416
|
+
platform: 'ios',
|
|
417
|
+
dev: false,
|
|
418
|
+
sourcemap: true
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
if (!bundleResult.success) {
|
|
422
|
+
throw new Error(`打包失败: ${bundleResult.error}`);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
// 2. 发布
|
|
426
|
+
const publishResult = await provider.publish({
|
|
427
|
+
name: 'v1.2.3',
|
|
428
|
+
description: 'Bug fixes and performance improvements',
|
|
429
|
+
rollout: 100
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
if (!publishResult.success) {
|
|
433
|
+
throw new Error(`发布失败: ${publishResult.error}`);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
console.log('构建和发布完成!');
|
|
437
|
+
}
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
#### 2. CI/CD集成
|
|
441
|
+
```typescript
|
|
442
|
+
async function ciBuild() {
|
|
443
|
+
const provider = moduleManager.getProvider();
|
|
444
|
+
|
|
445
|
+
const result = await provider.bundle({
|
|
446
|
+
platform: process.env.PLATFORM as 'ios' | 'android',
|
|
447
|
+
dev: process.env.NODE_ENV !== 'production',
|
|
448
|
+
sourcemap: process.env.NODE_ENV === 'production'
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
return result;
|
|
452
|
+
}
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
#### 3. 应用管理服务
|
|
456
|
+
```typescript
|
|
457
|
+
class AppManagementService {
|
|
458
|
+
private provider = moduleManager.getProvider();
|
|
459
|
+
|
|
460
|
+
async setupNewApp(name: string, platform: Platform) {
|
|
461
|
+
// 创建应用
|
|
462
|
+
const createResult = await this.provider.createApp(name, platform);
|
|
463
|
+
|
|
464
|
+
if (createResult.success) {
|
|
465
|
+
// 获取应用信息
|
|
466
|
+
const { appId } = await this.provider.getSelectedApp(platform);
|
|
467
|
+
|
|
468
|
+
// 列出版本
|
|
469
|
+
await this.provider.listVersions(appId);
|
|
470
|
+
|
|
471
|
+
return { appId, success: true };
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
return { success: false, error: createResult.error };
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
```
|
|
478
|
+
|
|
479
|
+
### ⚠️ 注意事项
|
|
480
|
+
|
|
481
|
+
1. **错误处理**: 所有Provider方法都返回`CommandResult`,需要检查`success`字段
|
|
482
|
+
2. **类型安全**: Provider提供完整的TypeScript类型支持
|
|
483
|
+
3. **会话管理**: 使用前确保已登录,可通过`loadSession()`检查
|
|
484
|
+
4. **平台支持**: 支持`'ios' | 'android' | 'harmony'`三个平台
|
|
485
|
+
|
|
486
|
+
### 🔧 高级功能
|
|
487
|
+
|
|
488
|
+
#### 自定义工作流
|
|
489
|
+
```typescript
|
|
490
|
+
// 注册自定义工作流
|
|
491
|
+
provider.registerWorkflow({
|
|
492
|
+
name: 'quick-release',
|
|
493
|
+
description: '快速发布流程',
|
|
494
|
+
steps: [
|
|
495
|
+
{
|
|
496
|
+
name: 'bundle',
|
|
497
|
+
execute: async () => {
|
|
498
|
+
return await provider.bundle({ platform: 'ios', dev: false });
|
|
499
|
+
}
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
name: 'publish',
|
|
503
|
+
execute: async (context, bundleResult) => {
|
|
504
|
+
if (!bundleResult.success) {
|
|
505
|
+
throw new Error('打包失败,无法发布');
|
|
506
|
+
}
|
|
507
|
+
return await provider.publish({ name: 'auto-release', rollout: 50 });
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
]
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
// 执行工作流
|
|
514
|
+
await provider.executeWorkflow('quick-release', { args: [], options: {} });
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
### 📚 完整示例
|
|
518
|
+
|
|
519
|
+
```typescript
|
|
520
|
+
import { moduleManager } from 'react-native-update-cli';
|
|
521
|
+
|
|
522
|
+
class ReactNativeUpdateService {
|
|
523
|
+
private provider = moduleManager.getProvider();
|
|
524
|
+
|
|
525
|
+
async initialize() {
|
|
526
|
+
// 加载会话
|
|
527
|
+
await this.provider.loadSession();
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
async buildAndDeploy(platform: Platform, version: string) {
|
|
531
|
+
try {
|
|
532
|
+
// 1. 打包
|
|
533
|
+
const bundleResult = await this.provider.bundle({
|
|
534
|
+
platform,
|
|
535
|
+
dev: false,
|
|
536
|
+
sourcemap: true
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
if (!bundleResult.success) {
|
|
540
|
+
throw new Error(`打包失败: ${bundleResult.error}`);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// 2. 发布
|
|
544
|
+
const publishResult = await this.provider.publish({
|
|
545
|
+
name: version,
|
|
546
|
+
description: `Release ${version}`,
|
|
547
|
+
rollout: 100
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
if (!publishResult.success) {
|
|
551
|
+
throw new Error(`发布失败: ${publishResult.error}`);
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
return { success: true, data: publishResult.data };
|
|
555
|
+
|
|
556
|
+
} catch (error) {
|
|
557
|
+
return {
|
|
558
|
+
success: false,
|
|
559
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
560
|
+
};
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
async getAppInfo(platform: Platform) {
|
|
565
|
+
const { appId } = await this.provider.getSelectedApp(platform);
|
|
566
|
+
const versions = await this.provider.listVersions(appId);
|
|
567
|
+
|
|
568
|
+
return { appId, versions };
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// 使用示例
|
|
573
|
+
const service = new ReactNativeUpdateService();
|
|
574
|
+
await service.initialize();
|
|
575
|
+
await service.buildAndDeploy('ios', 'v1.0.0');
|
|
576
|
+
```
|
package/cli.json
CHANGED
|
@@ -294,6 +294,24 @@
|
|
|
294
294
|
"hasValue": true
|
|
295
295
|
}
|
|
296
296
|
}
|
|
297
|
+
},
|
|
298
|
+
"list": {
|
|
299
|
+
"description": "List all bundles",
|
|
300
|
+
"options": {
|
|
301
|
+
"output": {
|
|
302
|
+
"default": "${tempDir}/output/list",
|
|
303
|
+
"hasValue": true
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
"workflow": {
|
|
308
|
+
"description": "List all workflows",
|
|
309
|
+
"options": {
|
|
310
|
+
"output": {
|
|
311
|
+
"default": "${tempDir}/output/workflow",
|
|
312
|
+
"hasValue": true
|
|
313
|
+
}
|
|
314
|
+
}
|
|
297
315
|
}
|
|
298
316
|
},
|
|
299
317
|
"globalOptions": {
|
package/lib/api.js
CHANGED
|
@@ -43,16 +43,16 @@ _export(exports, {
|
|
|
43
43
|
return uploadFile;
|
|
44
44
|
}
|
|
45
45
|
});
|
|
46
|
-
const _nodefetch = /*#__PURE__*/ _interop_require_default(require("node-fetch"));
|
|
47
46
|
const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
|
|
48
|
-
const _util = /*#__PURE__*/ _interop_require_default(require("util"));
|
|
49
47
|
const _path = /*#__PURE__*/ _interop_require_default(require("path"));
|
|
48
|
+
const _util = /*#__PURE__*/ _interop_require_default(require("util"));
|
|
49
|
+
const _filesizeparser = /*#__PURE__*/ _interop_require_default(require("filesize-parser"));
|
|
50
|
+
const _formdata = /*#__PURE__*/ _interop_require_default(require("form-data"));
|
|
51
|
+
const _nodefetch = /*#__PURE__*/ _interop_require_default(require("node-fetch"));
|
|
50
52
|
const _progress = /*#__PURE__*/ _interop_require_default(require("progress"));
|
|
51
|
-
const _packagejson = /*#__PURE__*/ _interop_require_default(require("../package.json"));
|
|
52
53
|
const _tcpping = /*#__PURE__*/ _interop_require_default(require("tcp-ping"));
|
|
53
|
-
const
|
|
54
|
+
const _packagejson = /*#__PURE__*/ _interop_require_default(require("../package.json"));
|
|
54
55
|
const _constants = require("./utils/constants");
|
|
55
|
-
const _formdata = /*#__PURE__*/ _interop_require_default(require("form-data"));
|
|
56
56
|
const _i18n = require("./utils/i18n");
|
|
57
57
|
function _interop_require_default(obj) {
|
|
58
58
|
return obj && obj.__esModule ? obj : {
|
package/lib/app.js
CHANGED
|
@@ -28,9 +28,9 @@ _export(exports, {
|
|
|
28
28
|
return listApp;
|
|
29
29
|
}
|
|
30
30
|
});
|
|
31
|
-
const _utils = require("./utils");
|
|
32
31
|
const _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
|
|
33
32
|
const _ttytable = /*#__PURE__*/ _interop_require_default(require("tty-table"));
|
|
33
|
+
const _utils = require("./utils");
|
|
34
34
|
const _api = require("./api");
|
|
35
35
|
const _i18n = require("./utils/i18n");
|
|
36
36
|
function _interop_require_default(obj) {
|