@h-ai/capacitor 1.0.0-beta.19 → 1.0.0-beta.20

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.en.md CHANGED
@@ -4,11 +4,73 @@
4
4
 
5
5
  [Framework home](../../README.en.md) · Related modules: [@h-ai/api-client](../api-client/README.en.md) · [@h-ai/core](../core/README.en.md)
6
6
 
7
- ## Introduction
8
-
9
7
  A Capacitor native bridge for hai Framework mobile apps, with a unified API for secure token storage, device information, push notifications, camera, and status bar access.
10
8
 
11
- ## Core features
9
+ ## Quick Start
10
+
11
+ ```ts
12
+ import { capacitor } from '@h-ai/capacitor'
13
+
14
+ const initialized = await capacitor.init()
15
+ if (!initialized.success)
16
+ throw new Error(initialized.error.message)
17
+ const failures: unknown[] = []
18
+ try {
19
+ const saved = await capacitor.preferences.set('theme', 'dark')
20
+ if (!saved.success)
21
+ throw new Error(saved.error.message)
22
+ const theme = await capacitor.preferences.get('theme')
23
+ if (!theme.success)
24
+ throw new Error(theme.error.message)
25
+ // theme.data is 'dark'; an absent key returns null.
26
+ }
27
+ catch (cause) {
28
+ failures.push(cause)
29
+ }
30
+ finally {
31
+ const closed = await capacitor.close()
32
+ if (!closed.success)
33
+ failures.push(closed.error)
34
+ }
35
+ if (failures.length)
36
+ throw new AggregateError(failures, 'Native preference operation failed')
37
+ ```
38
+
39
+ ## Features
40
+
41
+ ### Purpose, inputs and outputs
42
+
43
+ Use capacitor subfeatures after successful initialization. Check HaiResult.success before reading data; void has no business data and Promises must be awaited. tokens is an independent adapter returned by createCapacitorTokenStorage(); its methods reject on native storage failure. Standalone Preferences helpers do not use module state and wrap the same plugin operations in HaiResult.
44
+
45
+ | Entry | Use case | Input (`—` means none) | Return value | Call example |
46
+ | -------------------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
47
+ | `capacitor.init` | Detect and prepare the native host | `—` | `Promise<HaiResult<void>>` | `await capacitor.init()` |
48
+ | `capacitor.close` | Release owned native resources | `—` | `Promise<HaiResult<void>>` | `await capacitor.close()` |
49
+ | `capacitor.getPlatform` | Choose platform behavior | `—` | `string: ios / android / web` | `capacitor.getPlatform()` |
50
+ | `capacitor.isNative` | Check the native environment | `—` | `boolean` | `capacitor.isNative()` |
51
+ | `capacitor.isInitialized` | Check module readiness | `—` | `boolean` | `capacitor.isInitialized` |
52
+ | `capacitor.device.getInfo` | Read device diagnostics | `—` | `Promise<HaiResult<{ platform, osVersion, model, manufacturer, isVirtual, appVersion?, appBuild? }>>` | `await capacitor.device.getInfo()` |
53
+ | `capacitor.device.getAppVersion` | Read the installed app version | `—` | `Promise<HaiResult<{ version, build }>>` | `await capacitor.device.getAppVersion()` |
54
+ | `capacitor.camera.takePhoto` | Capture or select a photo | `{ source?: camera/photos/prompt, quality?: 0…100, width?, height?, resultType?: uri/base64/dataUrl }` | `Promise<HaiResult<{ data: string, format: string }>>` | `await capacitor.camera.takePhoto({ source: "photos", resultType: "dataUrl" })` |
55
+ | `capacitor.push.register` | Request permission and a push token | `{ signal?: AbortSignal }` | `Promise<HaiResult<{ token: string }>>` | `await capacitor.push.register()` |
56
+ | `capacitor.push.listen` | Observe notifications and taps | `{ onReceived?, onActionPerformed? }, { signal? }` | `Promise<HaiResult<() => Promise<HaiResult<void>>>>` | `await capacitor.push.listen(callbacks, { signal })` |
57
+ | `capacitor.statusBar.configure` | Configure the status bar | `{ style?: dark/light/default, backgroundColor?: color, overlay?: boolean }` | `Promise<HaiResult<void>>` | `await capacitor.statusBar.configure({ style: "dark", overlay: true })` |
58
+ | `capacitor.statusBar.show` | Show the status bar | `—` | `Promise<HaiResult<void>>` | `await capacitor.statusBar.show()` |
59
+ | `capacitor.statusBar.hide` | Hide the status bar | `—` | `Promise<HaiResult<void>>` | `await capacitor.statusBar.hide()` |
60
+ | `capacitor.preferences.get` | Read a nonsensitive preference | `key: string` | `Promise<HaiResult<string / null>>` | `await capacitor.preferences.get("theme")` |
61
+ | `capacitor.preferences.set` | Save a nonsensitive preference | `key: string, value: string` | `Promise<HaiResult<void>>` | `await capacitor.preferences.set("theme", "dark")` |
62
+ | `capacitor.preferences.remove` | Remove a nonsensitive preference | `key: string` | `Promise<HaiResult<void>>` | `await capacitor.preferences.remove("theme")` |
63
+ | `createCapacitorTokenStorage` | Create native secure token storage | `—` | `TokenStorage` | `createCapacitorTokenStorage()` |
64
+ | `tokens.getAccessToken` | Read the saved access token | `—` | `Promise<string / null>` | `await tokens.getAccessToken()` |
65
+ | `tokens.getRefreshToken` | Read the saved refresh token | `—` | `Promise<string / null>` | `await tokens.getRefreshToken()` |
66
+ | `tokens.setAccessToken` | Save an access token | `token: string` | `Promise<void>` | `await tokens.setAccessToken(accessToken)` |
67
+ | `tokens.setRefreshToken` | Save a refresh token | `token: string` | `Promise<void>` | `await tokens.setRefreshToken(refreshToken)` |
68
+ | `tokens.clear` | Remove both saved credentials | `—` | `Promise<void>` | `await tokens.clear()` |
69
+ | `safeGetPreference` | Read a preference without module lifecycle | `key: string` | `Promise<HaiResult<string / null>>` | `await safeGetPreference("theme")` |
70
+ | `safeSetPreference` | Save a preference without module lifecycle | `key: string, value: string` | `Promise<HaiResult<void>>` | `await safeSetPreference("theme", "dark")` |
71
+ | `safeRemovePreference` | Remove a preference without module lifecycle | `key: string` | `Promise<HaiResult<void>>` | `await safeRemovePreference("theme")` |
72
+
73
+ Photo source selects the camera, library or prompt; quality is 0–100 and width/height are pixel constraints. Successful data is a displayable webPath, raw Base64 or a MIME-prefixed Data URL according to resultType; format is the plugin image format. callbacks.onReceived/onActionPerformed receive notifications and signal comes from an application AbortController. A successful listen returns an async cleanup function whose result must be checked. Import standalone factories and Preferences helpers from the package root.
12
74
 
