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/window_registry.cj
CHANGED
|
@@ -1,116 +1,116 @@
|
|
|
1
|
-
package cjTauri
|
|
2
|
-
|
|
3
|
-
import std.collection.*
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* 一个窗口的记录:label 唯一,config 是它创建时的窗口配置快照
|
|
7
|
-
*
|
|
8
|
-
* label 是窗口对外的**唯一身份**(Tauri 同样按 label 寻址):前端页面只认 label,
|
|
9
|
-
* C 侧句柄是跨 FFI 的不透明指针,留在宿主实现内部、不越过 IPC 协议(见
|
|
10
|
-
* docs/架构演进-多平台与多窗口.md §7.2)。
|
|
11
|
-
*/
|
|
12
|
-
public class WindowRecord {
|
|
13
|
-
public let label: String
|
|
14
|
-
public let host: WebViewHost
|
|
15
|
-
public let config: WindowConfig
|
|
16
|
-
|
|
17
|
-
public init(label: String, host: WebViewHost, config: WindowConfig) {
|
|
18
|
-
this.label = label
|
|
19
|
-
this.host = host
|
|
20
|
-
this.config = config
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* label → 窗口记录(批次 2 的地基)
|
|
26
|
-
*
|
|
27
|
-
* 单窗口阶段只登记一条 "main"——与桥 JS 的 windowLabel 缺省值、旧代码里写死的 "main"
|
|
28
|
-
* 是同一个约定(**默认值不能变**,否则现有示例与探针会静默收不到事件,见架构文档 §6.4)。
|
|
29
|
-
* 多窗口落地后它是「label → 宿主」的唯一权威来源:事件定向投递(emitToWindow)与
|
|
30
|
-
* 命令上下文(IpcContext.window)都从这里查。
|
|
31
|
-
*
|
|
32
|
-
* 为什么重复 label 直接抛而不是覆盖:覆盖会让「一个 label 后面挂着两个宿主」静默成立,
|
|
33
|
-
* 而这类 bug 的表现是「事件忽而收得到、忽而收不到」,是最难查的一类。
|
|
34
|
-
*/
|
|
35
|
-
class WindowRegistry {
|
|
36
|
-
private var windows: HashMap<String, WindowRecord> = HashMap<String, WindowRecord>()
|
|
37
|
-
// 为什么另存一份插入顺序:HashMap 不承诺迭代顺序,而广播要按确定顺序投递——
|
|
38
|
-
// 否则多窗口下事件的到达顺序随机,测试也没法断言(labels() 直接给这张表)。
|
|
39
|
-
private var order: ArrayList<String> = ArrayList<String>()
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* 登记一个窗口:label 非空且未被占用
|
|
43
|
-
*/
|
|
44
|
-
func add(record: WindowRecord): Unit {
|
|
45
|
-
if (record.label.size == 0) {
|
|
46
|
-
throw Exception("window label 不能为空")
|
|
47
|
-
}
|
|
48
|
-
if (this.windows.contains(record.label)) {
|
|
49
|
-
throw Exception("duplicate window label: \"${record.label}\"")
|
|
50
|
-
}
|
|
51
|
-
this.windows.add(record.label, record)
|
|
52
|
-
this.order.add(record.label)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* 按 label 取窗口;未登记返回 None(调用方决定是降级还是报错)
|
|
57
|
-
*/
|
|
58
|
-
func get(label: String): Option<WindowRecord> {
|
|
59
|
-
return this.windows.get(label)
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* 全部 label,**按登记顺序**(广播路径据此保持确定顺序)
|
|
64
|
-
*/
|
|
65
|
-
func labels(): ArrayList<String> {
|
|
66
|
-
let out = ArrayList<String>()
|
|
67
|
-
for (l in this.order) {
|
|
68
|
-
out.add(l)
|
|
69
|
-
}
|
|
70
|
-
return out
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* 解析投递目标:空串 = 广播(按登记顺序给出全部窗口),非空 = 命中则单元素、否则空表
|
|
75
|
-
*
|
|
76
|
-
* 路由决策放在这里而不是调用方:它是纯函数(不碰宿主)因而能单测,调用方只剩
|
|
77
|
-
* 「投给谁」与「一个都没命中时怎么报」两件事。**未注册的 label 不回落成广播**——
|
|
78
|
-
* 写错 label 就该什么都收不到(由调用方打一条 stderr),静默变成广播比丢事件更难查。
|
|
79
|
-
*/
|
|
80
|
-
func targets(window: String): ArrayList<WindowRecord> {
|
|
81
|
-
let out = ArrayList<WindowRecord>()
|
|
82
|
-
if (window.size == 0) {
|
|
83
|
-
for (l in this.order) {
|
|
84
|
-
out.add(this.windows.get(l).getOrThrow())
|
|
85
|
-
}
|
|
86
|
-
return out
|
|
87
|
-
}
|
|
88
|
-
match (this.windows.get(window)) {
|
|
89
|
-
case Some(rec) => out.add(rec)
|
|
90
|
-
case None => ()
|
|
91
|
-
}
|
|
92
|
-
return out
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* 注销窗口;label 不存在时为空操作(关窗路径可能重复触发,不该被异常打断)
|
|
97
|
-
*/
|
|
98
|
-
func remove(label: String): Unit {
|
|
99
|
-
if (!this.windows.contains(label)) {
|
|
100
|
-
return
|
|
101
|
-
}
|
|
102
|
-
let _ = this.windows.remove(label)
|
|
103
|
-
// 顺序表同步:重建一遍(窗口数以个位计,不值得为它引一个索引表)
|
|
104
|
-
let kept = ArrayList<String>()
|
|
105
|
-
for (l in this.order) {
|
|
106
|
-
if (l != label) {
|
|
107
|
-
kept.add(l)
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
this.order = kept
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
func size(): Int64 {
|
|
114
|
-
return this.windows.size
|
|
115
|
-
}
|
|
116
|
-
}
|
|
1
|
+
package cjTauri
|
|
2
|
+
|
|
3
|
+
import std.collection.*
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* 一个窗口的记录:label 唯一,config 是它创建时的窗口配置快照
|
|
7
|
+
*
|
|
8
|
+
* label 是窗口对外的**唯一身份**(Tauri 同样按 label 寻址):前端页面只认 label,
|
|
9
|
+
* C 侧句柄是跨 FFI 的不透明指针,留在宿主实现内部、不越过 IPC 协议(见
|
|
10
|
+
* docs/架构演进-多平台与多窗口.md §7.2)。
|
|
11
|
+
*/
|
|
12
|
+
public class WindowRecord {
|
|
13
|
+
public let label: String
|
|
14
|
+
public let host: WebViewHost
|
|
15
|
+
public let config: WindowConfig
|
|
16
|
+
|
|
17
|
+
public init(label: String, host: WebViewHost, config: WindowConfig) {
|
|
18
|
+
this.label = label
|
|
19
|
+
this.host = host
|
|
20
|
+
this.config = config
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* label → 窗口记录(批次 2 的地基)
|
|
26
|
+
*
|
|
27
|
+
* 单窗口阶段只登记一条 "main"——与桥 JS 的 windowLabel 缺省值、旧代码里写死的 "main"
|
|
28
|
+
* 是同一个约定(**默认值不能变**,否则现有示例与探针会静默收不到事件,见架构文档 §6.4)。
|
|
29
|
+
* 多窗口落地后它是「label → 宿主」的唯一权威来源:事件定向投递(emitToWindow)与
|
|
30
|
+
* 命令上下文(IpcContext.window)都从这里查。
|
|
31
|
+
*
|
|
32
|
+
* 为什么重复 label 直接抛而不是覆盖:覆盖会让「一个 label 后面挂着两个宿主」静默成立,
|
|
33
|
+
* 而这类 bug 的表现是「事件忽而收得到、忽而收不到」,是最难查的一类。
|
|
34
|
+
*/
|
|
35
|
+
class WindowRegistry {
|
|
36
|
+
private var windows: HashMap<String, WindowRecord> = HashMap<String, WindowRecord>()
|
|
37
|
+
// 为什么另存一份插入顺序:HashMap 不承诺迭代顺序,而广播要按确定顺序投递——
|
|
38
|
+
// 否则多窗口下事件的到达顺序随机,测试也没法断言(labels() 直接给这张表)。
|
|
39
|
+
private var order: ArrayList<String> = ArrayList<String>()
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 登记一个窗口:label 非空且未被占用
|
|
43
|
+
*/
|
|
44
|
+
func add(record: WindowRecord): Unit {
|
|
45
|
+
if (record.label.size == 0) {
|
|
46
|
+
throw Exception("window label 不能为空")
|
|
47
|
+
}
|
|
48
|
+
if (this.windows.contains(record.label)) {
|
|
49
|
+
throw Exception("duplicate window label: \"${record.label}\"")
|
|
50
|
+
}
|
|
51
|
+
this.windows.add(record.label, record)
|
|
52
|
+
this.order.add(record.label)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 按 label 取窗口;未登记返回 None(调用方决定是降级还是报错)
|
|
57
|
+
*/
|
|
58
|
+
func get(label: String): Option<WindowRecord> {
|
|
59
|
+
return this.windows.get(label)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 全部 label,**按登记顺序**(广播路径据此保持确定顺序)
|
|
64
|
+
*/
|
|
65
|
+
func labels(): ArrayList<String> {
|
|
66
|
+
let out = ArrayList<String>()
|
|
67
|
+
for (l in this.order) {
|
|
68
|
+
out.add(l)
|
|
69
|
+
}
|
|
70
|
+
return out
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 解析投递目标:空串 = 广播(按登记顺序给出全部窗口),非空 = 命中则单元素、否则空表
|
|
75
|
+
*
|
|
76
|
+
* 路由决策放在这里而不是调用方:它是纯函数(不碰宿主)因而能单测,调用方只剩
|
|
77
|
+
* 「投给谁」与「一个都没命中时怎么报」两件事。**未注册的 label 不回落成广播**——
|
|
78
|
+
* 写错 label 就该什么都收不到(由调用方打一条 stderr),静默变成广播比丢事件更难查。
|
|
79
|
+
*/
|
|
80
|
+
func targets(window: String): ArrayList<WindowRecord> {
|
|
81
|
+
let out = ArrayList<WindowRecord>()
|
|
82
|
+
if (window.size == 0) {
|
|
83
|
+
for (l in this.order) {
|
|
84
|
+
out.add(this.windows.get(l).getOrThrow())
|
|
85
|
+
}
|
|
86
|
+
return out
|
|
87
|
+
}
|
|
88
|
+
match (this.windows.get(window)) {
|
|
89
|
+
case Some(rec) => out.add(rec)
|
|
90
|
+
case None => ()
|
|
91
|
+
}
|
|
92
|
+
return out
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* 注销窗口;label 不存在时为空操作(关窗路径可能重复触发,不该被异常打断)
|
|
97
|
+
*/
|
|
98
|
+
func remove(label: String): Unit {
|
|
99
|
+
if (!this.windows.contains(label)) {
|
|
100
|
+
return
|
|
101
|
+
}
|
|
102
|
+
let _ = this.windows.remove(label)
|
|
103
|
+
// 顺序表同步:重建一遍(窗口数以个位计,不值得为它引一个索引表)
|
|
104
|
+
let kept = ArrayList<String>()
|
|
105
|
+
for (l in this.order) {
|
|
106
|
+
if (l != label) {
|
|
107
|
+
kept.add(l)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
this.order = kept
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
func size(): Int64 {
|
|
114
|
+
return this.windows.size
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
package ohos_app_cangjie_entry
|
|
2
|
-
|
|
3
|
-
import kit.ArkUI.*
|
|
4
|
-
import kit.ArkWeb.*
|
|
5
|
-
import kit.PerformanceAnalysisKit.Hilog
|
|
6
|
-
import ohos.arkui.component.web.Web
|
|
7
|
-
import ohos.arkui.state_macro_manage.*
|
|
8
|
-
import cjTauri.*
|
|
9
|
-
|
|
10
|
-
/*
|
|
11
|
-
* 应用侧的 ArkWeb 宿主组件
|
|
12
|
-
*
|
|
13
|
-
* 这个 `@Component` **必须住在应用模块里**,不能由框架包提供:框架包一旦 import
|
|
14
|
-
* `kit.ArkUI.*` / `kit.ArkWeb.*`,合并进应用动态库后包初始化链会跳到坏地址、启动即 SIGSEGV。
|
|
15
|
-
* 框架侧只留 `arkWebProxyPost` / `arkWebProxyPoll` 两个不碰 ArkUI 的桥接函数。
|
|
16
|
-
*
|
|
17
|
-
* 单窗口版:label 用框架默认的 DEFAULT_WINDOW_LABEL。要做多窗口就照着加一份、
|
|
18
|
-
* 换成别的 label(框架的宿主路由是按 label 查的,不会串台)。
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* proxy 的 `post` 入口:先交给框架处理报文,再把队列里的脚本推回页面
|
|
23
|
-
*
|
|
24
|
-
* 为什么「顺手推」放在这里:`javaScriptProxy` 的回调就在 UI 线程上,而
|
|
25
|
-
* `controller.runJavaScript` 也必须在 UI 线程调。页面 → 原生的**返回值通道不可用**
|
|
26
|
-
* (实测恒为 `null`),所以鸿蒙侧只能「页面发心跳 → 原生在该回调里把待执行脚本推出去」,
|
|
27
|
-
* 这是唯一的回投路径;框架会把它收到的 invoke 结果 / event 都排进这个队列。
|
|
28
|
-
*/
|
|
29
|
-
func onProxyPost(label: String, raw: String, ctrl: WebviewController): String {
|
|
30
|
-
let ack = arkWebProxyPost(label, raw)
|
|
31
|
-
match (ArkWebRuntime.hostFor(label)) {
|
|
32
|
-
case Some(h) =>
|
|
33
|
-
let pending = h.takePendingScripts()
|
|
34
|
-
var i = 0
|
|
35
|
-
while (i < pending.size) {
|
|
36
|
-
ctrl.runJavaScript(pending[i], { _, _ => () })
|
|
37
|
-
i += 1
|
|
38
|
-
}
|
|
39
|
-
case None => ()
|
|
40
|
-
}
|
|
41
|
-
return ack
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
@Component
|
|
45
|
-
class CjTauriWebView {
|
|
46
|
-
/* label 决定:①页面里 __CJ_TAURI_LABEL__ ②报文里的 window 字段 ③宿主取哪份页面来源。
|
|
47
|
-
必须是 `@Prop`:普通成员会被宏展开成 ObservedProperty 形参,外面传字符串进来会报
|
|
48
|
-
「expected 4 arguments」。 */
|
|
49
|
-
@Prop
|
|
50
|
-
var windowLabel: String
|
|
51
|
-
|
|
52
|
-
/* 组件生命周期内必须保持同一个 controller 实例(ArkWeb 的硬约束) */
|
|
53
|
-
private let controller: WebviewController = WebviewController()
|
|
54
|
-
|
|
55
|
-
/* 页面地址由宿主给定;@State 让它参与刷新(宿主登记页面往往晚于组件首次 build)。
|
|
56
|
-
`@State` 不允许与 private/public/static 同用——宏会直接拒绝。 */
|
|
57
|
-
@State
|
|
58
|
-
var pageUrl: String = ""
|
|
59
|
-
|
|
60
|
-
public func build() {
|
|
61
|
-
Column {
|
|
62
|
-
if (this.pageUrl.size > 0) {
|
|
63
|
-
Web(src: this.pageUrl, controller: this.controller)
|
|
64
|
-
.width(100.percent)
|
|
65
|
-
.height(100.percent)
|
|
66
|
-
.fileAccess(true)
|
|
67
|
-
.javaScriptProxy(
|
|
68
|
-
funcList: [
|
|
69
|
-
{ raw => onProxyPost(this.windowLabel, raw, this.controller) },
|
|
70
|
-
/* `poll` 只为兼容页面上可能残留的旧桥脚本:返回值传不回 JS,
|
|
71
|
-
真正的脚本推送已在 `onProxyPost` 里完成。 */
|
|
72
|
-
{ _ => "" }
|
|
73
|
-
],
|
|
74
|
-
name: ARKWEB_PROXY_NAME, methodList: ["post", "poll"],
|
|
75
|
-
controller: this.controller
|
|
76
|
-
)
|
|
77
|
-
.onPageBegin({ _ => this.onPageBegin() })
|
|
78
|
-
.onPageEnd({ _ => this.onPageEnd() })
|
|
79
|
-
}
|
|
80
|
-
}.width(100.percent).height(100.percent)
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* 组件挂载钩子(首次 `build()` 之前调用一次)
|
|
85
|
-
*
|
|
86
|
-
* **必须在这里同步宿主地址**:宿主把页面落盘后才把 `file://` 地址放进自己的字段,
|
|
87
|
-
* 而 `build()` 是声明式的一次性求值——`pageUrl` 仍为空就永远不建 `Web`,
|
|
88
|
-
* `onPageBegin` 也就永远不会来,页面白屏。
|
|
89
|
-
*/
|
|
90
|
-
protected override func aboutToAppear(): Unit {
|
|
91
|
-
match (ArkWebRuntime.hostFor(this.windowLabel)) {
|
|
92
|
-
case Some(h) =>
|
|
93
|
-
let u = h.currentUrl()
|
|
94
|
-
if (u.size > 0) {
|
|
95
|
-
this.pageUrl = u
|
|
96
|
-
}
|
|
97
|
-
Hilog.info(1, "CjTauri", "aboutToAppear label=${this.windowLabel} pageUrl=${u}")
|
|
98
|
-
case None => Hilog.info(1, "CjTauri", "aboutToAppear without host")
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
private func onPageBegin(): Unit {
|
|
103
|
-
Hilog.info(1, "CjTauri", "page begin label=${this.windowLabel}")
|
|
104
|
-
match (ArkWebRuntime.hostFor(this.windowLabel)) {
|
|
105
|
-
case Some(h) =>
|
|
106
|
-
h.notePageBegin()
|
|
107
|
-
let url = h.currentUrl()
|
|
108
|
-
if (url.size > 0 && url != this.pageUrl) {
|
|
109
|
-
this.pageUrl = url
|
|
110
|
-
}
|
|
111
|
-
// 桥脚本与插件 shim 都在 initScripts 里:ArkWeb 没有 document-start 注入,
|
|
112
|
-
// `onPageBegin` 是能拿到的最早时机。
|
|
113
|
-
for (js in h.initScriptsSnapshot()) {
|
|
114
|
-
this.runScript(js)
|
|
115
|
-
}
|
|
116
|
-
this.runScript(arkWebLabelScript(this.windowLabel))
|
|
117
|
-
case None => Hilog.info(1, "CjTauri", "page begin without host: label=${this.windowLabel}")
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
private func onPageEnd(): Unit {
|
|
122
|
-
Hilog.info(1, "CjTauri", "page end label=${this.windowLabel}")
|
|
123
|
-
match (ArkWebRuntime.hostFor(this.windowLabel)) {
|
|
124
|
-
case Some(h) =>
|
|
125
|
-
h.notePageEnd()
|
|
126
|
-
// 组件首次 build 时宿主可能还没登记(页面为空),这里再同步一次并触发刷新
|
|
127
|
-
let url = h.currentUrl()
|
|
128
|
-
if (url.size > 0 && url != this.pageUrl) {
|
|
129
|
-
this.pageUrl = url
|
|
130
|
-
}
|
|
131
|
-
case None => ()
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/** 单条脚本执行(ArkWeb 的 runJavaScript 是异步的,回调里只做失败日志) */
|
|
136
|
-
private func runScript(js: String): Unit {
|
|
137
|
-
if (js.size == 0) {
|
|
138
|
-
return
|
|
139
|
-
}
|
|
140
|
-
// runJavaScript(script, callback) 两个都是位置参数(命名参数前缀会被编译器拒)
|
|
141
|
-
this.controller.runJavaScript(
|
|
142
|
-
js,
|
|
143
|
-
{
|
|
144
|
-
err, result =>
|
|
145
|
-
match (err) {
|
|
146
|
-
case Some(e) => Hilog.info(1, "CjTauri", "runJavaScript failed: ${e.message}")
|
|
147
|
-
case None => Hilog.info(1, "CjTauri", "runJavaScript ok")
|
|
148
|
-
}
|
|
149
|
-
let _ = result
|
|
150
|
-
}
|
|
151
|
-
)
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
@Entry
|
|
156
|
-
@Component
|
|
157
|
-
class EntryView {
|
|
158
|
-
func build() {
|
|
159
|
-
Column {
|
|
160
|
-
// 高度由**外层容器**给:自定义组件的调用点不能挂链式修饰(`.height(...)`),
|
|
161
|
-
// 那样宏展开时补不上 `__gen_parent`,报的是「missing arguments for parameter list」。
|
|
162
|
-
Column() {
|
|
163
|
-
CjTauriWebView(windowLabel: DEFAULT_WINDOW_LABEL)
|
|
164
|
-
}.width(100.percent).height(100.percent)
|
|
165
|
-
}.width(100.percent).height(100.percent)
|
|
166
|
-
}
|
|
167
|
-
}
|
|
Binary file
|
package/src/host_factory.cj
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
package cjTauri
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* 应用侧注入的宿主工厂(自定义平台的装配入口)
|
|
5
|
-
*
|
|
6
|
-
* 内置平台(Windows / 桌面 Linux)由 `createHost()` 直接选实现;没有内置宿主的平台
|
|
7
|
-
* (鸿蒙 ArkWeb,以及 ARM64 Linux——两者 `os` 都报 `Linux`,只能用 `arch` 分开)
|
|
8
|
-
* 由应用在**构造 `TauriApp()` 之前**注册工厂:
|
|
9
|
-
*
|
|
10
|
-
* ```
|
|
11
|
-
* setHostFactory({ label => MyArkWebHost(label) })
|
|
12
|
-
* let app = TauriApp()
|
|
13
|
-
* ```
|
|
14
|
-
*
|
|
15
|
-
* 为什么放在框架外:ArkWeb 的宿主必须直接建 ArkUI 组件(`Web` + `WebviewController`),
|
|
16
|
-
* 框架核心一旦 import 这些 kit,桌面目标的构建也要跟着拉 ArkUI 依赖。把「建组件」留在应用、
|
|
17
|
-
* 把「桥与事件」留在框架,两边各自只依赖自己的那半边。
|
|
18
|
-
*
|
|
19
|
-
* 单一职责:本文件只管「工厂登记」这一件事,装配时机与语义见上面注释。
|
|
20
|
-
*/
|
|
21
|
-
private var HOST_FACTORY: Option<(String) -> WebViewHost> = None
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* 注册自定义 WebView 宿主工厂(必须在构造 `TauriApp()` 之前调用)
|
|
25
|
-
*
|
|
26
|
-
* label 与内置宿主同义(默认窗口是 `DEFAULT_WINDOW_LABEL`):工厂会为每个窗口各调一次,
|
|
27
|
-
* 实现方要保证「一个 label 一个宿主实例」,否则多窗口下事件会串台。
|
|
28
|
-
* 重复调用=替换而非叠加(只保留最后一次登记)。
|
|
29
|
-
*/
|
|
30
|
-
public func setHostFactory(factory: (String) -> WebViewHost): Unit {
|
|
31
|
-
HOST_FACTORY = Some(factory)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* 取注入的宿主;没登记就抛一条**可照做**的错误
|
|
36
|
-
*
|
|
37
|
-
* 不静默回落到空实现:宿主缺席时应用会拿到一个永远开不出窗口的对象,
|
|
38
|
-
* 比启动即失败更难排查(AGENTS §1 第 4 条:跑不起来要如实说明)。
|
|
39
|
-
*/
|
|
40
|
-
func requireInjectedHost(label: String): WebViewHost {
|
|
41
|
-
match (HOST_FACTORY) {
|
|
42
|
-
case Some(factory) => return factory(label)
|
|
43
|
-
case None =>
|
|
44
|
-
throw CommandException(
|
|
45
|
-
"当前平台没有内置 WebView 宿主:请在构造 TauriApp() 之前调用 cjTauri.setHostFactory({ label => ... }) 注入实现(鸿蒙 ArkWeb 走这条通路)"
|
|
46
|
-
)
|
|
47
|
-
}
|
|
48
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/cli/templates/{ohos-pc → ohos-skeleton}/AppScope/resources/base/element/string.json
RENAMED
|
File without changes
|
/package/cli/templates/{ohos-pc → ohos-skeleton}/AppScope/resources/base/media/background.png
RENAMED
|
File without changes
|
/package/cli/templates/{ohos-pc → ohos-skeleton}/AppScope/resources/base/media/foreground.png
RENAMED
|
File without changes
|
/package/cli/templates/{ohos-pc → ohos-skeleton}/AppScope/resources/base/media/layered_image.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/element/color.json
RENAMED
|
File without changes
|
/package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/element/string.json
RENAMED
|
File without changes
|
/package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/media/background.png
RENAMED
|
File without changes
|
/package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/media/foreground.png
RENAMED
|
File without changes
|
|
File without changes
|
/package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/media/startIcon.png
RENAMED
|
File without changes
|
|
File without changes
|
/package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/rawfile/capabilities.json
RENAMED
|
File without changes
|
/package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/rawfile/index.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|