cj-tauri 1.1.2 → 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 +137 -77
- package/bin/cj-tauri.js +287 -287
- package/cjpm.toml +13 -2
- package/cli/cjpm.toml +22 -13
- package/cli/src/doctor.cj +308 -304
- package/cli/src/main.cj +129 -121
- package/cli/src/manifest.cj +632 -0
- package/cli/src/manifest_test.cj +87 -0
- package/cli/src/project.cj +770 -754
- package/cli/src/resolve.cj +348 -348
- package/cli/src/scaffold.cj +46 -38
- package/cli/src/sync.cj +526 -0
- package/cli/src/util.cj +9 -0
- package/cli/templates/app/README.md +30 -59
- package/cli/templates/app/{ui → assets/ui}/index.html +2 -0
- package/cli/templates/app/cj-tauri.toml +32 -0
- package/cli/templates/app/cjpm.toml +21 -4
- package/cli/templates/app/src/main.cj +29 -16
- package/cli/templates/app-react/README.md +34 -45
- package/cli/templates/app-react/{ui → assets/ui}/index.html +25 -25
- package/cli/templates/app-react/{ui → assets/ui}/src/App.css +67 -67
- package/cli/templates/app-react/{ui → assets/ui}/src/App.jsx +124 -124
- package/cli/templates/app-react/cj-tauri.toml +33 -0
- package/cli/templates/app-react/cjpm.toml +21 -4
- package/cli/templates/app-react/src/main.cj +18 -29
- package/cli/templates/app-vue/README.md +34 -38
- package/cli/templates/app-vue/{ui → assets/ui}/index.html +25 -25
- package/cli/templates/app-vue/{ui → assets/ui}/src/App.vue +176 -176
- package/cli/templates/app-vue/cj-tauri.toml +33 -0
- package/cli/templates/app-vue/cjpm.toml +21 -4
- package/cli/templates/app-vue/src/main.cj +18 -29
- package/cli/templates/{ohos-pc → ohos-skeleton}/README.md +5 -0
- package/cli/templates/{ohos-pc → ohos-skeleton}/build-hap.sh +15 -0
- package/cli/templates/{ohos-pc → ohos-skeleton}/entry/cjpm.toml +8 -0
- 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 -0
- package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/module.json5 +8 -0
- 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 -51
- package/prebuilt/linux-x64/cj-tauri +0 -0
- package/src/api_system.cj +67 -67
- package/src/app.cj +325 -940
- 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 -0
- package/src/arkweb_menu.cj +216 -0
- package/src/arkweb_script.cj +0 -12
- 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 -604
- package/src/host_arkweb.cj +201 -17
- package/src/host_webkit.cj +663 -548
- package/src/host_webview2.cj +663 -548
- 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 -0
- package/src/logging.cj +127 -127
- package/src/menu.cj +197 -197
- package/src/platform/platform_app_context.cj +77 -0
- package/src/platform/platform_assets.cj +33 -0
- package/src/platform/platform_discover.cj +176 -0
- package/src/platform/platform_env.cj +29 -0
- package/src/platform/platform_feature.cj +31 -0
- package/src/platform/platform_page_source.cj +87 -0
- package/src/platform/platform_target_info.cj +32 -0
- package/src/platform_host_provider.cj +87 -0
- package/src/plugin.cj +333 -299
- package/src/plugins/clipboard/plugin_clipboard.cj +152 -144
- 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 +8 -0
- package/src/plugins/notification/plugin_notification.cj +154 -146
- package/src/plugins/serial/plugin_serial.cj +17 -1
- package/src/plugins/serial/serial_bridge.cj +9 -1
- 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 +29 -1
- package/src/plugins/sqlite/plugin_sqlite.cj +8 -0
- 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 -0
- package/src/tests/capability_test.cj +243 -243
- package/src/tests/dialog_spec_test.cj +73 -0
- package/src/tests/fake_host.cj +201 -186
- 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 -0
- 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 +66 -3
- 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/cli/templates/ohos-pc/entry/src/main/cangjie/index.cj +0 -167
- package/prebuilt/win32-x64/cj-tauri.exe +0 -0
- package/src/host_factory.cj +0 -48
- /package/cli/templates/app/{capabilities → assets/capabilities}/default.json +0 -0
- /package/cli/templates/app-react/{capabilities → assets/capabilities}/default.json +0 -0
- /package/cli/templates/app-react/{ui → assets/ui}/package.json +0 -0
- /package/cli/templates/app-react/{ui → assets/ui}/src/main.jsx +0 -0
- /package/cli/templates/app-react/{ui → assets/ui}/vite.config.js +0 -0
- /package/cli/templates/app-vue/{capabilities → assets/capabilities}/default.json +0 -0
- /package/cli/templates/app-vue/{ui → assets/ui}/package.json +0 -0
- /package/cli/templates/app-vue/{ui → assets/ui}/src/main.js +0 -0
- /package/cli/templates/app-vue/{ui → assets/ui}/vite.config.js +0 -0
- /package/cli/templates/{ohos-pc → ohos-skeleton}/AppScope/app.json5 +0 -0
- /package/cli/templates/{ohos-pc → ohos-skeleton}/AppScope/resources/base/element/string.json +0 -0
- /package/cli/templates/{ohos-pc → ohos-skeleton}/AppScope/resources/base/media/background.png +0 -0
- /package/cli/templates/{ohos-pc → ohos-skeleton}/AppScope/resources/base/media/foreground.png +0 -0
- /package/cli/templates/{ohos-pc → ohos-skeleton}/AppScope/resources/base/media/layered_image.json +0 -0
- /package/cli/templates/{ohos-pc → ohos-skeleton}/build-profile.json5 +0 -0
- /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/build-profile.json5 +0 -0
- /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/hvigorfile.ts +0 -0
- /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/oh-package.json5 +0 -0
- /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/cangjie/ability_stage.cj +0 -0
- /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/cangjie/app_host.cj +0 -0
- /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/cangjie/main_ability.cj +0 -0
- /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/element/color.json +0 -0
- /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/element/string.json +0 -0
- /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/media/background.png +0 -0
- /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/media/foreground.png +0 -0
- /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/media/layered_image.json +0 -0
- /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/media/startIcon.png +0 -0
- /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/profile/main_pages.json +0 -0
- /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/rawfile/capabilities.json +0 -0
- /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/rawfile/index.html +0 -0
- /package/cli/templates/{ohos-pc → ohos-skeleton}/hvigor/hvigor-config.json5 +0 -0
- /package/cli/templates/{ohos-pc → ohos-skeleton}/hvigorfile.ts +0 -0
- /package/cli/templates/{ohos-pc → ohos-skeleton}/oh-package.json5 +0 -0
package/src/host_arkweb.cj
CHANGED
|
@@ -43,6 +43,16 @@ import stdx.encoding.json.JsonArray
|
|
|
43
43
|
@When[env == "ohos"]
|
|
44
44
|
import stdx.encoding.json.JsonString
|
|
45
45
|
|
|
46
|
+
// 页面来源契约(load(source) 收敛,RFC §4.3):Asset 由胶水注入的 rawfile 解析器材化
|
|
47
|
+
@When[env == "ohos"]
|
|
48
|
+
import cjTauri.platform.*
|
|
49
|
+
|
|
50
|
+
// chdir:musl libc 的 C 函数(与 serial_ohos.cj 的 FFI 同模式;@When 门禁保桌面零影响)。
|
|
51
|
+
// foreign func 是包级符号——必须放文件顶层,嵌进类体会报「member function can not be foreign」。
|
|
52
|
+
@When[env == "ohos"]
|
|
53
|
+
@C
|
|
54
|
+
foreign func chdir(path: CString): Int32
|
|
55
|
+
|
|
46
56
|
/**
|
|
47
57
|
* 鸿蒙宿主的进程级运行时:沙箱目录、各窗口宿主、跨线程队列开关
|
|
48
58
|
*
|
|
@@ -71,6 +81,11 @@ public class ArkWebRuntime {
|
|
|
71
81
|
*
|
|
72
82
|
* 用 `context.filesDir`:鸿蒙上它是应用私有可写目录,进程重启后内容仍在,
|
|
73
83
|
* 于是页面文件可以在**每次启动**重建(内容由应用决定,不做持久化依赖)。
|
|
84
|
+
*
|
|
85
|
+
* **cwd 同时切进沙箱**:鸿蒙上进程 cwd 指向不可写位置(实测 errno 13),而应用唯一
|
|
86
|
+
* 免权限可写的就是沙箱目录。相对路径(业务的工作区、store 插件的落盘、scope 的
|
|
87
|
+
* `$CWD` 变量)全部以 cwd 为基准——不切的话,所有按相对路径落盘的插件在设备上
|
|
88
|
+
* 全部不可用。这等价于 Tauri 移动端的做法:路径基准必须是 appDataDir,不是进程 cwd。
|
|
74
89
|
*/
|
|
75
90
|
public static func configure(filesDir: String): Unit {
|
|
76
91
|
if (filesDir.size == 0) {
|
|
@@ -78,6 +93,14 @@ public class ArkWebRuntime {
|
|
|
78
93
|
return
|
|
79
94
|
}
|
|
80
95
|
ArkWebRuntime.sandboxDir = filesDir
|
|
96
|
+
unsafe {
|
|
97
|
+
let cpath = LibC.mallocCString(filesDir)
|
|
98
|
+
let r = chdir(cpath)
|
|
99
|
+
LibC.free(cpath)
|
|
100
|
+
if (r != 0) {
|
|
101
|
+
eprintln("[cj-tauri] chdir(${filesDir}) failed: errno=${r}(相对路径落盘仍以原 cwd 为基准)")
|
|
102
|
+
}
|
|
103
|
+
}
|
|
81
104
|
eprintln("[cj-tauri] ArkWeb sandbox: ${filesDir}")
|
|
82
105
|
}
|
|
83
106
|
|
|
@@ -145,9 +168,14 @@ public class ArkWebDialogRequest {
|
|
|
145
168
|
this.message = message
|
|
146
169
|
}
|
|
147
170
|
|
|
148
|
-
/**
|
|
171
|
+
/**
|
|
172
|
+
* 是否「确定 / 取消」两键(`info` / `warning` / `error` 只有一个确定键,弹出即成立)
|
|
173
|
+
*
|
|
174
|
+
* 判定本身在 `src/dialog_spec.cj`(三平台共用一份):这里原先写死 `kind == "confirm"`,
|
|
175
|
+
* 而这个文件带平台门禁、桌面编不到,同一个 kind 在两个平台各判一次就迟早判岔。
|
|
176
|
+
*/
|
|
149
177
|
public func isConfirm(): Bool {
|
|
150
|
-
return this.kind
|
|
178
|
+
return dialogShapeIsTwoKey(dialogShapeOf(this.kind))
|
|
151
179
|
}
|
|
152
180
|
}
|
|
153
181
|
|
|
@@ -175,6 +203,8 @@ let CJ_ARKWEB_DIALOG_POLL_MS: Int64 = 20
|
|
|
175
203
|
@When[env == "ohos"]
|
|
176
204
|
public class ArkWebHost <: WebViewHost {
|
|
177
205
|
private let windowLabel: String
|
|
206
|
+
// 资产解析器:胶水在 load 前注入(rawfile 材化);鸿蒙没有 cwd 读盘兜底
|
|
207
|
+
private var assetResolver: Option<AssetResolver> = None
|
|
178
208
|
|
|
179
209
|
/* 页面来源:start(html) 先存 html、落盘后 pageUrl 才成立;startUrl 直接定 pageUrl。 */
|
|
180
210
|
private var pageHtml: String = ""
|
|
@@ -208,6 +238,15 @@ public class ArkWebHost <: WebViewHost {
|
|
|
208
238
|
private var dialogRequestCount: Int64 = 0
|
|
209
239
|
private var dialogAnswerCount: Int64 = 0
|
|
210
240
|
|
|
241
|
+
/*
|
|
242
|
+
* 菜单模型快照:worker 线程写(setMenu / setMenuItemState)、UI 线程读(menuModel),
|
|
243
|
+
* 与上面三个对话框槽同受 queueLock 保护。ArkUI 那半边(bindMenu)在应用侧,
|
|
244
|
+
* 框架这边只存模型——理由见 arkweb_menu.cj 的类注释。
|
|
245
|
+
*/
|
|
246
|
+
private var menuRoot: ArrayList<ArkWebMenuItem> = ArrayList<ArkWebMenuItem>()
|
|
247
|
+
private var menuItemCount: Int64 = 0
|
|
248
|
+
private var menuClickCount: Int64 = 0
|
|
249
|
+
|
|
211
250
|
private var messageHandler: (String) -> Unit = { _ => }
|
|
212
251
|
private var shellHandler: (String) -> Unit = { _ => }
|
|
213
252
|
private var destroyHandler: () -> Unit = { => }
|
|
@@ -249,7 +288,37 @@ public class ArkWebHost <: WebViewHost {
|
|
|
249
288
|
}
|
|
250
289
|
|
|
251
290
|
/**
|
|
252
|
-
*
|
|
291
|
+
* 加载页面(唯一入口,RFC §4.3)
|
|
292
|
+
*
|
|
293
|
+
* 与桌面的差异:Asset **没有 cwd 读盘兜底**——hap 里没有工程目录,资产只能来自
|
|
294
|
+
* 胶水注入的 resolver(rawfile 材化)。缺注入或资产缺失时如实报错,不静默白屏。
|
|
295
|
+
*/
|
|
296
|
+
public func load(source: PageSource): Unit {
|
|
297
|
+
match (source) {
|
|
298
|
+
case Inline(html) => this.start(html)
|
|
299
|
+
case Url(url) => this.startUrl(url)
|
|
300
|
+
case DevServer(url) => this.startUrl(url)
|
|
301
|
+
case Asset(name) =>
|
|
302
|
+
match (this.assetResolver) {
|
|
303
|
+
case Some(r) =>
|
|
304
|
+
match (r.readText(name)) {
|
|
305
|
+
case Some(html) => this.start(html)
|
|
306
|
+
case None =>
|
|
307
|
+
throw AssetResolutionException("资产未找到:${name}(胶水注入的 rawfile 里没有这个资产,检查清单 [assets] 与骨架 rawfile 拷贝)")
|
|
308
|
+
}
|
|
309
|
+
case None =>
|
|
310
|
+
throw AssetResolutionException("资产 ${name} 未注入 AssetResolver(鸿蒙侧胶水须先把 rawfile 材化并注入解析器,再 load)")
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/** 注入资产解析器(胶水在 load 前调用,rawfile 材化器) */
|
|
316
|
+
public func setAssetResolver(resolver: Option<AssetResolver>): Unit {
|
|
317
|
+
this.assetResolver = resolver
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* 注册预执行脚本(必须早于 load,与桌面同一契约)
|
|
253
322
|
*
|
|
254
323
|
* 内联 HTML 走「拼进 head 最前」这条通道(真正早于页面脚本);URL 页面只能等
|
|
255
324
|
* `onPageBegin` 再 runJavaScript——那时页面顶层脚本可能已经跑过,**这是本平台的已知限制**,
|
|
@@ -284,17 +353,99 @@ public class ArkWebHost <: WebViewHost {
|
|
|
284
353
|
eprintln("[cj-tauri] ArkWeb: openDevTools is not available on this platform (use web debugging)")
|
|
285
354
|
}
|
|
286
355
|
|
|
287
|
-
/* ----
|
|
356
|
+
/* ---- 菜单:框架存模型,应用侧用 bindMenu 画(见 arkweb_menu.cj 的类注释) ---- */
|
|
288
357
|
|
|
358
|
+
/**
|
|
359
|
+
* 收下应用给的菜单线路格式(`MenuModel.toWire()`),解析成快照存起来。
|
|
360
|
+
*
|
|
361
|
+
* **不阻塞、也不画界面**:真正的菜单由应用侧的 `ArkWebView` 在 `bindMenu` 里画,
|
|
362
|
+
* UI 线程经 [menuModel] 取快照。这样框架包不引用 ArkUI(AGENTS §4 的 SIGSEGV 坑)。
|
|
363
|
+
*/
|
|
289
364
|
public func setMenu(wire: String): Unit {
|
|
290
|
-
let
|
|
291
|
-
|
|
365
|
+
let parsed = parseArkWebMenuWire(wire)
|
|
366
|
+
var rows: Int64 = 0
|
|
367
|
+
synchronized(ArkWebRuntime.queueLock) {
|
|
368
|
+
this.menuRoot = parsed
|
|
369
|
+
rows = countMenuItems(parsed)
|
|
370
|
+
this.menuItemCount = rows
|
|
371
|
+
}
|
|
372
|
+
eprintln("[cj-tauri] ArkWeb: menu applied (${wire.size} bytes, ${rows} item(s), app-side bindMenu)")
|
|
292
373
|
}
|
|
293
374
|
|
|
375
|
+
/**
|
|
376
|
+
* 运行期改单项状态(按 id 找,找不到静默忽略——与桌面两平台同口径)。
|
|
377
|
+
*
|
|
378
|
+
* 这里**不再抛异常**:菜单模型住在本进程,改动是纯内存动作;UI 下一轮 [menuModel]
|
|
379
|
+
* 拿到的就是新状态(`bindMenu` 每次 build 重新生成,不需要额外通知)。
|
|
380
|
+
*/
|
|
294
381
|
public func setMenuItemState(id: String, enabled: Bool, checked: Bool): Unit {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
382
|
+
var hit = false
|
|
383
|
+
synchronized(ArkWebRuntime.queueLock) {
|
|
384
|
+
for (item in this.menuRoot) {
|
|
385
|
+
match (item.find(id)) {
|
|
386
|
+
case Some(node) =>
|
|
387
|
+
node.enabled = enabled
|
|
388
|
+
node.checked = checked
|
|
389
|
+
hit = true
|
|
390
|
+
case None => ()
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
eprintln("[cj-tauri] ArkWeb: menu item state id=\"${id}\" enabled=${enabled} checked=${checked} hit=${hit}")
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
/**
|
|
398
|
+
* UI 线程取菜单快照(每次一份深拷贝,UI 改它不会动到宿主里的模型)。
|
|
399
|
+
*
|
|
400
|
+
* 应用侧的 `ArkWebView` 在 `build()` 里按它生成 `bindMenu` 的 `MenuElement` 数组;
|
|
401
|
+
* 没有菜单时回空表(应用照常建树,别等菜单才画 Web)。
|
|
402
|
+
*/
|
|
403
|
+
public func menuModel(): ArrayList<ArkWebMenuItem> {
|
|
404
|
+
let out = ArrayList<ArkWebMenuItem>()
|
|
405
|
+
synchronized(ArkWebRuntime.queueLock) {
|
|
406
|
+
for (item in this.menuRoot) {
|
|
407
|
+
out.add(item.snapshot())
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return out
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* 应用侧 UI 里「这一项被点了」→ 回投 shell 事件。
|
|
415
|
+
*
|
|
416
|
+
* 报文与桌面 C 桥的 `cj_core_menu_clicked` **逐字同形**
|
|
417
|
+
* (`{"kind":"menu","id":…,"enabled":…,"checked":…}`),于是应用层的 `onShellEvent`、
|
|
418
|
+
* 前端 `menu:click`、以及应用按事件同步自己模型的代码都不用分平台。
|
|
419
|
+
*
|
|
420
|
+
* 勾选项的翻转由本函数做(与 Windows 侧「Win32 不替我们翻,自己翻」同口径):
|
|
421
|
+
* 报出去的是**翻转后**的状态,页面照它更新即可。
|
|
422
|
+
*/
|
|
423
|
+
public func noteMenuClick(id: String): Unit {
|
|
424
|
+
var enabled = true
|
|
425
|
+
var checked = false
|
|
426
|
+
var found = false
|
|
427
|
+
synchronized(ArkWebRuntime.queueLock) {
|
|
428
|
+
for (item in this.menuRoot) {
|
|
429
|
+
match (item.find(id)) {
|
|
430
|
+
case Some(node) =>
|
|
431
|
+
if (node.isCheckbox()) {
|
|
432
|
+
node.checked = !node.checked
|
|
433
|
+
}
|
|
434
|
+
enabled = node.enabled
|
|
435
|
+
checked = node.checked
|
|
436
|
+
found = true
|
|
437
|
+
case None => ()
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
if (!found) {
|
|
442
|
+
eprintln("[cj-tauri] ArkWeb: menu click ignored (id=\"${id}\" is not in the current menu)")
|
|
443
|
+
return
|
|
444
|
+
}
|
|
445
|
+
this.menuClickCount++
|
|
446
|
+
eprintln("[cj-tauri] ArkWeb: menu clicked id=\"${id}\" enabled=${enabled} checked=${checked}")
|
|
447
|
+
this.shellHandler("{\"kind\":\"menu\",\"id\":\"${arkWebJsonEscape(id)}\",\"enabled\":${enabled}," +
|
|
448
|
+
"\"checked\":${checked}}")
|
|
298
449
|
}
|
|
299
450
|
|
|
300
451
|
public func setTitlebarSubtitle(text: String): Unit {
|
|
@@ -325,9 +476,16 @@ public class ArkWebHost <: WebViewHost {
|
|
|
325
476
|
let _ = enabled
|
|
326
477
|
}
|
|
327
478
|
|
|
328
|
-
/**
|
|
479
|
+
/** 能力位:菜单已置 1(2026-10-24 真机取证),其余仍为 0(AGENTS §1 门禁 4) */
|
|
329
480
|
public func hostCapabilities(): Int32 {
|
|
330
|
-
|
|
481
|
+
/*
|
|
482
|
+
* 菜单是鸿蒙侧第一项真落地的宿主能力:框架存模型(arkweb_menu.cj)、应用侧 bindMenu 画、
|
|
483
|
+
* 点击经 noteMenuClick 回投(报文与桌面同形)。其余位仍为 0——判据是「仓颉侧有没有 API」:
|
|
484
|
+
* 托盘(鸿蒙无系统托盘)、全局快捷键(只有组件级 keyboardshortcut)、拖入文件(SDK 只有
|
|
485
|
+
* 拖出侧的 drag / dragPreview,没有 drop 回调)、通知(SDK 无 notification_manager 模块)、
|
|
486
|
+
* 标题栏副标题(无 setWindowTitle)。AGENTS §1 门禁 4:没有实机证据的位置 1。
|
|
487
|
+
*/
|
|
488
|
+
return CJ_CAP_MENU
|
|
331
489
|
}
|
|
332
490
|
|
|
333
491
|
public func setShellHandler(handler: (String) -> Unit): Unit {
|
|
@@ -469,16 +627,23 @@ public class ArkWebHost <: WebViewHost {
|
|
|
469
627
|
}
|
|
470
628
|
}
|
|
471
629
|
|
|
630
|
+
/**
|
|
631
|
+
* 写文本进系统剪贴板(鸿蒙 = 原生 pasteboard,见 `clipboard_bridge.cj` 的鸿蒙段)
|
|
632
|
+
*
|
|
633
|
+
* 返回 false 只有三种可能:句柄拿不到、UDMF 对象建不出来、平台拒绝这次写入。
|
|
634
|
+
* **不要把 false 读成「暂时没接」**——这条能力在鸿蒙上已经接了,false 就是真失败。
|
|
635
|
+
*/
|
|
472
636
|
public func clipboardWriteText(text: String): Bool {
|
|
473
|
-
|
|
474
|
-
// 剪贴板在鸿蒙走 pasteboard 模块(`ohos.pasteboard`),尚未接入:如实 false,
|
|
475
|
-
// 不返回 true 骗调用方(这正是「发后即忘返回 0 ≠ 发送成功」那条坑的同族)。
|
|
476
|
-
eprintln("[cj-tauri] ArkWeb: clipboard write unsupported (pasteboard not wired yet)")
|
|
477
|
-
return false
|
|
637
|
+
return arkwebClipboardWriteText(text)
|
|
478
638
|
}
|
|
479
639
|
|
|
640
|
+
/**
|
|
641
|
+
* 读系统剪贴板文本:None = 空 / 非文本 / 平台拒绝(含缺 `READ_PASTEBOARD` 权限)
|
|
642
|
+
*
|
|
643
|
+
* 三种 None 对调用方是同一个「没拿到」——接口契约就是 Option,不在这儿编造区分。
|
|
644
|
+
*/
|
|
480
645
|
public func clipboardReadText(): Option<String> {
|
|
481
|
-
return
|
|
646
|
+
return arkwebClipboardReadText()
|
|
482
647
|
}
|
|
483
648
|
|
|
484
649
|
public func notify(title: String, body: String): Bool {
|
|
@@ -738,3 +903,22 @@ public class ArkWebHost <: WebViewHost {
|
|
|
738
903
|
return "${block}${html}"
|
|
739
904
|
}
|
|
740
905
|
}
|
|
906
|
+
|
|
907
|
+
/* 菜单项总数(含各级子孙):只用于日志对账,不参与渲染 */
|
|
908
|
+
@When[env == "ohos"]
|
|
909
|
+
private func countMenuItems(items: ArrayList<ArkWebMenuItem>): Int64 {
|
|
910
|
+
var total: Int64 = 0
|
|
911
|
+
for (item in items) {
|
|
912
|
+
total++
|
|
913
|
+
total += countMenuItems(item.children)
|
|
914
|
+
}
|
|
915
|
+
return total
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
/* shell 报文里 id 的最小转义:只处理 `\` 与 `"`(与 C 侧 cj_json_escape_into 同口径) */
|
|
919
|
+
@When[env == "ohos"]
|
|
920
|
+
private func arkWebJsonEscape(text: String): String {
|
|
921
|
+
// 迭代 String 得到的是 UInt8 字节(AGENTS §4),`String(byte)` 并不接受 UInt8——
|
|
922
|
+
// 这里只需要处理两个 ASCII 元字符,直接走 replace 更稳,也不碰字节/码点的口径。
|
|
923
|
+
return text.replace("\\", "\\\\").replace("\"", "\\\"")
|
|
924
|
+
}
|