13
75
  - **Token storage**: `@aparajita/capacitor-secure-storage` (required on native platforms). Android uses KeyStore + encrypted SharedPreferences; iOS uses Keychain. No Web fallback.
14
76
  - **Preferences**: `@capacitor/preferences` (required). General preferences storage for nonsensitive settings, not authentication tokens.
@@ -18,21 +80,7 @@ A Capacitor native bridge for hai Framework mobile apps, with a unified API for
18
80
  - **Camera/gallery**: `@capacitor/camera` (optional). Capture photos or select gallery images.
19
81
  - **Status bar**: `@capacitor/status-bar` (optional). Immersive mode, background color, and style settings.
20
82
 
21
- ## Getting started
22
-
23
- ### Quick start
24
-
25
- ```ts
26
- import { capacitor } from '@h-ai/capacitor'
27
-
28
- // 应用启动时初始化(检测 Capacitor 环境)
29
- const result = await capacitor.init()
30
- if (!result.success) {
31
- // 非 Capacitor 环境(纯 Web)
32
- }
33
- ```
34
-
35
- #### Secure token storage with api-client
83
+ ### Secure token storage with api-client
36
84
 
37
85
  ```ts
38
86
  import { apiClient } from '@h-ai/api-client'
@@ -55,7 +103,7 @@ A failed credential write blocks both credentials, including an access token alr
55
103
 
56
104
  All TokenStorage instances in the same module share a native mutation queue. `clear()` waits for earlier writes before removing credentials, preventing late writes from restoring old tokens after successful cleanup. Explicit later writes may save new credentials. This ordering does not coordinate independent WebViews or JavaScript runtimes.
57
105
 
58
- #### Device information and push notifications
106
+ ### Device information and push notifications
59
107
 
60
108
  ```ts
61
109
  import { capacitor } from '@h-ai/capacitor'
