@h-ai/cli 0.1.0-alpha5
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/LICENSE +202 -0
- package/README.md +167 -0
- package/dist/chunk-2H7UOFLK.js +10 -0
- package/dist/chunk-2H7UOFLK.js.map +1 -0
- package/dist/chunk-LANIDJC7.js +659 -0
- package/dist/chunk-LANIDJC7.js.map +1 -0
- package/dist/chunk-YV7WPUI6.js +206 -0
- package/dist/chunk-YV7WPUI6.js.map +1 -0
- package/dist/config-templates-S5RI2MC6.js +5 -0
- package/dist/config-templates-S5RI2MC6.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1645 -0
- package/dist/index.js.map +1 -0
- package/dist/skill-templates-N5DU5FNX.js +5 -0
- package/dist/skill-templates-N5DU5FNX.js.map +1 -0
- package/dist/src-XJ6YXNAF.js +15030 -0
- package/dist/src-XJ6YXNAF.js.map +1 -0
- package/package.json +59 -0
- package/templates/README.md +126 -0
- package/templates/apps/admin/messages/en-US.json +33 -0
- package/templates/apps/admin/messages/zh-CN.json +33 -0
- package/templates/apps/admin/src/routes/+layout.svelte.hbs +30 -0
- package/templates/apps/admin/src/routes/+page.svelte.hbs +35 -0
- package/templates/apps/admin/src/routes/admin/+layout.svelte.hbs +44 -0
- package/templates/apps/admin/src/routes/admin/+page.svelte.hbs +45 -0
- package/templates/apps/admin/src/routes/admin/settings/+page.svelte.hbs +37 -0
- package/templates/apps/admin/src/routes/api/health/+server.ts +12 -0
- package/templates/apps/android-app/.env.hbs +3 -0
- package/templates/apps/android-app/capacitor.config.ts.hbs +12 -0
- package/templates/apps/android-app/messages/en-US.json +24 -0
- package/templates/apps/android-app/messages/zh-CN.json +24 -0
- package/templates/apps/android-app/src/lib/api.ts.hbs +30 -0
- package/templates/apps/android-app/src/lib/capacitor.ts +21 -0
- package/templates/apps/android-app/src/routes/+layout.svelte.hbs +42 -0
- package/templates/apps/android-app/src/routes/+layout.ts +7 -0
- package/templates/apps/android-app/src/routes/+page.svelte.hbs +27 -0
- package/templates/apps/api/src/routes/+layout.svelte +14 -0
- package/templates/apps/api/src/routes/+page.svelte +11 -0
- package/templates/apps/api/src/routes/api/v1/health/+server.ts +14 -0
- package/templates/apps/api/src/routes/api/v1/items/+server.ts +37 -0
- package/templates/apps/api/src/routes/api/v1/items/[id]/+server.ts +30 -0
- package/templates/apps/h5/messages/en-US.json +37 -0
- package/templates/apps/h5/messages/zh-CN.json +37 -0
- package/templates/apps/h5/src/routes/+layout.svelte.hbs +57 -0
- package/templates/apps/h5/src/routes/+page.svelte.hbs +27 -0
- package/templates/apps/h5/src/routes/discover/+page.svelte.hbs +27 -0
- package/templates/apps/h5/src/routes/profile/+page.svelte.hbs +27 -0
- package/templates/apps/website/messages/en-US.json +32 -0
- package/templates/apps/website/messages/zh-CN.json +32 -0
- package/templates/apps/website/src/routes/+layout.svelte.hbs +66 -0
- package/templates/apps/website/src/routes/+page.svelte.hbs +33 -0
- package/templates/apps/website/src/routes/about/+page.svelte.hbs +27 -0
- package/templates/apps/website/src/routes/api/health/+server.ts +12 -0
- package/templates/apps/website/src/routes/contact/+page.svelte.hbs +59 -0
- package/templates/apps/website/src/routes/services/+page.svelte.hbs +63 -0
- package/templates/base/e2e/helpers.ts +49 -0
- package/templates/base/package.json.hbs +67 -0
- package/templates/base/playwright.config.ts +32 -0
- package/templates/base/src/app.css +2 -0
- package/templates/base/src/app.d.ts.hbs +18 -0
- package/templates/base/src/app.html.hbs +16 -0
- package/templates/base/src/hooks.server.ts.hbs +123 -0
- package/templates/base/src/lib/server/init.ts.hbs +190 -0
- package/templates/base/svelte.config.js.hbs +30 -0
- package/templates/base/tsconfig.json +8 -0
- package/templates/base/vite.config.ts.hbs +27 -0
- package/templates/features/ai/routes/api/chat/+server.ts +26 -0
- package/templates/features/datapipe/routes/api/datapipe/pipeline/+server.ts +41 -0
- package/templates/features/iam/routes-admin/(auth)/+layout.svelte.hbs +21 -0
- package/templates/features/iam/routes-admin/(auth)/auth/login/+page.svelte.hbs +98 -0
- package/templates/features/iam/routes-admin/(auth)/auth/register/+page.svelte.hbs +124 -0
- package/templates/features/iam/routes-h5/auth/login/+page.svelte.hbs +98 -0
- package/templates/features/iam/routes-h5/auth/register/+page.svelte.hbs +114 -0
- package/templates/features/iam/routes-shared/api/auth/login/+server.ts +32 -0
- package/templates/features/iam/routes-shared/api/auth/logout/+server.ts +15 -0
- package/templates/features/iam/routes-shared/api/auth/me/+server.ts +12 -0
- package/templates/features/iam/routes-shared/api/auth/register/+server.ts +26 -0
- package/templates/features/payment/routes/api/v1/payment/create/+server.ts +30 -0
- package/templates/features/payment/routes/api/v1/payment/notify/[provider]/+server.ts +42 -0
- package/templates/features/payment/routes/api/v1/payment/query/[orderNo]/+server.ts +25 -0
- package/templates/features/storage/routes/api/upload/+server.ts +35 -0
- package/templates/features/vecdb/routes/api/vecdb/search/+server.ts +36 -0
- package/templates/i18n/project.inlang/settings.json +11 -0
- package/templates/skills/AGENTS.md +26 -0
- package/templates/skills/CLAUDE.md +12 -0
- package/templates/skills/copilot-instructions.md +61 -0
- package/templates/skills/hai-ai/SKILL.md +659 -0
- package/templates/skills/hai-api-client/SKILL.md +346 -0
- package/templates/skills/hai-app-create/SKILL.md +371 -0
- package/templates/skills/hai-app-review/SKILL.md +156 -0
- package/templates/skills/hai-app-tests/SKILL.md +468 -0
- package/templates/skills/hai-audit/SKILL.md +141 -0
- package/templates/skills/hai-build/SKILL.md +319 -0
- package/templates/skills/hai-cache/SKILL.md +184 -0
- package/templates/skills/hai-capacitor/SKILL.md +389 -0
- package/templates/skills/hai-core/SKILL.md +544 -0
- package/templates/skills/hai-crypto/SKILL.md +183 -0
- package/templates/skills/hai-datapipe/SKILL.md +214 -0
- package/templates/skills/hai-deploy/SKILL.md +210 -0
- package/templates/skills/hai-iam/SKILL.md +355 -0
- package/templates/skills/hai-kit/SKILL.md +319 -0
- package/templates/skills/hai-payment/SKILL.md +289 -0
- package/templates/skills/hai-reach/SKILL.md +325 -0
- package/templates/skills/hai-reldb/SKILL.md +459 -0
- package/templates/skills/hai-scheduler/SKILL.md +242 -0
- package/templates/skills/hai-storage/SKILL.md +230 -0
- package/templates/skills/hai-ui/SKILL.md +275 -0
- package/templates/skills/hai-vecdb/SKILL.md +273 -0
- package/templates/skills/opencode.json +11 -0
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hai-capacitor
|
|
3
|
+
description: 使用 @h-ai/capacitor 桥接 Capacitor 原生能力(Token 安全存储、设备信息、推送通知、相机、状态栏),构建 Android/iOS 原生应用;当需求涉及原生 App 开发、Capacitor 集成、安全存储或原生设备功能时使用。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# hai-capacitor
|
|
7
|
+
|
|
8
|
+
> `@h-ai/capacitor` 是 hai-framework 的 Capacitor 原生桥接模块,封装常用原生能力为统一 API,返回 `HaiResult<T>`。与 `@h-ai/api-client` 配合实现 App 端 Token 安全存储。
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 适用场景
|
|
13
|
+
|
|
14
|
+
- Android/iOS 原生应用开发(SvelteKit + Capacitor)
|
|
15
|
+
- Token 安全存储(Capacitor Preferences → SharedPreferences / UserDefaults)
|
|
16
|
+
- 设备信息获取(平台、型号、版本)
|
|
17
|
+
- 推送通知注册与监听(FCM / APNs)
|
|
18
|
+
- 原生相机拍照 / 相册选取
|
|
19
|
+
- 状态栏配置(沉浸式、颜色、样式)
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 模块结构
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
packages/capacitor/src/
|
|
27
|
+
index.ts # export * 聚合
|
|
28
|
+
capacitor-main.ts # 服务对象(export const capacitor)
|
|
29
|
+
capacitor-types.ts # 公共类型(CapacitorFunctions / CapacitorError / 业务类型)
|
|
30
|
+
capacitor-config.ts # 错误码(HaiCapacitorError as const)
|
|
31
|
+
capacitor-i18n.ts # i18n 消息获取器
|
|
32
|
+
capacitor-token-storage.ts # Token 存储(TokenStorage 实现 + safe* 工具)
|
|
33
|
+
capacitor-device.ts # 设备信息
|
|
34
|
+
capacitor-camera.ts # 相机/相册
|
|
35
|
+
capacitor-push.ts # 推送通知
|
|
36
|
+
capacitor-status-bar.ts # 状态栏
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## 使用步骤
|
|
42
|
+
|
|
43
|
+
### 1. 初始化与关闭
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { capacitor } from '@h-ai/capacitor'
|
|
47
|
+
|
|
48
|
+
// 应用启动时初始化(检测 Capacitor 环境可用性)
|
|
49
|
+
const result = await capacitor.init()
|
|
50
|
+
if (!result.success) {
|
|
51
|
+
// result.error.code === HaiCapacitorError.NOT_AVAILABLE.code
|
|
52
|
+
// 非 Capacitor 环境(纯 Web)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 检查状态
|
|
56
|
+
capacitor.isInitialized // boolean
|
|
57
|
+
capacitor.getPlatform() // 'android' | 'ios' | 'web'
|
|
58
|
+
capacitor.isNative() // true = 原生 App
|
|
59
|
+
|
|
60
|
+
// 关闭模块(重置状态)
|
|
61
|
+
await capacitor.close()
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 2. Token 安全存储(与 api-client 配合)
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { api } from '@h-ai/api-client'
|
|
68
|
+
import { createCapacitorTokenStorage } from '@h-ai/capacitor'
|
|
69
|
+
|
|
70
|
+
await api.init({
|
|
71
|
+
baseUrl: import.meta.env.PUBLIC_API_BASE,
|
|
72
|
+
auth: {
|
|
73
|
+
storage: createCapacitorTokenStorage(),
|
|
74
|
+
refreshUrl: '/api/v1/auth/refresh',
|
|
75
|
+
},
|
|
76
|
+
})
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`createCapacitorTokenStorage()` 返回 `TokenStorage` 实例(兼容 `@h-ai/api-client`),底层使用 `@capacitor/preferences`:
|
|
80
|
+
|
|
81
|
+
- Android → SharedPreferences(应用沙盒)
|
|
82
|
+
- iOS → UserDefaults
|
|
83
|
+
- Web → localStorage(退化,建议仅原生端使用)
|
|
84
|
+
|
|
85
|
+
所有方法内置 try-catch,Preferences 异常时 get 返回 `null`、set/clear 静默失败并记录日志。
|
|
86
|
+
|
|
87
|
+
#### Preferences 子操作
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { capacitor } from '@h-ai/capacitor'
|
|
91
|
+
|
|
92
|
+
// 返回 HaiResult<string | null>
|
|
93
|
+
const result = await capacitor.preferences.get('my_key')
|
|
94
|
+
if (result.success) {
|
|
95
|
+
// result.data — 值或 null
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
await capacitor.preferences.set('my_key', 'value')
|
|
99
|
+
await capacitor.preferences.remove('my_key')
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 3. 设备信息
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { capacitor } from '@h-ai/capacitor'
|
|
106
|
+
|
|
107
|
+
const info = await capacitor.device.getInfo()
|
|
108
|
+
if (info.success) {
|
|
109
|
+
info.data.platform // 'android' | 'ios' | 'web'
|
|
110
|
+
info.data.model // 'Pixel 7'
|
|
111
|
+
info.data.osVersion // '14'
|
|
112
|
+
info.data.manufacturer // 'Google'
|
|
113
|
+
info.data.isVirtual // false
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const version = await capacitor.device.getAppVersion()
|
|
117
|
+
if (version.success) {
|
|
118
|
+
version.data.version // '1.0.0'
|
|
119
|
+
version.data.build // '42'
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### 4. 推送通知
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
import { capacitor } from '@h-ai/capacitor'
|
|
127
|
+
|
|
128
|
+
// 注册推送(请求权限 + 获取设备 Token)
|
|
129
|
+
const reg = await capacitor.push.register()
|
|
130
|
+
if (reg.success) {
|
|
131
|
+
// 将 reg.data.token 上报给后端
|
|
132
|
+
await api.post('/push/register', { token: reg.data.token })
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// 监听推送事件(返回 HaiResult 包裹的 async 清理函数)
|
|
136
|
+
const listenResult = await capacitor.push.listen({
|
|
137
|
+
onReceived: (notification) => {
|
|
138
|
+
// 前台收到推送
|
|
139
|
+
// notification: { id, title?, body?, data? }
|
|
140
|
+
},
|
|
141
|
+
onActionPerformed: (notification) => {
|
|
142
|
+
// 用户点击推送
|
|
143
|
+
},
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
// 停止监听
|
|
147
|
+
if (listenResult.success) {
|
|
148
|
+
await listenResult.data()
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### 5. 相机
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
import { capacitor } from '@h-ai/capacitor'
|
|
156
|
+
|
|
157
|
+
const photo = await capacitor.camera.takePhoto({
|
|
158
|
+
quality: 80, // 0-100
|
|
159
|
+
source: 'camera', // 'camera' | 'photos' | 'prompt'
|
|
160
|
+
resultType: 'base64', // 'uri' | 'base64' | 'dataUrl'
|
|
161
|
+
width: 800, // 最大宽度(可选)
|
|
162
|
+
height: 600, // 最大高度(可选)
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
if (photo.success) {
|
|
166
|
+
const imgSrc = `data:image/${photo.data.format};base64,${photo.data.data}`
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### 6. 状态栏
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
import { capacitor } from '@h-ai/capacitor'
|
|
174
|
+
|
|
175
|
+
await capacitor.statusBar.configure({
|
|
176
|
+
backgroundColor: '#ffffff',
|
|
177
|
+
style: 'dark', // 'dark' | 'light' | 'default'(文字颜色)
|
|
178
|
+
overlay: true, // 沉浸式
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
await capacitor.statusBar.hide()
|
|
182
|
+
await capacitor.statusBar.show()
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## 核心 API
|
|
188
|
+
|
|
189
|
+
| API | 用途 | 返回值 |
|
|
190
|
+
| --- | --- | --- |
|
|
191
|
+
| `capacitor.init()` | 初始化模块(检测环境) | `HaiResult<void>` |
|
|
192
|
+
| `capacitor.close()` | 关闭模块,重置状态 | `Promise<void>` |
|
|
193
|
+
| `capacitor.getPlatform()` | 获取当前平台 | `'android' \| 'ios' \| 'web'` |
|
|
194
|
+
| `capacitor.isNative()` | 是否为原生环境 | `boolean` |
|
|
195
|
+
| `capacitor.isInitialized` | 是否已初始化 | `boolean` |
|
|
196
|
+
| `createCapacitorTokenStorage()` | 创建 Token 存储 | `TokenStorage`(兼容 api-client) |
|
|
197
|
+
| `capacitor.preferences.get(key)` | 安全读取 Preference | `HaiResult<string \| null>` |
|
|
198
|
+
| `capacitor.preferences.set(key, value)` | 安全写入 Preference | `HaiResult<void>` |
|
|
199
|
+
| `capacitor.preferences.remove(key)` | 安全删除 Preference | `HaiResult<void>` |
|
|
200
|
+
| `capacitor.device.getInfo()` | 设备信息 | `HaiResult<DeviceInfo>` |
|
|
201
|
+
| `capacitor.device.getAppVersion()` | 应用版本 | `HaiResult<{ version, build }>` |
|
|
202
|
+
| `capacitor.push.register()` | 注册推送 | `HaiResult<PushRegistration>` |
|
|
203
|
+
| `capacitor.push.listen(callbacks)` | 监听推送事件 | `HaiResult<() => Promise<void>>`(async 清理函数) |
|
|
204
|
+
| `capacitor.camera.takePhoto(options?)` | 拍照 / 选取图片 | `HaiResult<PhotoResult>` |
|
|
205
|
+
| `capacitor.statusBar.configure(config)` | 配置状态栏 | `HaiResult<void>` |
|
|
206
|
+
| `capacitor.statusBar.show()` | 显示状态栏 | `HaiResult<void>` |
|
|
207
|
+
| `capacitor.statusBar.hide()` | 隐藏状态栏 | `HaiResult<void>` |
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## 错误码 — `HaiCapacitorError`
|
|
212
|
+
|
|
213
|
+
| 错误码 | code | 说明 |
|
|
214
|
+
| -------------------------------------------- | ---------------------- | -------------------- |
|
|
215
|
+
| `HaiCapacitorError.INIT_FAILED` | `hai:capacitor:001` | 初始化失败 |
|
|
216
|
+
| `HaiCapacitorError.NOT_AVAILABLE` | `hai:capacitor:002` | Capacitor 不可用 |
|
|
217
|
+
| `HaiCapacitorError.INIT_IN_PROGRESS` | `hai:capacitor:003` | 正在初始化中 |
|
|
218
|
+
| `HaiCapacitorError.NOT_INITIALIZED` | `hai:capacitor:010` | 模块未初始化 |
|
|
219
|
+
| `HaiCapacitorError.PREFERENCES_GET_FAILED` | `hai:capacitor:011` | Preferences 读取失败 |
|
|
220
|
+
| `HaiCapacitorError.PREFERENCES_SET_FAILED` | `hai:capacitor:012` | Preferences 写入失败 |
|
|
221
|
+
| `HaiCapacitorError.PREFERENCES_REMOVE_FAILED`| `hai:capacitor:013` | Preferences 删除失败 |
|
|
222
|
+
| `HaiCapacitorError.DEVICE_INFO_FAILED` | `hai:capacitor:020` | 获取设备信息失败 |
|
|
223
|
+
| `HaiCapacitorError.PUSH_REGISTER_FAILED` | `hai:capacitor:030` | 推送注册失败 |
|
|
224
|
+
| `HaiCapacitorError.PUSH_LISTEN_FAILED` | `hai:capacitor:031` | 推送监听失败 |
|
|
225
|
+
| `HaiCapacitorError.CAMERA_FAILED` | `hai:capacitor:040` | 拍照/相册失败 |
|
|
226
|
+
| `HaiCapacitorError.STATUS_BAR_FAILED` | `hai:capacitor:050` | 状态栏配置失败 |
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## 常见模式
|
|
231
|
+
|
|
232
|
+
### Android 应用标准初始化
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
// src/lib/capacitor.ts
|
|
236
|
+
import { capacitor } from '@h-ai/capacitor'
|
|
237
|
+
|
|
238
|
+
export async function initCapacitor() {
|
|
239
|
+
const result = await capacitor.init()
|
|
240
|
+
if (!result.success) {
|
|
241
|
+
return
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (capacitor.isNative()) {
|
|
245
|
+
await capacitor.statusBar.configure({
|
|
246
|
+
backgroundColor: '#ffffff',
|
|
247
|
+
style: 'light',
|
|
248
|
+
overlay: false,
|
|
249
|
+
})
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
```svelte
|
|
255
|
+
<!-- src/routes/+layout.svelte -->
|
|
256
|
+
<script lang="ts">
|
|
257
|
+
import { onMount } from 'svelte'
|
|
258
|
+
import { initCapacitor } from '$lib/capacitor'
|
|
259
|
+
|
|
260
|
+
onMount(() => { initCapacitor() })
|
|
261
|
+
</script>
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### SPA 模式配置(必需)
|
|
265
|
+
|
|
266
|
+
Capacitor 应用必须使用 SPA 模式:
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
// src/routes/+layout.ts
|
|
270
|
+
export const prerender = true
|
|
271
|
+
export const ssr = false
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
```javascript
|
|
275
|
+
// svelte.config.js
|
|
276
|
+
import adapter from '@sveltejs/adapter-static'
|
|
277
|
+
|
|
278
|
+
const config = {
|
|
279
|
+
kit: {
|
|
280
|
+
adapter: adapter({
|
|
281
|
+
pages: 'build',
|
|
282
|
+
assets: 'build',
|
|
283
|
+
fallback: 'index.html',
|
|
284
|
+
}),
|
|
285
|
+
},
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### Token 存储 + 认证流程
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
// src/lib/api.ts
|
|
293
|
+
import { api } from '@h-ai/api-client'
|
|
294
|
+
import { createCapacitorTokenStorage } from '@h-ai/capacitor'
|
|
295
|
+
|
|
296
|
+
export async function initApi() {
|
|
297
|
+
return api.init({
|
|
298
|
+
baseUrl: `${import.meta.env.PUBLIC_API_BASE}/api/v1`,
|
|
299
|
+
auth: {
|
|
300
|
+
storage: createCapacitorTokenStorage(),
|
|
301
|
+
refreshUrl: '/auth/refresh',
|
|
302
|
+
},
|
|
303
|
+
})
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export { api }
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### 推送通知完整流程
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
import { capacitor } from '@h-ai/capacitor'
|
|
313
|
+
|
|
314
|
+
export async function setupPush() {
|
|
315
|
+
if (!capacitor.isNative()) {
|
|
316
|
+
return
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const reg = await capacitor.push.register()
|
|
320
|
+
if (!reg.success) {
|
|
321
|
+
return
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// 上报 Token 给后端
|
|
325
|
+
await api.post('/push/register', {
|
|
326
|
+
token: reg.data.token,
|
|
327
|
+
platform: capacitor.getPlatform(),
|
|
328
|
+
})
|
|
329
|
+
|
|
330
|
+
// 监听推送
|
|
331
|
+
const listenResult = await capacitor.push.listen({
|
|
332
|
+
onReceived: (n) => {
|
|
333
|
+
// 前台通知处理
|
|
334
|
+
},
|
|
335
|
+
onActionPerformed: (n) => {
|
|
336
|
+
// 用户点击跳转
|
|
337
|
+
},
|
|
338
|
+
})
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### 拍照上传
|
|
343
|
+
|
|
344
|
+
```typescript
|
|
345
|
+
import { capacitor } from '@h-ai/capacitor'
|
|
346
|
+
|
|
347
|
+
async function captureAndUpload() {
|
|
348
|
+
const photo = await capacitor.camera.takePhoto({
|
|
349
|
+
source: 'camera',
|
|
350
|
+
resultType: 'base64',
|
|
351
|
+
quality: 80,
|
|
352
|
+
width: 1024,
|
|
353
|
+
})
|
|
354
|
+
|
|
355
|
+
if (!photo.success) {
|
|
356
|
+
return
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// 上传 base64 给后端
|
|
360
|
+
await api.post('/files/upload', {
|
|
361
|
+
data: photo.data.data,
|
|
362
|
+
format: photo.data.format,
|
|
363
|
+
})
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
---
|
|
368
|
+
|
|
369
|
+
## 插件依赖
|
|
370
|
+
|
|
371
|
+
| 插件 | 类型 | 用于 |
|
|
372
|
+
| --- | --- | --- |
|
|
373
|
+
| `@capacitor/core` | peerDependency(必需) | 核心运行时 |
|
|
374
|
+
| `@capacitor/preferences` | peerDependency(必需) | Token 存储 |
|
|
375
|
+
| `@capacitor/device` | 可选 | `getDeviceInfo()` |
|
|
376
|
+
| `@capacitor/app` | 可选 | `getAppVersion()` |
|
|
377
|
+
| `@capacitor/push-notifications` | 可选 | `registerPush()` / `listenPush()` |
|
|
378
|
+
| `@capacitor/camera` | 可选 | `takePhoto()` |
|
|
379
|
+
| `@capacitor/status-bar` | 可选 | `configureStatusBar()` / `show/hide` |
|
|
380
|
+
|
|
381
|
+
可选插件未安装时,对应 API 调用会返回 `err`(动态 import 失败被 catch)。
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
## 相关 Skills
|
|
386
|
+
|
|
387
|
+
- `hai-api-client`:HTTP 客户端(Token 管理依赖 capacitor 存储)
|
|
388
|
+
- `hai-iam`:认证流程(登录获取 Token → 存储到 Capacitor)
|
|
389
|
+
- `hai-ui`:移动端 UI 组件(SafeArea、BottomNav 等)
|