cj-tauri 2.0.0 → 2.1.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 +113 -99
- package/bin/cj-tauri.js +287 -287
- package/cjpm.toml +63 -52
- package/cli/cjpm.toml +22 -22
- package/cli/src/doctor.cj +308 -306
- package/cli/src/main.cj +129 -129
- package/cli/src/manifest.cj +632 -558
- package/cli/src/manifest_test.cj +87 -0
- package/cli/src/project.cj +770 -770
- package/cli/src/resolve.cj +348 -348
- package/cli/src/scaffold.cj +369 -369
- package/cli/src/sync.cj +526 -526
- package/cli/src/util.cj +168 -168
- package/cli/templates/app/README.md +51 -48
- package/cli/templates/app/assets/capabilities/default.json +7 -7
- package/cli/templates/app/assets/ui/index.html +120 -118
- package/cli/templates/app/cj-tauri.toml +32 -22
- package/cli/templates/app/cjpm.toml +34 -34
- package/cli/templates/app/src/main.cj +101 -90
- package/cli/templates/app-react/README.md +56 -56
- package/cli/templates/app-react/assets/capabilities/default.json +7 -7
- package/cli/templates/app-react/assets/ui/index.html +25 -25
- package/cli/templates/app-react/assets/ui/package.json +19 -19
- package/cli/templates/app-react/assets/ui/src/App.css +67 -67
- package/cli/templates/app-react/assets/ui/src/App.jsx +124 -124
- package/cli/templates/app-react/assets/ui/src/main.jsx +6 -6
- package/cli/templates/app-react/assets/ui/vite.config.js +24 -24
- package/cli/templates/app-react/cj-tauri.toml +33 -23
- package/cli/templates/app-react/cjpm.toml +34 -34
- package/cli/templates/app-react/src/main.cj +91 -91
- package/cli/templates/app-vue/README.md +56 -56
- package/cli/templates/app-vue/assets/capabilities/default.json +7 -7
- package/cli/templates/app-vue/assets/ui/index.html +25 -25
- package/cli/templates/app-vue/assets/ui/package.json +18 -18
- package/cli/templates/app-vue/assets/ui/src/App.vue +176 -176
- package/cli/templates/app-vue/assets/ui/src/main.js +4 -4
- package/cli/templates/app-vue/assets/ui/vite.config.js +24 -24
- package/cli/templates/app-vue/cj-tauri.toml +33 -23
- package/cli/templates/app-vue/cjpm.toml +34 -34
- package/cli/templates/app-vue/src/main.cj +91 -91
- package/cli/templates/ohos-skeleton/AppScope/app.json5 +13 -13
- package/cli/templates/ohos-skeleton/AppScope/resources/base/element/string.json +8 -8
- package/cli/templates/ohos-skeleton/AppScope/resources/base/media/layered_image.json +6 -6
- package/cli/templates/ohos-skeleton/README.md +84 -79
- package/cli/templates/ohos-skeleton/build-hap.sh +15 -0
- package/cli/templates/ohos-skeleton/build-profile.json5 +46 -46
- package/cli/templates/ohos-skeleton/entry/build-profile.json5 +26 -26
- package/cli/templates/ohos-skeleton/entry/cjpm.toml +51 -43
- package/cli/templates/ohos-skeleton/entry/hvigorfile.ts +6 -6
- package/cli/templates/ohos-skeleton/entry/oh-package.json5 +9 -9
- package/cli/templates/ohos-skeleton/entry/src/main/cangjie/ability_stage.cj +17 -17
- package/cli/templates/ohos-skeleton/entry/src/main/cangjie/app_host.cj +94 -94
- package/cli/templates/ohos-skeleton/entry/src/main/cangjie/dialog_host.cj +217 -0
- package/cli/templates/ohos-skeleton/entry/src/main/cangjie/index.cj +527 -167
- package/cli/templates/ohos-skeleton/entry/src/main/cangjie/main_ability.cj +139 -139
- package/cli/templates/ohos-skeleton/entry/src/main/module.json5 +57 -49
- package/cli/templates/ohos-skeleton/entry/src/main/resources/base/element/color.json +8 -8
- package/cli/templates/ohos-skeleton/entry/src/main/resources/base/element/string.json +16 -16
- package/cli/templates/ohos-skeleton/entry/src/main/resources/base/media/layered_image.json +6 -6
- package/cli/templates/ohos-skeleton/entry/src/main/resources/base/profile/main_pages.json +2 -2
- package/cli/templates/ohos-skeleton/entry/src/main/resources/rawfile/capabilities.json +6 -6
- package/cli/templates/ohos-skeleton/entry/src/main/resources/rawfile/index.html +92 -92
- package/cli/templates/ohos-skeleton/hvigor/hvigor-config.json5 +5 -5
- package/cli/templates/ohos-skeleton/hvigorfile.ts +6 -6
- package/cli/templates/ohos-skeleton/oh-package.json5 +10 -10
- package/native/build_win.bat +62 -62
- package/native/core/bridge_core.c +1681 -1626
- package/native/core/bridge_core.h +675 -618
- package/native/core/bridge_js.h +108 -108
- package/native/platforms/harmonyos/README.md +115 -6
- package/native/platforms/linux/bridge_linux.c +2787 -2485
- package/native/platforms/windows/bridge_win.c +3740 -3248
- package/native/tests/gtk_threading_probe.c +143 -143
- package/native/tests/test_bridge_core.c +1339 -1228
- package/package.json +53 -53
- package/prebuilt/linux-x64/cj-tauri +0 -0
- package/src/api_system.cj +67 -67
- package/src/app.cj +325 -969
- package/src/app_events.cj +166 -0
- package/src/app_host_ops.cj +287 -0
- package/src/app_run.cj +283 -0
- package/src/app_spec.cj +76 -76
- package/src/arkweb_menu.cj +216 -0
- package/src/arkweb_script.cj +142 -142
- package/src/capability.cj +409 -409
- package/src/clipboard_bridge.cj +178 -0
- package/src/dialog_spec.cj +79 -0
- package/src/dragdrop.cj +26 -26
- package/src/embedded_assets.cj +98 -98
- package/src/host.cj +752 -607
- package/src/host_arkweb.cj +924 -778
- package/src/host_webkit.cj +663 -570
- package/src/host_webview2.cj +663 -570
- package/src/hotkey.cj +66 -66
- package/src/ipc_hub.cj +337 -337
- package/src/ipc_message.cj +286 -286
- package/src/launch.cj +62 -62
- package/src/logging.cj +127 -127
- package/src/menu.cj +197 -197
- package/src/platform/platform_app_context.cj +77 -77
- package/src/platform/platform_assets.cj +33 -33
- package/src/platform/platform_discover.cj +176 -176
- package/src/platform/platform_env.cj +29 -29
- package/src/platform/platform_feature.cj +31 -31
- package/src/platform/platform_page_source.cj +87 -87
- package/src/platform/platform_target_info.cj +32 -32
- package/src/platform_host_provider.cj +87 -87
- package/src/plugin.cj +333 -333
- package/src/plugins/clipboard/plugin_clipboard.cj +152 -152
- package/src/plugins/dialog/plugin_dialog.cj +209 -209
- package/src/plugins/fs/plugin_fs.cj +105 -1
- package/src/plugins/http/http_backend.cj +131 -0
- package/src/plugins/http/http_desktop.cj +195 -0
- package/src/plugins/http/http_ohos.cj +204 -0
- package/src/plugins/http/plugin_http.cj +310 -459
- package/src/plugins/log/plugin_log.cj +105 -105
- package/src/plugins/menu/plugin_menu.cj +158 -158
- package/src/plugins/notification/plugin_notification.cj +154 -154
- package/src/plugins/serial/plugin_serial.cj +458 -454
- package/src/plugins/serial/serial_bridge.cj +194 -194
- package/src/plugins/serial/serial_manager_ohos.cj +92 -0
- package/src/plugins/serial/serial_ohos.cj +529 -0
- package/src/plugins/shell/plugin_shell.cj +258 -258
- package/src/plugins/sqlite/plugin_sqlite.cj +705 -710
- package/src/plugins/sqlite/sqlite_ffi.cj +206 -211
- package/src/plugins/ws/plugin_ws.cj +488 -470
- package/src/process_hidden.cj +174 -174
- package/src/scope.cj +391 -391
- package/src/shell_event.cj +69 -69
- package/src/tests/app_spec_test.cj +126 -127
- package/src/tests/capability_test.cj +243 -243
- package/src/tests/dialog_spec_test.cj +73 -0
- package/src/tests/fake_host.cj +201 -201
- package/src/tests/ipc_hub_test.cj +487 -487
- package/src/tests/logging_test.cj +62 -62
- package/src/tests/platform_contract_test.cj +251 -251
- package/src/tests/plugin_clipboard_test.cj +222 -222
- package/src/tests/plugin_dialog_test.cj +237 -237
- package/src/tests/plugin_fs_test.cj +207 -0
- package/src/tests/plugin_http_test.cj +124 -124
- package/src/tests/plugin_notification_test.cj +205 -205
- package/src/tests/plugin_serial_test.cj +48 -0
- package/src/tests/plugin_test.cj +605 -585
- package/src/tests/plugin_ws_test.cj +40 -40
- package/src/tests/process_hidden_test.cj +129 -129
- package/src/tests/scope_test.cj +350 -350
- package/src/tests/system_host_test.cj +99 -81
- package/src/tests/urlutil_test.cj +53 -53
- package/src/tests/version_test.cj +75 -75
- package/src/tests/window_registry_test.cj +123 -123
- package/src/tray.cj +90 -90
- package/src/urlutil.cj +159 -159
- package/src/version.cj +44 -44
- package/src/window.cj +51 -51
- package/src/window_registry.cj +116 -116
- package/prebuilt/win32-x64/cj-tauri.exe +0 -0
- package/src/plugins/serial/serial_ohos_stub.cj +0 -61
- package/src/plugins/sqlite/sqlite_ohos_stub.cj +0 -91
package/src/clipboard_bridge.cj
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
package cjTauri
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* 鸿蒙侧 pasteboard 的唯一依赖:`LibC.mallocCString` / `malloc` / `free`
|
|
5
|
+
*
|
|
6
|
+
* 加 `@When` 门禁是必须的——桌面两平台走 C 桥(下面那段 `cj_bridge_clipboard_*`),
|
|
7
|
+
* 用不到 LibC;不门禁就会在桌面构建里变成一条 `unused import` 警告(AGENTS §3 零警告)。
|
|
8
|
+
*/
|
|
9
|
+
@When[env == "ohos"]
|
|
10
|
+
import std.posix.*
|
|
11
|
+
|
|
3
12
|
|
|
4
13
|
/**
|
|
5
14
|
* 剪贴板 / 通知桥(plugin_clipboard、plugin_notification 的 FFI 面):
|
|
@@ -53,3 +62,172 @@ foreign func cj_bridge_clipboard_free(s: CString): Unit
|
|
|
53
62
|
@When[env != "ohos"]
|
|
54
63
|
@C
|
|
55
64
|
foreign func cj_bridge_notification_notify(h: CPointer<Unit>, title: CString, body: CString): Int32
|
|
65
|
+
|
|
66
|
+
/* ==========================================================================
|
|
67
|
+
* 鸿蒙侧剪贴板:直接 FFI 到原生 pasteboard(`libpasteboard.so`)
|
|
68
|
+
*
|
|
69
|
+
* ## 为什么不是 `ohos.pasteboard`
|
|
70
|
+
*
|
|
71
|
+
* 仓颉套件里**没有**这个包。查过两套 SDK 的包清单(`api/lib/linux_ohos_aarch64_cjnative/`):
|
|
72
|
+
* 6.1(apiVersion 24,`build-hap.sh` 默认选它的那套)的 340 个 ohos 包里没有 pasteboard,
|
|
73
|
+
* `kit/` 下也没有再导出;只有旧的 5.0(apiVersion 15,Beta2)带 `ohos.pasteboard.cjo`。
|
|
74
|
+
* 于是在设备上能用的只有原生 C API(`native/sysroot/usr/include/database/pasteboard/`,
|
|
75
|
+
* 同一 sysroot 里就有 `libpasteboard.so`,`entry/cjpm.toml` 的 `-L` 已指着它)。
|
|
76
|
+
*
|
|
77
|
+
* ## 为什么这不算「破坏宿主能力位如实约定」
|
|
78
|
+
*
|
|
79
|
+
* 平台差异只落在 `@When[env == "ohos"]` 这一处(AGENTS §2 允许的第二个落点就是条件编译),
|
|
80
|
+
* 桌面两平台仍走 C 桥同名导出,上层(`WebViewHost.clipboardWriteText/ReadText`)一行都不用分叉。
|
|
81
|
+
*
|
|
82
|
+
* ## 权限前提(判据在设备上,不在代码里)
|
|
83
|
+
*
|
|
84
|
+
* 写(SetData)不需要权限;**读(GetData)要 `ohos.permission.READ_PASTEBOARD`**
|
|
85
|
+
* (`udmf_datashare_config.json` 里是 user_grant + system_basic)。普通签名的应用拿不到该权限时,
|
|
86
|
+
* GetData 不抛异常、只回空数据 / 非 0 状态——所以读路径**只能靠真机实测**判定通没通,
|
|
87
|
+
* 代码里不许假设它「应该能读」。`arkwebClipboardReadText` 因此对「空 / 被拒 / 非文本」一律回 None。
|
|
88
|
+
* ========================================================================== */
|
|
89
|
+
|
|
90
|
+
/** 取本进程的粘贴板句柄(失败回空指针) */
|
|
91
|
+
@When[env == "ohos"]
|
|
92
|
+
@C
|
|
93
|
+
foreign func OH_Pasteboard_Create(): CPointer<Unit>
|
|
94
|
+
|
|
95
|
+
@When[env == "ohos"]
|
|
96
|
+
@C
|
|
97
|
+
foreign func OH_Pasteboard_Destroy(pasteboard: CPointer<Unit>): Unit
|
|
98
|
+
|
|
99
|
+
/** 0 = 成功;非 0 = 平台拒绝(状态码见 `oh_pasteboard_err_code.h`) */
|
|
100
|
+
@When[env == "ohos"]
|
|
101
|
+
@C
|
|
102
|
+
foreign func OH_Pasteboard_SetData(pasteboard: CPointer<Unit>, data: CPointer<Unit>): Int32
|
|
103
|
+
|
|
104
|
+
/** 读:`status` 是出参(`Pasteboard_Status` 的 0 是 E_OK);返回的 UdmfData 由调用方 Destroy */
|
|
105
|
+
@When[env == "ohos"]
|
|
106
|
+
@C
|
|
107
|
+
foreign func OH_Pasteboard_GetData(pasteboard: CPointer<Unit>, status: CPointer<Int32>): CPointer<Unit>
|
|
108
|
+
|
|
109
|
+
@When[env == "ohos"]
|
|
110
|
+
@C
|
|
111
|
+
foreign func OH_UdmfData_Create(): CPointer<Unit>
|
|
112
|
+
|
|
113
|
+
@When[env == "ohos"]
|
|
114
|
+
@C
|
|
115
|
+
foreign func OH_UdmfData_Destroy(pThis: CPointer<Unit>): Unit
|
|
116
|
+
|
|
117
|
+
@When[env == "ohos"]
|
|
118
|
+
@C
|
|
119
|
+
foreign func OH_UdmfData_AddRecord(pThis: CPointer<Unit>, record: CPointer<Unit>): Int32
|
|
120
|
+
|
|
121
|
+
/** 取「主纯文本」(不必自己遍历 records);没有纯文本时回非 0 */
|
|
122
|
+
@When[env == "ohos"]
|
|
123
|
+
@C
|
|
124
|
+
foreign func OH_UdmfData_GetPrimaryPlainText(data: CPointer<Unit>, plainText: CPointer<Unit>): Int32
|
|
125
|
+
|
|
126
|
+
@When[env == "ohos"]
|
|
127
|
+
@C
|
|
128
|
+
foreign func OH_UdmfRecord_Create(): CPointer<Unit>
|
|
129
|
+
|
|
130
|
+
@When[env == "ohos"]
|
|
131
|
+
@C
|
|
132
|
+
foreign func OH_UdmfRecord_Destroy(pThis: CPointer<Unit>): Unit
|
|
133
|
+
|
|
134
|
+
@When[env == "ohos"]
|
|
135
|
+
@C
|
|
136
|
+
foreign func OH_UdmfRecord_AddPlainText(pThis: CPointer<Unit>, plainText: CPointer<Unit>): Int32
|
|
137
|
+
|
|
138
|
+
@When[env == "ohos"]
|
|
139
|
+
@C
|
|
140
|
+
foreign func OH_UdsPlainText_Create(): CPointer<Unit>
|
|
141
|
+
|
|
142
|
+
@When[env == "ohos"]
|
|
143
|
+
@C
|
|
144
|
+
foreign func OH_UdsPlainText_Destroy(pThis: CPointer<Unit>): Unit
|
|
145
|
+
|
|
146
|
+
@When[env == "ohos"]
|
|
147
|
+
@C
|
|
148
|
+
foreign func OH_UdsPlainText_SetContent(pThis: CPointer<Unit>, content: CString): Int32
|
|
149
|
+
|
|
150
|
+
/** 回的是库内自有缓冲(**不要** free),并发的另一次读会让它失效——取到就立刻拷成 String */
|
|
151
|
+
@When[env == "ohos"]
|
|
152
|
+
@C
|
|
153
|
+
foreign func OH_UdsPlainText_GetContent(pThis: CPointer<Unit>): CString
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* 写文本进系统剪贴板(鸿蒙侧)。true = 平台接受了这次写入。
|
|
157
|
+
*
|
|
158
|
+
* 收尾是**显式**的:本机仓颉没有 `defer`(实测 `error: undeclared identifier 'defer'`),
|
|
159
|
+
* 每个出口都要自己 Destroy,漏一个就是一处泄漏。
|
|
160
|
+
*/
|
|
161
|
+
@When[env == "ohos"]
|
|
162
|
+
public func arkwebClipboardWriteText(text: String): Bool {
|
|
163
|
+
let pb = unsafe { OH_Pasteboard_Create() }
|
|
164
|
+
if (unsafe { pb.isNull() }) {
|
|
165
|
+
return false
|
|
166
|
+
}
|
|
167
|
+
let data = unsafe { OH_UdmfData_Create() }
|
|
168
|
+
let record = unsafe { OH_UdmfRecord_Create() }
|
|
169
|
+
let plain = unsafe { OH_UdsPlainText_Create() }
|
|
170
|
+
if (unsafe { data.isNull() } || unsafe { record.isNull() } || unsafe { plain.isNull() }) {
|
|
171
|
+
unsafe { OH_UdsPlainText_Destroy(plain) }
|
|
172
|
+
unsafe { OH_UdmfRecord_Destroy(record) }
|
|
173
|
+
unsafe { OH_UdmfData_Destroy(data) }
|
|
174
|
+
unsafe { OH_Pasteboard_Destroy(pb) }
|
|
175
|
+
return false
|
|
176
|
+
}
|
|
177
|
+
let content = unsafe { LibC.mallocCString(text) }
|
|
178
|
+
var ok = false
|
|
179
|
+
if (unsafe { OH_UdsPlainText_SetContent(plain, content) } == 0) {
|
|
180
|
+
if (unsafe { OH_UdmfRecord_AddPlainText(record, plain) } == 0) {
|
|
181
|
+
if (unsafe { OH_UdmfData_AddRecord(data, record) } == 0) {
|
|
182
|
+
ok = unsafe { OH_Pasteboard_SetData(pb, data) } == 0
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
unsafe { LibC.free(content) }
|
|
187
|
+
unsafe { OH_UdsPlainText_Destroy(plain) }
|
|
188
|
+
unsafe { OH_UdmfRecord_Destroy(record) }
|
|
189
|
+
unsafe { OH_UdmfData_Destroy(data) }
|
|
190
|
+
unsafe { OH_Pasteboard_Destroy(pb) }
|
|
191
|
+
return ok
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* 读系统剪贴板文本(鸿蒙侧):None = 空 / 非文本 / 平台拒绝(含缺 READ_PASTEBOARD 权限)。
|
|
196
|
+
*
|
|
197
|
+
* 三种 None 在页面侧看起来一样,**这是有意的**:WebViewHost 的契约就是 Option,
|
|
198
|
+
* 平台没给出文本与平台拒绝了读取,对调用方是同一个「没拿到」。要区分得看 hilog 里的
|
|
199
|
+
* `[cj-bridge] pasteboard read status=` 行(由应用侧 `probeLog` 打,框架侧 eprintln 在设备上不可见)。
|
|
200
|
+
*/
|
|
201
|
+
@When[env == "ohos"]
|
|
202
|
+
public func arkwebClipboardReadText(): Option<String> {
|
|
203
|
+
let pb = unsafe { OH_Pasteboard_Create() }
|
|
204
|
+
if (unsafe { pb.isNull() }) {
|
|
205
|
+
return None
|
|
206
|
+
}
|
|
207
|
+
let statusBox = unsafe { LibC.malloc<Int32>(count: 1) }
|
|
208
|
+
if (unsafe { statusBox.isNull() }) {
|
|
209
|
+
unsafe { OH_Pasteboard_Destroy(pb) }
|
|
210
|
+
return None
|
|
211
|
+
}
|
|
212
|
+
let statusPtr = unsafe { CPointer<Int32>(statusBox) }
|
|
213
|
+
unsafe { statusPtr.write(0) }
|
|
214
|
+
let data = unsafe { OH_Pasteboard_GetData(pb, statusPtr) }
|
|
215
|
+
var out: Option<String> = None
|
|
216
|
+
if (!unsafe { data.isNull() }) {
|
|
217
|
+
let plain = unsafe { OH_UdsPlainText_Create() }
|
|
218
|
+
if (!unsafe { plain.isNull() }) {
|
|
219
|
+
if (unsafe { OH_UdmfData_GetPrimaryPlainText(data, plain) } == 0) {
|
|
220
|
+
let cstr = unsafe { OH_UdsPlainText_GetContent(plain) }
|
|
221
|
+
if (!unsafe { cstr.isNull() }) {
|
|
222
|
+
let value = unsafe { cstr.toString() }
|
|
223
|
+
out = Some(value)
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
unsafe { OH_UdsPlainText_Destroy(plain) }
|
|
227
|
+
}
|
|
228
|
+
unsafe { OH_UdmfData_Destroy(data) }
|
|
229
|
+
}
|
|
230
|
+
unsafe { LibC.free(statusBox) }
|
|
231
|
+
unsafe { OH_Pasteboard_Destroy(pb) }
|
|
232
|
+
return out
|
|
233
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
package cjTauri
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 消息框的「形状」:由 kind 归一而来,呈现层只认这三态
|
|
5
|
+
*
|
|
6
|
+
* ## 为什么单独抽一层
|
|
7
|
+
*
|
|
8
|
+
* `kind` 是页面可控的字符串(`dialog:message` 的入参),而「单键还是双键」直接决定呈现层的
|
|
9
|
+
* 按钮布局与回填语义。桌面两平台的原生对话框与鸿蒙的应用侧 overlay 必须给出**同一个**判定,
|
|
10
|
+
* 否则同一个 kind 在两处表现不同。原先这段判定写在 `host_arkweb.cj` 里,而那个文件带
|
|
11
|
+
* `@When[env == "ohos"]` 门禁——桌面上根本无法编译,也就没有单测覆盖。
|
|
12
|
+
*
|
|
13
|
+
* 这里只放「语义」,不放任何呈现:按钮文案、配色、布局一律由应用侧决定(框架不猜文案)。
|
|
14
|
+
*/
|
|
15
|
+
public enum DialogShape {
|
|
16
|
+
/**
|
|
17
|
+
* 单键(确定):弹出即成立,回填恒为 true
|
|
18
|
+
*
|
|
19
|
+
* `info` / `warning` / `error` 都归这里——它们的区别只体现在呈现的图标与配色,
|
|
20
|
+
* 语义上没有第二个选择。
|
|
21
|
+
*/
|
|
22
|
+
| Message
|
|
23
|
+
|
|
24
|
+
/** 双键(确定 / 取消):取消回填 false */
|
|
25
|
+
| Confirm
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 带文本输入:输入内容随回填一起交回
|
|
29
|
+
*
|
|
30
|
+
* 当前没有命令产生这个形状(桌面原生对话框没有 prompt 等价物,框架不造平台分叉的 API),
|
|
31
|
+
* 先把它留在协议里:宿主与呈现层按形状分派,将来开放时不必再改一次接口形状。
|
|
32
|
+
*/
|
|
33
|
+
| Prompt
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** 认得的 kind;其余一律按 info 处理(页面写错一个字母不该让对话框不弹) */
|
|
37
|
+
let DIALOG_KINDS: Array<String> = ["info", "warning", "error", "confirm", "prompt"]
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* kind 归一:去首尾空白、转小写,认不出的回落 `info`
|
|
41
|
+
*
|
|
42
|
+
* 回落而不是报错是有意的:`kind` 只影响呈现,写错了还让命令失败等于把「外观问题」升级成
|
|
43
|
+
* 「功能不可用」。归一的收益是**下游只可能见到这五个词之一**,不用各自再判一次。
|
|
44
|
+
*/
|
|
45
|
+
public func normalizeDialogKind(kind: String): String {
|
|
46
|
+
let trimmed = kind.trimAscii()
|
|
47
|
+
if (trimmed.size == 0) {
|
|
48
|
+
return "info"
|
|
49
|
+
}
|
|
50
|
+
let lowered = trimmed.toAsciiLower()
|
|
51
|
+
for (candidate in DIALOG_KINDS) {
|
|
52
|
+
if (candidate == lowered) {
|
|
53
|
+
return candidate
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return "info"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* kind → 形状(内部先归一,所以入参可以是任意字符串)
|
|
61
|
+
*
|
|
62
|
+
* 呈现层据此决定按钮个数与是否需要输入框;宿主据此决定回填值是布尔还是「布尔 + 文本」。
|
|
63
|
+
*/
|
|
64
|
+
public func dialogShapeOf(kind: String): DialogShape {
|
|
65
|
+
match (normalizeDialogKind(kind)) {
|
|
66
|
+
case "confirm" => return DialogShape.Confirm
|
|
67
|
+
case "prompt" => return DialogShape.Prompt
|
|
68
|
+
case _ => return DialogShape.Message
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** 形状是否要「确定 / 取消」两键(`Prompt` 也要两键:输入完要么交回、要么放弃) */
|
|
73
|
+
public func dialogShapeIsTwoKey(shape: DialogShape): Bool {
|
|
74
|
+
match (shape) {
|
|
75
|
+
case DialogShape.Confirm => return true
|
|
76
|
+
case DialogShape.Prompt => return true
|
|
77
|
+
case DialogShape.Message => return false
|
|
78
|
+
}
|
|
79
|
+
}
|
package/src/dragdrop.cj
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
package cjTauri
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* 拖放策略(RFC-002 §5 的 v1 落地):框架只负责「把拖进来的文件路径交出去」,
|
|
5
|
-
* 动作由页面决定(监听 `dragdrop:files` 事件,事件需在能力清单 events 里声明)。
|
|
6
|
-
*
|
|
7
|
-
* 策略必须在 `start()` / `startUrl()` 之前通过 `TauriApp.setDragDrop(...)` 定稿——
|
|
8
|
-
* Linux 侧要在建 view 时决定挂不挂 drag dest;不设置 = 不注册(默认关,现有应用零改动)。
|
|
9
|
-
*/
|
|
10
|
-
public class DragDropPolicy {
|
|
11
|
-
/** 关掉则平台层不注册 drop target(默认关) */
|
|
12
|
-
public let enabled: Bool
|
|
13
|
-
|
|
14
|
-
/** 接受文件路径(v1 唯一载荷;text 载荷留给后续版本,先不设开关) */
|
|
15
|
-
public let files: Bool
|
|
16
|
-
|
|
17
|
-
public init(enabled: Bool, files: Bool) {
|
|
18
|
-
this.enabled = enabled
|
|
19
|
-
this.files = files
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/** 便捷构造:开文件拖入(v1 最常用形态) */
|
|
23
|
-
public static func filesEnabled(): DragDropPolicy {
|
|
24
|
-
return DragDropPolicy(true, true)
|
|
25
|
-
}
|
|
26
|
-
}
|
|
1
|
+
package cjTauri
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 拖放策略(RFC-002 §5 的 v1 落地):框架只负责「把拖进来的文件路径交出去」,
|
|
5
|
+
* 动作由页面决定(监听 `dragdrop:files` 事件,事件需在能力清单 events 里声明)。
|
|
6
|
+
*
|
|
7
|
+
* 策略必须在 `start()` / `startUrl()` 之前通过 `TauriApp.setDragDrop(...)` 定稿——
|
|
8
|
+
* Linux 侧要在建 view 时决定挂不挂 drag dest;不设置 = 不注册(默认关,现有应用零改动)。
|
|
9
|
+
*/
|
|
10
|
+
public class DragDropPolicy {
|
|
11
|
+
/** 关掉则平台层不注册 drop target(默认关) */
|
|
12
|
+
public let enabled: Bool
|
|
13
|
+
|
|
14
|
+
/** 接受文件路径(v1 唯一载荷;text 载荷留给后续版本,先不设开关) */
|
|
15
|
+
public let files: Bool
|
|
16
|
+
|
|
17
|
+
public init(enabled: Bool, files: Bool) {
|
|
18
|
+
this.enabled = enabled
|
|
19
|
+
this.files = files
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** 便捷构造:开文件拖入(v1 最常用形态) */
|
|
23
|
+
public static func filesEnabled(): DragDropPolicy {
|
|
24
|
+
return DragDropPolicy(true, true)
|
|
25
|
+
}
|
|
26
|
+
}
|
package/src/embedded_assets.cj
CHANGED
|
@@ -1,98 +1,98 @@
|
|
|
1
|
-
package cjTauri
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* 内嵌资源释放(单文件包专用)。
|
|
5
|
-
*
|
|
6
|
-
* 背景:应用产物可以打成**单个 exe**(`scripts/pack-win-single.sh`),页面 / 能力清单 / vendor JS
|
|
7
|
-
* 都编成字符串,但**随包的外部程序**(例如 cjnote 的 cjh 后端)没法静态链接进 exe,只能作为 PE
|
|
8
|
-
* 资源(RT_RCDATA)跟着走;运行期由本函数取出写盘,应用再按得到的路径去起它。
|
|
9
|
-
*
|
|
10
|
-
* `dir` 由调用方给(框架不认识应用名),典型是 `%LOCALAPPDATA%\<应用名>\runtime`;
|
|
11
|
-
* **调用方负责先把目录建好**(桥只建最后一级)。
|
|
12
|
-
*
|
|
13
|
-
* 返回值:> 0 = 就绪的文件数(本次释放的 + 本来就在的);0 = 这个产物里没有内嵌资源
|
|
14
|
-
* (普通构建就是这样,**不是错误**);-1 = 参数为空或写盘失败(原因在 stderr)。
|
|
15
|
-
* 幂等:目标已在且大小与资源一致时桥会跳过,所以每次启动都可以调。
|
|
16
|
-
*/
|
|
17
|
-
public func extractEmbeddedAssets(dir: String): Int64 {
|
|
18
|
-
if (dir.isEmpty()) {
|
|
19
|
-
eprintln("[cj-tauri] extractEmbeddedAssets: 目录为空")
|
|
20
|
-
return -1
|
|
21
|
-
}
|
|
22
|
-
let n = extractAssetsBridge(dir)
|
|
23
|
-
if (n < 0) {
|
|
24
|
-
eprintln("[cj-tauri] 释放内嵌资源失败:${dir}")
|
|
25
|
-
}
|
|
26
|
-
return n
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* 鸿蒙侧没有 C 桥产物(`native/platforms/harmonyos/` 目前只有契约),照桌面那份写声明会让模块
|
|
31
|
-
* 加载期就 SIGSEGV(与 `log_bridge.cj` / `process_hidden.cj` 同一条坑,AGENTS §4)——按 `env` 分叉,
|
|
32
|
-
* 如实降级。判据用 `env` 而不是 `arch`:桌面 aarch64 Linux 也有 C 桥。
|
|
33
|
-
*/
|
|
34
|
-
@When[env != "ohos"]
|
|
35
|
-
@C
|
|
36
|
-
foreign func cj_bridge_extract_assets(dir: CString): Int32
|
|
37
|
-
|
|
38
|
-
@When[env != "ohos"]
|
|
39
|
-
func extractAssetsBridge(dir: String): Int64 {
|
|
40
|
-
var n: Int32 = 0
|
|
41
|
-
unsafe {
|
|
42
|
-
n = cj_bridge_extract_assets(LibC.mallocCString(dir))
|
|
43
|
-
}
|
|
44
|
-
return Int64(n)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
@When[env == "ohos"]
|
|
48
|
-
func extractAssetsBridge(dir: String): Int64 {
|
|
49
|
-
let _ = dir
|
|
50
|
-
eprintln("[cj-tauri] 本平台没有 C 桥,无内嵌资源可释放")
|
|
51
|
-
return 0
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* 按**绝对路径**预加载一个随包释放出来的动态库(单文件包专用)。
|
|
56
|
-
*
|
|
57
|
-
* 为什么需要它(2026-10-21 实测,另一台机器):仓颉运行时的随机数默认实现走 OpenSSL,而它按
|
|
58
|
-
* **裸名**找 `libcrypto-3-x64.dll` / `libssl-3-x64.dll`——SDK 与 stdx 都不带这两个,开发机上只是
|
|
59
|
-
* 恰好命中 PATH 里 Git 自带的那份。于是同一条 `ws://` 连接线,本机全通、别人双击就挂:
|
|
60
|
-
* `ws: connect failed: Can not load openssl library or function RAND_bytes.`
|
|
61
|
-
* (RFC6455 升级要算 `Sec-WebSocket-Key` 的随机 nonce,**明文 ws 也逃不掉**)。
|
|
62
|
-
*
|
|
63
|
-
* 只要进程内先按绝对路径加载一次,之后同类裸名加载就命中已加载模块:不必改 PATH,
|
|
64
|
-
* 也不必把 DLL 摆到 exe 旁边(单文件承诺不破)。
|
|
65
|
-
*
|
|
66
|
-
* `path` 必须是释放后的真实路径;返回 true = 已在进程内(含本来就在的)。
|
|
67
|
-
* 平台没有 C 桥时如实返回 false(`src/log_bridge.cj` 同款门禁)。
|
|
68
|
-
*/
|
|
69
|
-
public func preloadEmbeddedLibrary(path: String): Bool {
|
|
70
|
-
if (path.isEmpty()) {
|
|
71
|
-
eprintln("[cj-tauri] preloadEmbeddedLibrary: 路径为空")
|
|
72
|
-
return false
|
|
73
|
-
}
|
|
74
|
-
let ok = preloadLibraryBridge(path)
|
|
75
|
-
if (!ok) {
|
|
76
|
-
eprintln("[cj-tauri] 预加载动态库失败:${path}")
|
|
77
|
-
}
|
|
78
|
-
return ok
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
@When[env != "ohos"]
|
|
82
|
-
@C
|
|
83
|
-
foreign func cj_bridge_preload_library(path: CString): Int32
|
|
84
|
-
|
|
85
|
-
@When[env != "ohos"]
|
|
86
|
-
func preloadLibraryBridge(path: String): Bool {
|
|
87
|
-
var ok: Int32 = 0
|
|
88
|
-
unsafe {
|
|
89
|
-
ok = cj_bridge_preload_library(LibC.mallocCString(path))
|
|
90
|
-
}
|
|
91
|
-
return ok == 1
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
@When[env == "ohos"]
|
|
95
|
-
func preloadLibraryBridge(path: String): Bool {
|
|
96
|
-
let _ = path
|
|
97
|
-
return false
|
|
98
|
-
}
|
|
1
|
+
package cjTauri
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 内嵌资源释放(单文件包专用)。
|
|
5
|
+
*
|
|
6
|
+
* 背景:应用产物可以打成**单个 exe**(`scripts/pack-win-single.sh`),页面 / 能力清单 / vendor JS
|
|
7
|
+
* 都编成字符串,但**随包的外部程序**(例如 cjnote 的 cjh 后端)没法静态链接进 exe,只能作为 PE
|
|
8
|
+
* 资源(RT_RCDATA)跟着走;运行期由本函数取出写盘,应用再按得到的路径去起它。
|
|
9
|
+
*
|
|
10
|
+
* `dir` 由调用方给(框架不认识应用名),典型是 `%LOCALAPPDATA%\<应用名>\runtime`;
|
|
11
|
+
* **调用方负责先把目录建好**(桥只建最后一级)。
|
|
12
|
+
*
|
|
13
|
+
* 返回值:> 0 = 就绪的文件数(本次释放的 + 本来就在的);0 = 这个产物里没有内嵌资源
|
|
14
|
+
* (普通构建就是这样,**不是错误**);-1 = 参数为空或写盘失败(原因在 stderr)。
|
|
15
|
+
* 幂等:目标已在且大小与资源一致时桥会跳过,所以每次启动都可以调。
|
|
16
|
+
*/
|
|
17
|
+
public func extractEmbeddedAssets(dir: String): Int64 {
|
|
18
|
+
if (dir.isEmpty()) {
|
|
19
|
+
eprintln("[cj-tauri] extractEmbeddedAssets: 目录为空")
|
|
20
|
+
return -1
|
|
21
|
+
}
|
|
22
|
+
let n = extractAssetsBridge(dir)
|
|
23
|
+
if (n < 0) {
|
|
24
|
+
eprintln("[cj-tauri] 释放内嵌资源失败:${dir}")
|
|
25
|
+
}
|
|
26
|
+
return n
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 鸿蒙侧没有 C 桥产物(`native/platforms/harmonyos/` 目前只有契约),照桌面那份写声明会让模块
|
|
31
|
+
* 加载期就 SIGSEGV(与 `log_bridge.cj` / `process_hidden.cj` 同一条坑,AGENTS §4)——按 `env` 分叉,
|
|
32
|
+
* 如实降级。判据用 `env` 而不是 `arch`:桌面 aarch64 Linux 也有 C 桥。
|
|
33
|
+
*/
|
|
34
|
+
@When[env != "ohos"]
|
|
35
|
+
@C
|
|
36
|
+
foreign func cj_bridge_extract_assets(dir: CString): Int32
|
|
37
|
+
|
|
38
|
+
@When[env != "ohos"]
|
|
39
|
+
func extractAssetsBridge(dir: String): Int64 {
|
|
40
|
+
var n: Int32 = 0
|
|
41
|
+
unsafe {
|
|
42
|
+
n = cj_bridge_extract_assets(LibC.mallocCString(dir))
|
|
43
|
+
}
|
|
44
|
+
return Int64(n)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@When[env == "ohos"]
|
|
48
|
+
func extractAssetsBridge(dir: String): Int64 {
|
|
49
|
+
let _ = dir
|
|
50
|
+
eprintln("[cj-tauri] 本平台没有 C 桥,无内嵌资源可释放")
|
|
51
|
+
return 0
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* 按**绝对路径**预加载一个随包释放出来的动态库(单文件包专用)。
|
|
56
|
+
*
|
|
57
|
+
* 为什么需要它(2026-10-21 实测,另一台机器):仓颉运行时的随机数默认实现走 OpenSSL,而它按
|
|
58
|
+
* **裸名**找 `libcrypto-3-x64.dll` / `libssl-3-x64.dll`——SDK 与 stdx 都不带这两个,开发机上只是
|
|
59
|
+
* 恰好命中 PATH 里 Git 自带的那份。于是同一条 `ws://` 连接线,本机全通、别人双击就挂:
|
|
60
|
+
* `ws: connect failed: Can not load openssl library or function RAND_bytes.`
|
|
61
|
+
* (RFC6455 升级要算 `Sec-WebSocket-Key` 的随机 nonce,**明文 ws 也逃不掉**)。
|
|
62
|
+
*
|
|
63
|
+
* 只要进程内先按绝对路径加载一次,之后同类裸名加载就命中已加载模块:不必改 PATH,
|
|
64
|
+
* 也不必把 DLL 摆到 exe 旁边(单文件承诺不破)。
|
|
65
|
+
*
|
|
66
|
+
* `path` 必须是释放后的真实路径;返回 true = 已在进程内(含本来就在的)。
|
|
67
|
+
* 平台没有 C 桥时如实返回 false(`src/log_bridge.cj` 同款门禁)。
|
|
68
|
+
*/
|
|
69
|
+
public func preloadEmbeddedLibrary(path: String): Bool {
|
|
70
|
+
if (path.isEmpty()) {
|
|
71
|
+
eprintln("[cj-tauri] preloadEmbeddedLibrary: 路径为空")
|
|
72
|
+
return false
|
|
73
|
+
}
|
|
74
|
+
let ok = preloadLibraryBridge(path)
|
|
75
|
+
if (!ok) {
|
|
76
|
+
eprintln("[cj-tauri] 预加载动态库失败:${path}")
|
|
77
|
+
}
|
|
78
|
+
return ok
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
@When[env != "ohos"]
|
|
82
|
+
@C
|
|
83
|
+
foreign func cj_bridge_preload_library(path: CString): Int32
|
|
84
|
+
|
|
85
|
+
@When[env != "ohos"]
|
|
86
|
+
func preloadLibraryBridge(path: String): Bool {
|
|
87
|
+
var ok: Int32 = 0
|
|
88
|
+
unsafe {
|
|
89
|
+
ok = cj_bridge_preload_library(LibC.mallocCString(path))
|
|
90
|
+
}
|
|
91
|
+
return ok == 1
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
@When[env == "ohos"]
|
|
95
|
+
func preloadLibraryBridge(path: String): Bool {
|
|
96
|
+
let _ = path
|
|
97
|
+
return false
|
|
98
|
+
}
|