@@ -73,7 +121,7 @@ if (reg.success) {
73
121
 
74
122
  Push requires an actual native platform. The setup phase of `push.register({ signal? })` and `push.listen(callbacks, { signal? })` has a 30-second deadline including permission requests and listener attachment. Failure, timeout, cancellation and `capacitor.close()` stop callbacks and remove owned handles; late handles are removed when they arrive. Other consumers are not affected through removeAllListeners. After listen succeeds, its signal and returned cleanup can still stop it. Cleanup and close return `HaiResult<void>`; native removal failures return `PUSH_CLEANUP_FAILED` (`capacitor:032`) and retain failed handles for retry without repeating successful removals. Closing disables the module immediately, and initialization retries pending cleanup first. Controlled plugin timing tests do not replace repeated registration, permission and FCM/APNs checks on Android/iOS devices.
75
123
 
76
- #### Status bar
124
+ ### Status bar
77
125
 
78
126
  ```ts
79
127
  import { capacitor } from '@h-ai/capacitor'
@@ -85,7 +133,7 @@ await capacitor.statusBar.configure({
85
133
  })
86
134
  ```
87
135
 
88
- #### Camera
136
+ ### Camera
89
137
 
90
138
  ```ts
91
139
  const photo = await capacitor.camera.takePhoto({
@@ -95,7 +143,7 @@ const photo = await capacitor.camera.takePhoto({
95
143
  })
96
144
  ```
97
145
 
98
- #### Preferences
146
+ ### Preferences
99
147
 
100
148
  ```ts
101
149
  await capacitor.preferences.set('my_key', 'value')
@@ -105,18 +153,6 @@ await capacitor.preferences.remove('my_key')
105
153
 
106
154
  `capacitor.preferences` is for general preferences such as language, theme, and drafts. Use `createCapacitorTokenStorage()` for authentication tokens.
107
155
 
108
- ### Configuration
109
-
110
- This module has no configuration file. `capacitor.init()` only checks whether the Capacitor runtime is available.
111
-
112
- Capacitor applications must use SPA mode:
113
-
114
- ```ts
115
- // src/routes/+layout.ts
116
- export const prerender = true
117
- export const ssr = false
118
- ```
119
-
120
156
  ### Build an Android APK in a container
121
157
 
122
158
  Run `pnpm build --target app --platform android --runtime auto --debug` at the Hai project root. Omit `--debug` for a signed release. Successful batches appear under `.hai/build/app/android/<variant>/`. See the [native build and signing instructions](../../docs/usage/getting-started/build.md#原生和离线条件).
@@ -142,9 +178,21 @@ docker run --rm -it --platform linux/amd64 \
142
178
 
143
179
  Downloading dependencies requires access to npm, Gradle distributions, Google Maven, and Maven Central. Use the app's signing workflow for release builds. Mount the keystore read-only and inject passwords through the build environment. See the [mobile-app packaging and acceptance example](../../apps/mobile-app/README.md#原生交付与验收).
144
180
 
145
- ### Error handling
181
+ ## Configuration
182
+
183
+ This module has no configuration file. `capacitor.init()` only checks whether the Capacitor runtime is available.
184
+
185
+ Native WebViews load a client application. For SvelteKit, configure a static SPA as below; pure Svelte/Vite templates do not use this route file:
186
+
187
+ ```ts
188
+ // src/routes/+layout.ts
189
+ export const prerender = true
190
+ export const ssr = false
191
+ ```
192
+
193
+ ## Error Handling
146
194
 
147
- Business operations on `capacitor.*` and `safe*Preference` return `HaiResult<T>`. TokenStorage adapter methods reject their promises on platform or storage errors:
195
+ `init/close`, device/camera/push/statusBar/preferences operations and `safe*Preference` return `HaiResult<T>`; `getPlatform/isNative/isInitialized` return direct values. TokenStorage methods reject on platform or storage errors:
148
196
 
149
197
  ```ts
150
198
  import { capacitor, HaiCapacitorError } from '@h-ai/capacitor'
@@ -175,7 +223,7 @@ Common error codes:
175
223
  | `HaiCapacitorError.CAMERA_FAILED` | `hai:capacitor:040` | Camera operation failed |
176
224
  | `HaiCapacitorError.STATUS_BAR_FAILED` | `hai:capacitor:050` | Status bar operation failed |
177
225
 
178
- ## Development and testing
226
+ ## Development
179
227
 
180
228
  ```bash
181
229
  pnpm --filter @h-ai/capacitor test
package/README.ja.md CHANGED
@@ -4,11 +4,73 @@
4
4
 
5
5
  [フレームワークのホーム](../../README.ja.md) · 関連モジュール:[@h-ai/api-client](../api-client/README.ja.md) · [@h-ai/core](../core/README.ja.md)
6
6
 
7
- ## 概要
8
-
9
7
  hai Framework のモバイルアプリ向け Capacitor ネイティブブリッジ。安全な Token ストレージ、端末情報、プッシュ通知、カメラ、ステータスバーを共通 API で提供します。
10
8
 
11
- ## 主な機能
9
+ ## クイックスタート
10
+
11
+ ```ts
12
+ import { capacitor } from '@h-ai/capacitor'
13
+
14
+ const initialized = await capacitor.init()
15
+ if (!initialized.success)
16
+ throw new Error(initialized.error.message)
17
+ const failures: unknown[] = []
18
+ try {
19
+ const saved = await capacitor.preferences.set('theme', 'dark')
20
+ if (!saved.success)
21
+ throw new Error(saved.error.message)
22
+ const theme = await capacitor.preferences.get('theme')
23
+ if (!theme.success)
24
+ throw new Error(theme.error.message)
25
+ // theme.data は 'dark'。保存していないキーは null。
26
+ }
27
+ catch (cause) {
28
+ failures.push(cause)
29
+ }
30
+ finally {
31
+ const closed = await capacitor.close()
32
+ if (!closed.success)
33
+ failures.push(closed.error)
34
+ }
35
+ if (failures.length)
36
+ throw new AggregateError(failures, 'Native preference operation failed')
37
+ ```
38
+
39
+ ## 機能
40
+
41
+ ### 用途・入力・出力
42
+
43
+ capacitor のサブ機能は初期化成功後に使用します。HaiResult<T> は success の確認後に data を読み、void は業務データなし、Promise は await します。tokens は createCapacitorTokenStorage() が返す独立アダプターで、各メソッドはネイティブ保存に失敗すると Promise を拒否します。独立 Preferences ヘルパーはモジュール状態を使わず、同じプラグイン操作を HaiResult で返します。
44
+
45
+ | 入口 | 使用場面 | 入力(`—` は引数なし) | 戻り値 | 呼出例 |
46
+ | -------------------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
47
+ | `capacitor.init` | ネイティブ環境を確認して準備する | `—` | `Promise<HaiResult<void>>` | `await capacitor.init()` |
48
+ | `capacitor.close` | 所有するリソースを解放する | `—` | `Promise<HaiResult<void>>` | `await capacitor.close()` |
49
+ | `capacitor.getPlatform` | プラットフォーム別に処理する | `—` | `string: ios / android / web` | `capacitor.getPlatform()` |
50
+ | `capacitor.isNative` | ネイティブ環境か確認する | `—` | `boolean` | `capacitor.isNative()` |
51
+ | `capacitor.isInitialized` | モジュールの状態を確認する | `—` | `boolean` | `capacitor.isInitialized` |
52
+ | `capacitor.device.getInfo` | 端末の診断情報を取得する | `—` | `Promise<HaiResult<{ platform, osVersion, model, manufacturer, isVirtual, appVersion?, appBuild? }>>` | `await capacitor.device.getInfo()` |
53
+ | `capacitor.device.getAppVersion` | インストール済みアプリの版を取得する | `—` | `Promise<HaiResult<{ version, build }>>` | `await capacitor.device.getAppVersion()` |
54
+ | `capacitor.camera.takePhoto` | 撮影または写真を選択する | `{ source?: camera/photos/prompt, quality?: 0…100, width?, height?, resultType?: uri/base64/dataUrl }` | `Promise<HaiResult<{ data: string, format: string }>>` | `await capacitor.camera.takePhoto({ source: "photos", resultType: "dataUrl" })` |
55
+ | `capacitor.push.register` | 権限を要求してプッシュトークンを取得する | `{ signal?: AbortSignal }` | `Promise<HaiResult<{ token: string }>>` | `await capacitor.push.register()` |
56
+ | `capacitor.push.listen` | 通知とタップを監視する | `{ onReceived?, onActionPerformed? }, { signal? }` | `Promise<HaiResult<() => Promise<HaiResult<void>>>>` | `await capacitor.push.listen(callbacks, { signal })` |
57
+ | `capacitor.statusBar.configure` | ステータスバーを設定する | `{ style?: dark/light/default, backgroundColor?: color, overlay?: boolean }` | `Promise<HaiResult<void>>` | `await capacitor.statusBar.configure({ style: "dark", overlay: true })` |
58
+ | `capacitor.statusBar.show` | ステータスバーを表示する | `—` | `Promise<HaiResult<void>>` | `await capacitor.statusBar.show()` |
59
+ | `capacitor.statusBar.hide` | ステータスバーを非表示にする | `—` | `Promise<HaiResult<void>>` | `await capacitor.statusBar.hide()` |
60
+ | `capacitor.preferences.get` | 機密でない設定を読む | `key: string` | `Promise<HaiResult<string / null>>` | `await capacitor.preferences.get("theme")` |
61
+ | `capacitor.preferences.set` | 機密でない設定を保存する | `key: string, value: string` | `Promise<HaiResult<void>>` | `await capacitor.preferences.set("theme", "dark")` |
62
+ | `capacitor.preferences.remove` | 機密でない設定を削除する | `key: string` | `Promise<HaiResult<void>>` | `await capacitor.preferences.remove("theme")` |
63
+ | `createCapacitorTokenStorage` | ネイティブの安全な認証保存を作成する | `—` | `TokenStorage` | `createCapacitorTokenStorage()` |
64
+ | `tokens.getAccessToken` | 保存したアクセストークンを読む | `—` | `Promise<string / null>` | `await tokens.getAccessToken()` |
65
+ | `tokens.getRefreshToken` | 保存した更新トークンを読む | `—` | `Promise<string / null>` | `await tokens.getRefreshToken()` |
66
+ | `tokens.setAccessToken` | アクセストークンを保存する | `token: string` | `Promise<void>` | `await tokens.setAccessToken(accessToken)` |
67
+ | `tokens.setRefreshToken` | 更新トークンを保存する | `token: string` | `Promise<void>` | `await tokens.setRefreshToken(refreshToken)` |
68
+ | `tokens.clear` | 保存した認証情報を削除する | `—` | `Promise<void>` | `await tokens.clear()` |
69
+ | `safeGetPreference` | モジュールのライフサイクル外で設定を読む | `key: string` | `Promise<HaiResult<string / null>>` | `await safeGetPreference("theme")` |
70
+ | `safeSetPreference` | モジュールのライフサイクル外で設定を保存する | `key: string, value: string` | `Promise<HaiResult<void>>` | `await safeSetPreference("theme", "dark")` |
71
+ | `safeRemovePreference` | モジュールのライフサイクル外で設定を削除する | `key: string` | `Promise<HaiResult<void>>` | `await safeRemovePreference("theme")` |
72
+
73
+ 写真の source はカメラ・ライブラリ・選択画面、quality は 0–100、width/height はピクセル制約です。成功時の data は resultType に応じた webPath、生 Base64、MIME 接頭辞付き Data URL、format はプラグインの画像形式です。callbacks.onReceived/onActionPerformed は通知を受け、signal はアプリの AbortController から渡します。listen 成功時の data は await して結果を確認する解除関数です。独立工場と Preferences ヘルパーはパッケージのルートから import します。
12
74
 
13
75
  - **Token ストレージ**:`@aparajita/capacitor-secure-storage`(ネイティブで必須)。Android は KeyStore + 暗号化 SharedPreferences、iOS は Keychain を使用。Web へのフォールバックはありません。
14
76
  - **Preferences**:`@capacitor/preferences`(必須)。機密情報を含まない一般設定の保存用で、認証 Token には使用しません。
@@ -18,21 +80,7 @@ hai Framework のモバイルアプリ向け Capacitor ネイティブブリッ
18
80
  - **カメラ/アルバム**:`@capacitor/camera`(任意)。撮影とアルバム画像の選択。
19
81
  - **ステータスバー**:`@capacitor/status-bar`(任意)。没入型表示、背景色、スタイルの設定。
20
82
 
21
- ## 使い始める
22
-
23
- ### クイックスタート
24
-
25
- ```ts
26
- import { capacitor } from '@h-ai/capacitor'
27
-
28
- // 应用启动时初始化(检测 Capacitor 环境)
29
- const result = await capacitor.init()
30
- if (!result.success) {
31
- // 非 Capacitor 环境(纯 Web)
32
- }
33
- ```
34
-
35
- #### api-client と連携する安全な Token ストレージ
83
+ ### api-client と連携する安全な Token ストレージ
36
84
 
37
85
  ```ts
38
86
  import { apiClient } from '@h-ai/api-client'
@@ -55,7 +103,7 @@ await apiClient.init({
55
103
 
56
104
  同じモジュール内のすべての TokenStorage はネイティブ変更キューを共有します。`clear()` は先行書き込みの完了後に削除し、削除成功後に古い書き込みが認証情報を復活させることを防ぎます。その後の明示的な書き込みは新しい認証情報を保存できます。別の WebView や JavaScript 実行環境とのプロセス間調整は提供しません。
57
105
 
58
- #### 端末情報とプッシュ通知
106
+ ### 端末情報とプッシュ通知
59
107
 
60
108
  ```ts
61
109
  import { capacitor } from '@h-ai/capacitor'
@@ -73,7 +121,7 @@ if (reg.success) {
73
121
 
74
122
  Push は実際のネイティブ環境が必要です。`push.register({ signal? })` と `push.listen(callbacks, { signal? })` の設定段階は権限要求とリスナー登録を含め30秒で終了します。失敗、タイムアウト、中止、`capacitor.close()` はコールバックを停止し、所有するハンドルを除去します。遅延したハンドルも到着時に除去し、removeAllListeners で他の利用者を巻き込みません。listen 成功後も signal と cleanup が有効です。cleanup と close は `HaiResult<void>` を返し、ネイティブ除去失敗は `PUSH_CLEANUP_FAILED`(`capacitor:032`)です。失敗したハンドルを保持して再試行し、成功済みの除去は繰り返しません。終了直後にモジュールを無効化し、再初期化前に残存ハンドルを処理します。制御したプラグイン試験は Android/iOS 実機の権限、FCM/APNs、反復登録試験を代替しません。
75
123
 
76
- #### ステータスバー
124
+ ### ステータスバー
77
125
 
78
126
  ```ts
79
127
  import { capacitor } from '@h-ai/capacitor'
@@ -85,7 +133,7 @@ await capacitor.statusBar.configure({
85
133
  })
86
134
  ```
87
135
 
88
- #### カメラ
136
+ ### カメラ
89
137
 
90
138
  ```ts
91
139
  const photo = await capacitor.camera.takePhoto({
@@ -95,7 +143,7 @@ const photo = await capacitor.camera.takePhoto({
95
143
  })
96
144
  ```
97
145
 
98
- #### Preferences
146
+ ### Preferences
99
147
 
100
148
  ```ts
101
149
  await capacitor.preferences.set('my_key', 'value')
@@ -105,18 +153,6 @@ await capacitor.preferences.remove('my_key')
105
153
 
106
154
  `capacitor.preferences` は言語、テーマ、下書きなどの一般的な設定用です。認証 Token には `createCapacitorTokenStorage()` を使用してください。
107
155
 
108
- ### 設定
109
-
110
- このモジュールに設定ファイルはありません。`capacitor.init()` は Capacitor の実行環境が利用可能かどうかのみを確認します。
111
-
112
- Capacitor アプリケーションは SPA モードを使用してください:
113
-
114
- ```ts
115
- // src/routes/+layout.ts
116
- export const prerender = true
117
- export const ssr = false
118
- ```
119
-
120
156
  ### コンテナで Android APK をビルドする
121
157
 
122
158
  Hai プロジェクトルートで `pnpm build --target app --platform android --runtime auto --debug` を実行します。`--debug` を省略すると署名付きリリースになります。成功したビルドは `.hai/build/app/android/<variant>/` に格納します。[ネイティブビルドと署名](../../docs/usage/getting-started/build.md#原生和离线条件)を参照してください。
@@ -142,9 +178,21 @@ docker run --rm -it --platform linux/amd64 \
142
178
 
143
179
  依存関係の取得には npm、Gradle の配布元、Google Maven、Maven Central へのアクセスが必要です。リリースにはアプリの署名手順を使用し、キーストアを読み取り専用でマウントして、パスワードをビルド環境から渡します。[mobile-app のビルドと受け入れ確認](../../apps/mobile-app/README.md#原生交付与验收)を参照してください。
144
180
 
145
- ### エラー処理
181
+ ## 設定
182
+
183
+ このモジュールに設定ファイルはありません。`capacitor.init()` は Capacitor の実行環境が利用可能かどうかのみを確認します。
184
+
185
+ ネイティブ WebView はクライアントアプリを読み込みます。SvelteKit は次の静的 SPA 設定を使い、純粋な Svelte/Vite テンプレートではこのルートファイルを使いません:
186
+
187
+ ```ts
188
+ // src/routes/+layout.ts
189
+ export const prerender = true
190
+ export const ssr = false
191
+ ```
192
+
193
+ ## エラー処理
146
194
 
147
- `capacitor.*` と `safe*Preference` は `HaiResult<T>` を返します。TokenStorage のメソッドはプラットフォームや保存エラーで Promise を reject します。
195
+ `init/close`、device/camera/push/statusBar/preferences と `safe*Preference` は `HaiResult<T>`、`getPlatform/isNative/isInitialized` は直接値を返します。TokenStorage のメソッドはプラットフォームや保存エラーで Promise を reject します。
148
196
 
149
197
  ```ts
150
198
  import { capacitor, HaiCapacitorError } from '@h-ai/capacitor'
package/README.md CHANGED
@@ -4,11 +4,73 @@
4
4
 
5
5
  [框架首页](../../README.md) · 相关模块:[@h-ai/api-client](../api-client/README.md) · [@h-ai/core](../core/README.md)
6
6
 
7
- ## 简介
8
-
9
7
  Capacitor 原生桥接模块,为 hai Framework 移动应用提供原生安全 Token 存储、设备信息、推送通知、相机与状态栏等能力的统一封装。
10
8
 
11
- ## 核心功能清单
9
+ ## 快速开始
10
+
11
+ ```ts
12
+ import { capacitor } from '@h-ai/capacitor'
13
+
14
+ const initialized = await capacitor.init()
15
+ if (!initialized.success)
16
+ throw new Error(initialized.error.message)
17
+ const failures: unknown[] = []
18
+ try {
19
+ const saved = await capacitor.preferences.set('theme', 'dark')
20
+ if (!saved.success)
21
+ throw new Error(saved.error.message)
22
+ const theme = await capacitor.preferences.get('theme')
23
+ if (!theme.success)
24
+ throw new Error(theme.error.message)
25
+ // theme.data 为 'dark';尚未保存的键为 null。
26
+ }
27
+ catch (cause) {
28
+ failures.push(cause)
29
+ }
30
+ finally {
31
+ const closed = await capacitor.close()
32
+ if (!closed.success)
33
+ failures.push(closed.error)
34
+ }
35
+ if (failures.length)
36
+ throw new AggregateError(failures, 'Native preference operation failed')
37
+ ```
38
+
39
+ ## 功能
40
+
41
+ ### 用途、输入与输出
42
+
43
+ capacitor 的子功能在初始化成功后使用。HaiResult<T> 先判断 success,再读成功 data;void 没有业务数据,Promise 必须 await。tokens 是 createCapacitorTokenStorage() 返回的独立适配器,其读写/清理在原生存储失败时拒绝 Promise。独立 Preferences 辅助函数不依赖模块状态,把同一插件操作包装为 HaiResult。
44
+
45
+ | 入口 | 使用场景 | 输入(`—` 表示无参数) | 返回值 | 调用示例 |
46
+ | -------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
47
+ | `capacitor.init` | 检测并准备原生宿主 | `—` | `Promise<HaiResult<void>>` | `await capacitor.init()` |
48
+ | `capacitor.close` | 释放推送监听等资源 | `—` | `Promise<HaiResult<void>>` | `await capacitor.close()` |
49
+ | `capacitor.getPlatform` | 选择平台行为 | `—` | `string: ios / android / web` | `capacitor.getPlatform()` |
50
+ | `capacitor.isNative` | 判断是否原生环境 | `—` | `boolean` | `capacitor.isNative()` |
51
+ | `capacitor.isInitialized` | 检查模块状态 | `—` | `boolean` | `capacitor.isInitialized` |
52
+ | `capacitor.device.getInfo` | 显示设备诊断信息 | `—` | `Promise<HaiResult<{ platform, osVersion, model, manufacturer, isVirtual, appVersion?, appBuild? }>>` | `await capacitor.device.getInfo()` |
53
+ | `capacitor.device.getAppVersion` | 显示当前安装版本 | `—` | `Promise<HaiResult<{ version, build }>>` | `await capacitor.device.getAppVersion()` |
54
+ | `capacitor.camera.takePhoto` | 拍照或选择相册图片 | `{ source?: camera/photos/prompt, quality?: 0…100, width?, height?, resultType?: uri/base64/dataUrl }` | `Promise<HaiResult<{ data: string, format: string }>>` | `await capacitor.camera.takePhoto({ source: "photos", resultType: "dataUrl" })` |
55
+ | `capacitor.push.register` | 申请权限并获取推送标识 | `{ signal?: AbortSignal }` | `Promise<HaiResult<{ token: string }>>` | `await capacitor.push.register()` |
56
+ | `capacitor.push.listen` | 接收推送与点击事件 | `{ onReceived?, onActionPerformed? }, { signal? }` | `Promise<HaiResult<() => Promise<HaiResult<void>>>>` | `await capacitor.push.listen(callbacks, { signal })` |
57
+ | `capacitor.statusBar.configure` | 设置状态栏显示 | `{ style?: dark/light/default, backgroundColor?: color, overlay?: boolean }` | `Promise<HaiResult<void>>` | `await capacitor.statusBar.configure({ style: "dark", overlay: true })` |
58
+ | `capacitor.statusBar.show` | 显示状态栏 | `—` | `Promise<HaiResult<void>>` | `await capacitor.statusBar.show()` |
59
+ | `capacitor.statusBar.hide` | 隐藏状态栏 | `—` | `Promise<HaiResult<void>>` | `await capacitor.statusBar.hide()` |
60
+ | `capacitor.preferences.get` | 读取普通偏好 | `key: string` | `Promise<HaiResult<string / null>>` | `await capacitor.preferences.get("theme")` |
61
+ | `capacitor.preferences.set` | 保存普通偏好 | `key: string, value: string` | `Promise<HaiResult<void>>` | `await capacitor.preferences.set("theme", "dark")` |
62
+ | `capacitor.preferences.remove` | 删除普通偏好 | `key: string` | `Promise<HaiResult<void>>` | `await capacitor.preferences.remove("theme")` |
63
+ | `createCapacitorTokenStorage` | 创建原生安全凭据适配器 | `—` | `TokenStorage` | `createCapacitorTokenStorage()` |
64
+ | `tokens.getAccessToken` | 读取已保存的访问令牌 | `—` | `Promise<string / null>` | `await tokens.getAccessToken()` |
65
+ | `tokens.getRefreshToken` | 读取已保存的刷新令牌 | `—` | `Promise<string / null>` | `await tokens.getRefreshToken()` |
66
+ | `tokens.setAccessToken` | 保存访问令牌 | `token: string` | `Promise<void>` | `await tokens.setAccessToken(accessToken)` |
67
+ | `tokens.setRefreshToken` | 保存刷新令牌 | `token: string` | `Promise<void>` | `await tokens.setRefreshToken(refreshToken)` |
68
+ | `tokens.clear` | 删除本机两类凭据 | `—` | `Promise<void>` | `await tokens.clear()` |
69
+ | `safeGetPreference` | 独立读取非敏感偏好 | `key: string` | `Promise<HaiResult<string / null>>` | `await safeGetPreference("theme")` |
70
+ | `safeSetPreference` | 独立保存非敏感偏好 | `key: string, value: string` | `Promise<HaiResult<void>>` | `await safeSetPreference("theme", "dark")` |
71
+ | `safeRemovePreference` | 独立删除非敏感偏好 | `key: string` | `Promise<HaiResult<void>>` | `await safeRemovePreference("theme")` |
72
+
73
+ 照片的 source 选择相机、相册或交互选择器;quality 是 0–100 的质量值,width/height 是像素约束。成功时 data 随 resultType 返回可显示的 webPath、裸 Base64 或带 MIME 前缀的 Data URL,format 是插件返回的图片格式。callbacks 的 onReceived/onActionPerformed 接收推送对象,signal 来自应用创建的 AbortController;成功 listen 的 data 是需要 await 并检查结果的清理函数。独立工厂与 Preferences 辅助函数从 @h-ai/capacitor 根入口导入。
12
74
 
13
75
  - **Token 存储**:`@aparajita/capacitor-secure-storage`(原生必需)。Android 使用 KeyStore + 加密 SharedPreferences,iOS 使用 Keychain;Web 不回退。
14
76
  - **Preferences**:`@capacitor/preferences`(必需)。通用偏好数据存储,适合非敏感配置,不用于认证 Token。
@@ -18,21 +80,7 @@ Capacitor 原生桥接模块,为 hai Framework 移动应用提供原生安全
18
80
  - **相机/相册**:`@capacitor/camera`(可选)。拍照、选取相册图片。
19
81
  - **状态栏**:`@capacitor/status-bar`(可选)。沉浸式、背景色、样式配置。
20
82
 
21
- ## 使用入门
22
-
23
- ### 快速开始
24
-
25
- ```ts
26
- import { capacitor } from '@h-ai/capacitor'
27
-
28
- // 应用启动时初始化(检测 Capacitor 环境)
29
- const result = await capacitor.init()
30
- if (!result.success) {
31
- // 非 Capacitor 环境(纯 Web)
32
- }
33
- ```
34
-
35
- #### 与 api-client 配合的 Token 安全存储
83
+ ### 与 api-client 配合的 Token 安全存储
36
84
 
37
85
  ```ts
38
86
  import { apiClient } from '@h-ai/api-client'
@@ -55,7 +103,7 @@ await apiClient.init({
55
103
 
56
104
  同一模块中的全部 TokenStorage 实例共享原生变更队列。`clear()` 等待更早调用的写入完成再删除,避免迟到写入在清理成功后恢复旧凭据;之后显式调用的写入可保存新凭据。该顺序不跨独立 WebView/JavaScript 运行环境提供进程间协调。
57
105
 
58
- #### 设备信息与推送
106
+ ### 设备信息与推送
59
107
 
60
108
  ```ts
61
109
  import { capacitor } from '@h-ai/capacitor'
@@ -73,7 +121,7 @@ if (reg.success) {
73
121
 
74
122
  推送仅在实际原生平台调用插件。`push.register({ signal? })` 与 `push.listen(callbacks, { signal? })` 的设置阶段限时 30 秒(包含权限和监听器挂载);失败、超时、取消及 `capacitor.close()` 都会停止回调并移除本次拥有的句柄,迟到的句柄在完成后立即移除,不调用影响其他消费者的 removeAllListeners。listen 成功后信号仍有效,也可调用返回的 cleanup。cleanup 与 close 均返回 `HaiResult<void>`;原生 remove 失败返回 `PUSH_CLEANUP_FAILED`(`capacitor:032`),失败句柄保留供再次调用重试,成功移除的句柄不重复操作。模块关闭后立即不可用;重新初始化前先重试遗留清理。自动化验证控制插件时序,不能代替 Android/iOS 真机 FCM/APNs 权限、注册与反复挂载验收。
75
123
 
76
- #### 状态栏
124
+ ### 状态栏
77
125
 
78
126
  ```ts
79
127
  import { capacitor } from '@h-ai/capacitor'
@@ -85,7 +133,7 @@ await capacitor.statusBar.configure({
85
133
  })
86
134
  ```
87
135
 
88
- #### 相机
136
+ ### 相机
89
137
 
90
138
  ```ts
91
139
  const photo = await capacitor.camera.takePhoto({
@@ -95,7 +143,7 @@ const photo = await capacitor.camera.takePhoto({
95
143
  })
96
144
  ```
97
145
 
98
- #### Preferences
146
+ ### Preferences
99
147
 
100
148
  ```ts
101
149
  await capacitor.preferences.set('my_key', 'value')
@@ -105,18 +153,6 @@ await capacitor.preferences.remove('my_key')
105
153
 
106
154
  `capacitor.preferences` 适合保存语言、主题、草稿等普通偏好数据;认证 Token 请使用 `createCapacitorTokenStorage()`。
107
155
 
108
- ### 配置
109
-
110
- 本模块无配置文件。`capacitor.init()` 仅检测 Capacitor 运行环境是否可用。
111
-
112
- Capacitor 应用必须使用 SPA 模式:
113
-
114
- ```ts
115
- // src/routes/+layout.ts
116
- export const prerender = true
117
- export const ssr = false
118
- ```
119
-
120
156
  ### Android 容器打包
121
157
 
122
158
  在 Hai 工程根运行 `pnpm build --target app --platform android --runtime auto --debug`。省略 `--debug` 构建签名发布包,成功后在 `.hai/build/app/android/<构建类型>/` 查看最新批次。签名设置见 [原生和离线条件](../../docs/usage/getting-started/build.md#原生和离线条件)。
@@ -142,9 +178,21 @@ docker run --rm -it --platform linux/amd64 \
142
178
 
143
179
  构建下载依赖时需要访问 npm、Gradle 分发站点、Google Maven 和 Maven Central。发布包沿用应用的签名流程,密钥库从容器外只读挂载,口令由构建环境注入。应用示例见 [mobile-app 原生交付与验收](../../apps/mobile-app/README.md#原生交付与验收)。
144
180
 
145
- ### 错误处理
181
+ ## 配置
182
+
183
+ 本模块无配置文件。`capacitor.init()` 仅检测 Capacitor 运行环境是否可用。
184
+
185
+ 原生 WebView 运行客户端页面。若应用使用 SvelteKit,配置静态 SPA;纯 Svelte/Vite 模板不使用下面的路由文件:
186
+
187
+ ```ts
188
+ // src/routes/+layout.ts
189
+ export const prerender = true
190
+ export const ssr = false
191
+ ```
192
+
193
+ ## 错误处理
146
194
 
147
- `capacitor.*` 业务操作与 `safe*Preference` 返回 `HaiResult<T>`;TokenStorage 适配器方法以 Promise 拒绝报告平台与存储错误:
195
+ `init/close`、device/camera/push/statusBar/preferences 业务操作与 `safe*Preference` 返回 `HaiResult<T>`;`getPlatform/isNative/isInitialized` 返回直接值。TokenStorage 适配器方法以 Promise 拒绝报告平台与存储错误:
148
196
 
149
197
  ```ts
150
198
  import { capacitor, HaiCapacitorError } from '@h-ai/capacitor'
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@h-ai/capacitor",
3
3
  "type": "module",
4
- "version": "1.0.0-beta.19",
4
+ "version": "1.0.0-beta.20",
5
5
  "description": "Hai Framework Capacitor bridge module for native mobile capabilities.",
6
6
  "license": "Apache-2.0",
7
7
  "exports": {
@@ -48,8 +48,8 @@
48
48
  }
49
49
  },
50
50
  "dependencies": {
51
- "@h-ai/api-client": "1.0.0-beta.19",
52
- "@h-ai/core": "1.0.0-beta.19"
51
+ "@h-ai/api-client": "1.0.0-beta.20",
52
+ "@h-ai/core": "1.0.0-beta.20"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@aparajita/capacitor-secure-storage": "^8.0.1",