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.
Files changed (162) hide show
  1. package/README.md +137 -77
  2. package/bin/cj-tauri.js +287 -287
  3. package/cjpm.toml +13 -2
  4. package/cli/cjpm.toml +22 -13
  5. package/cli/src/doctor.cj +308 -304
  6. package/cli/src/main.cj +129 -121
  7. package/cli/src/manifest.cj +632 -0
  8. package/cli/src/manifest_test.cj +87 -0
  9. package/cli/src/project.cj +770 -754
  10. package/cli/src/resolve.cj +348 -348
  11. package/cli/src/scaffold.cj +46 -38
  12. package/cli/src/sync.cj +526 -0
  13. package/cli/src/util.cj +9 -0
  14. package/cli/templates/app/README.md +30 -59
  15. package/cli/templates/app/{ui → assets/ui}/index.html +2 -0
  16. package/cli/templates/app/cj-tauri.toml +32 -0
  17. package/cli/templates/app/cjpm.toml +21 -4
  18. package/cli/templates/app/src/main.cj +29 -16
  19. package/cli/templates/app-react/README.md +34 -45
  20. package/cli/templates/app-react/{ui → assets/ui}/index.html +25 -25
  21. package/cli/templates/app-react/{ui → assets/ui}/src/App.css +67 -67
  22. package/cli/templates/app-react/{ui → assets/ui}/src/App.jsx +124 -124
  23. package/cli/templates/app-react/cj-tauri.toml +33 -0
  24. package/cli/templates/app-react/cjpm.toml +21 -4
  25. package/cli/templates/app-react/src/main.cj +18 -29
  26. package/cli/templates/app-vue/README.md +34 -38
  27. package/cli/templates/app-vue/{ui → assets/ui}/index.html +25 -25
  28. package/cli/templates/app-vue/{ui → assets/ui}/src/App.vue +176 -176
  29. package/cli/templates/app-vue/cj-tauri.toml +33 -0
  30. package/cli/templates/app-vue/cjpm.toml +21 -4
  31. package/cli/templates/app-vue/src/main.cj +18 -29
  32. package/cli/templates/{ohos-pc → ohos-skeleton}/README.md +5 -0
  33. package/cli/templates/{ohos-pc → ohos-skeleton}/build-hap.sh +15 -0
  34. package/cli/templates/{ohos-pc → ohos-skeleton}/entry/cjpm.toml +8 -0
  35. package/cli/templates/ohos-skeleton/entry/src/main/cangjie/dialog_host.cj +217 -0
  36. package/cli/templates/ohos-skeleton/entry/src/main/cangjie/index.cj +527 -0
  37. package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/module.json5 +8 -0
  38. package/native/build_win.bat +62 -62
  39. package/native/core/bridge_core.c +1681 -1626
  40. package/native/core/bridge_core.h +675 -618
  41. package/native/core/bridge_js.h +108 -108
  42. package/native/platforms/harmonyos/README.md +115 -6
  43. package/native/platforms/linux/bridge_linux.c +2787 -2485
  44. package/native/platforms/windows/bridge_win.c +3740 -3248
  45. package/native/tests/gtk_threading_probe.c +143 -143
  46. package/native/tests/test_bridge_core.c +1339 -1228
  47. package/package.json +53 -51
  48. package/prebuilt/linux-x64/cj-tauri +0 -0
  49. package/src/api_system.cj +67 -67
  50. package/src/app.cj +325 -940
  51. package/src/app_events.cj +166 -0
  52. package/src/app_host_ops.cj +287 -0
  53. package/src/app_run.cj +283 -0
  54. package/src/app_spec.cj +76 -0
  55. package/src/arkweb_menu.cj +216 -0
  56. package/src/arkweb_script.cj +0 -12
  57. package/src/capability.cj +409 -409
  58. package/src/clipboard_bridge.cj +178 -0
  59. package/src/dialog_spec.cj +79 -0
  60. package/src/dragdrop.cj +26 -26
  61. package/src/embedded_assets.cj +98 -98
  62. package/src/host.cj +752 -604
  63. package/src/host_arkweb.cj +201 -17
  64. package/src/host_webkit.cj +663 -548
  65. package/src/host_webview2.cj +663 -548
  66. package/src/hotkey.cj +66 -66
  67. package/src/ipc_hub.cj +337 -337
  68. package/src/ipc_message.cj +286 -286
  69. package/src/launch.cj +62 -0
  70. package/src/logging.cj +127 -127
  71. package/src/menu.cj +197 -197
  72. package/src/platform/platform_app_context.cj +77 -0
  73. package/src/platform/platform_assets.cj +33 -0
  74. package/src/platform/platform_discover.cj +176 -0
  75. package/src/platform/platform_env.cj +29 -0
  76. package/src/platform/platform_feature.cj +31 -0
  77. package/src/platform/platform_page_source.cj +87 -0
  78. package/src/platform/platform_target_info.cj +32 -0
  79. package/src/platform_host_provider.cj +87 -0
  80. package/src/plugin.cj +333 -299
  81. package/src/plugins/clipboard/plugin_clipboard.cj +152 -144
  82. package/src/plugins/dialog/plugin_dialog.cj +209 -209
  83. package/src/plugins/fs/plugin_fs.cj +105 -1
  84. package/src/plugins/http/http_backend.cj +131 -0
  85. package/src/plugins/http/http_desktop.cj +195 -0
  86. package/src/plugins/http/http_ohos.cj +204 -0
  87. package/src/plugins/http/plugin_http.cj +310 -459
  88. package/src/plugins/log/plugin_log.cj +105 -105
  89. package/src/plugins/menu/plugin_menu.cj +8 -0
  90. package/src/plugins/notification/plugin_notification.cj +154 -146
  91. package/src/plugins/serial/plugin_serial.cj +17 -1
  92. package/src/plugins/serial/serial_bridge.cj +9 -1
  93. package/src/plugins/serial/serial_manager_ohos.cj +92 -0
  94. package/src/plugins/serial/serial_ohos.cj +529 -0
  95. package/src/plugins/shell/plugin_shell.cj +29 -1
  96. package/src/plugins/sqlite/plugin_sqlite.cj +8 -0
  97. package/src/plugins/ws/plugin_ws.cj +488 -470
  98. package/src/process_hidden.cj +174 -174
  99. package/src/scope.cj +391 -391
  100. package/src/shell_event.cj +69 -69
  101. package/src/tests/app_spec_test.cj +126 -0
  102. package/src/tests/capability_test.cj +243 -243
  103. package/src/tests/dialog_spec_test.cj +73 -0
  104. package/src/tests/fake_host.cj +201 -186
  105. package/src/tests/ipc_hub_test.cj +487 -487
  106. package/src/tests/logging_test.cj +62 -62
  107. package/src/tests/platform_contract_test.cj +251 -0
  108. package/src/tests/plugin_clipboard_test.cj +222 -222
  109. package/src/tests/plugin_dialog_test.cj +237 -237
  110. package/src/tests/plugin_fs_test.cj +207 -0
  111. package/src/tests/plugin_http_test.cj +124 -124
  112. package/src/tests/plugin_notification_test.cj +205 -205
  113. package/src/tests/plugin_serial_test.cj +48 -0
  114. package/src/tests/plugin_test.cj +66 -3
  115. package/src/tests/plugin_ws_test.cj +40 -40
  116. package/src/tests/process_hidden_test.cj +129 -129
  117. package/src/tests/scope_test.cj +350 -350
  118. package/src/tests/system_host_test.cj +99 -81
  119. package/src/tests/urlutil_test.cj +53 -53
  120. package/src/tests/version_test.cj +75 -75
  121. package/src/tests/window_registry_test.cj +123 -123
  122. package/src/tray.cj +90 -90
  123. package/src/urlutil.cj +159 -159
  124. package/src/version.cj +44 -44
  125. package/src/window.cj +51 -51
  126. package/src/window_registry.cj +116 -116
  127. package/cli/templates/ohos-pc/entry/src/main/cangjie/index.cj +0 -167
  128. package/prebuilt/win32-x64/cj-tauri.exe +0 -0
  129. package/src/host_factory.cj +0 -48
  130. /package/cli/templates/app/{capabilities → assets/capabilities}/default.json +0 -0
  131. /package/cli/templates/app-react/{capabilities → assets/capabilities}/default.json +0 -0
  132. /package/cli/templates/app-react/{ui → assets/ui}/package.json +0 -0
  133. /package/cli/templates/app-react/{ui → assets/ui}/src/main.jsx +0 -0
  134. /package/cli/templates/app-react/{ui → assets/ui}/vite.config.js +0 -0
  135. /package/cli/templates/app-vue/{capabilities → assets/capabilities}/default.json +0 -0
  136. /package/cli/templates/app-vue/{ui → assets/ui}/package.json +0 -0
  137. /package/cli/templates/app-vue/{ui → assets/ui}/src/main.js +0 -0
  138. /package/cli/templates/app-vue/{ui → assets/ui}/vite.config.js +0 -0
  139. /package/cli/templates/{ohos-pc → ohos-skeleton}/AppScope/app.json5 +0 -0
  140. /package/cli/templates/{ohos-pc → ohos-skeleton}/AppScope/resources/base/element/string.json +0 -0
  141. /package/cli/templates/{ohos-pc → ohos-skeleton}/AppScope/resources/base/media/background.png +0 -0
  142. /package/cli/templates/{ohos-pc → ohos-skeleton}/AppScope/resources/base/media/foreground.png +0 -0
  143. /package/cli/templates/{ohos-pc → ohos-skeleton}/AppScope/resources/base/media/layered_image.json +0 -0
  144. /package/cli/templates/{ohos-pc → ohos-skeleton}/build-profile.json5 +0 -0
  145. /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/build-profile.json5 +0 -0
  146. /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/hvigorfile.ts +0 -0
  147. /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/oh-package.json5 +0 -0
  148. /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/cangjie/ability_stage.cj +0 -0
  149. /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/cangjie/app_host.cj +0 -0
  150. /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/cangjie/main_ability.cj +0 -0
  151. /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/element/color.json +0 -0
  152. /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/element/string.json +0 -0
  153. /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/media/background.png +0 -0
  154. /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/media/foreground.png +0 -0
  155. /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/media/layered_image.json +0 -0
  156. /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/media/startIcon.png +0 -0
  157. /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/profile/main_pages.json +0 -0
  158. /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/rawfile/capabilities.json +0 -0
  159. /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/rawfile/index.html +0 -0
  160. /package/cli/templates/{ohos-pc → ohos-skeleton}/hvigor/hvigor-config.json5 +0 -0
  161. /package/cli/templates/{ohos-pc → ohos-skeleton}/hvigorfile.ts +0 -0
  162. /package/cli/templates/{ohos-pc → ohos-skeleton}/oh-package.json5 +0 -0
@@ -1,80 +1,51 @@
1
1
  # {{PROJECT_NAME}}
2
2
 
3
3
  基于 [cj-tauri]({{FRAMEWORK_ROOT}})(仓颉版 Tauri)的应用:**仓颉后端 + 系统 WebView 前端**,
4
- 通过 `window.__CJ_TAURI__` 做 invoke/listen 双向 IPC,并由 capability 清单做最小权限管控。
4
+ 通过 `window.__CJ_TAURI__` 做 invoke/listen 双向 IPC,并由 capabilities 清单做最小权限管控。
5
5
 
6
- ## 目录结构
6
+ ## 目录结构(一份业务代码,骨架按目标派生)
7
7
 
8
8
  ```
9
9
  {{PROJECT_NAME}}/
10
- ├── cjpm.toml # 应用构建配置(依赖 cj-tauri 框架)
11
- ├── src/main.cj # 仓颉入口:窗口配置 + 命令注册 + 启动
12
- ├── ui/index.html # 前端页面(任意 Web 技术栈)
13
- └── capabilities/default.json # 能力白名单(命令 / 事件)
10
+ ├── cj-tauri.toml # 应用清单——单一真相(id/version/窗口/资产/能力目录)
11
+ ├── cjpm.toml # 业务包(static 库;骨架以 path 依赖引用)
12
+ ├── src/main.cj # 业务装配点 build(): AppSpec(零平台知识)
13
+ ├── assets/
14
+ │ ├── ui/index.html # 前端页面(任意 Web 技术栈)
15
+ │ └── capabilities/default.json # 能力白名单(命令 / 事件 / 权限集)
16
+ └── targets/ # cj-tauri sync 生成的骨架(勿手改;check 判漂移)
17
+ ├── desktop/ # 桌面可执行(launcher 调 build())
18
+ └── ohos/ # 鸿蒙 hap 工程(DevEco + build-hap.sh)
14
19
  ```
15
20
 
16
21
  ## 运行
17
22
 
18
23
  ```bash
19
- # 开发:构建 C 桥 + 编译 + 启动窗口
20
- cj-tauri dev
21
-
22
- # 仅构建 / 仅运行
23
- cj-tauri build
24
- cj-tauri run
24
+ cj-tauri sync # 派生 targets/ 骨架(首次;重跑幂等)
25
+ cj-tauri dev # 构建 C 桥 + 编译 + 启动窗口
26
+ cj-tauri build # 仅构建
27
+ cj-tauri run # 运行已构建产物
28
+ cj-tauri check # 清单校验 + 骨架漂移 + 插件三方比对
25
29
  ```
26
30
 
27
- 不带 CLI 时手动运行:
31
+ ## 鸿蒙端(PC / 2in1)
28
32
 
29
33
  ```bash
30
- cjpm build
31
- # 需要把「框架 native 目录 + stdx 目录 + 仓颉运行时目录」加入动态库搜索路径后,
32
- # 在项目根目录(capabilities/ 与 ui/ 是相对路径读取)启动:
33
- # Linux: LD_LIBRARY_PATH=<native>:<stdx>:<cangjie runtime/lib> ./target/release/bin/main
34
- # Windows: set PATH=<native>;<native>\webview2;<stdx>;<cangjie>\runtime\lib\windows_x86_64_cjnative;%PATH%
35
- # target\release\bin\main.exe
36
- ```
37
-
38
- ## 窗口配置
39
-
40
- ```cangjie
41
- let app = TauriApp()
42
- .window(WindowConfig("我的应用", 1200, 800)) // 标题 / 宽 / 高
34
+ export CANGJIE_STDX_OHOS=<鸿蒙版 stdx>/linux_ohos_aarch64_cjnative/dynamic/stdx
35
+ cd targets/ohos && bash build-hap.sh # 编 hap
36
+ cd targets/ohos && bash build-hap.sh --install # 编完装到设备并拉起
43
37
  ```
44
38
 
45
- 默认标题 `cj-tauri 应用`、1000×700、允许开发者工具;
46
- `WindowConfig.devTools = false` 可禁用,前端 `invoke('system:devtools')` 可在运行时打开(需在能力清单里声明)。
39
+ 提示:模板不带签名证书——首次在 DevEco 里 File → Project Structure → Signing Configs
40
+ 勾「Automatically generate signature」(要登录华为账号);不签名只能编出
41
+ *-unsigned.hap,装不进设备。
47
42
 
48
- ## 加一个命令
49
-
50
- 1. 在 `src/main.cj` 实现 `CommandHandler`:
51
-
52
- ```cangjie
53
- public class PingCommand <: CommandHandler {
54
- public init() {}
55
- public func handle(cmd: String, args: JsonObject, ipc: IpcContext): JsonValue {
56
- return JsonString("pong")
57
- }
58
- }
59
- ```
60
-
61
- 2. 注册:`.register("ping", PingCommand())`
62
- 3. 在 `capabilities/default.json` 的 `commands` 里声明 `"ping"`(**不声明会被拒绝**;
63
- 清单由框架在 `run()` 时自动扫描 `capabilities/` 目录,无需自己读文件)
64
- 4. 前端调用:`window.__CJ_TAURI__.invoke('ping').then(...)`
65
-
66
- ## 后端推事件
67
-
68
- ```cangjie
69
- var payload = JsonObject()
70
- payload.put("n", JsonInt(1))
71
- ipc.emit("tick", payload) // 需在 capabilities 的 events 中声明 "tick"
72
- ```
73
-
74
- ```js
75
- window.__CJ_TAURI__.listen('tick', function (payload) { console.log(payload.n); });
76
- ```
43
+ ## 命令与能力
77
44
 
78
- ## 文档
45
+ **把骨架变成你的应用,改三处**:① `src/main.cj` 照 `GreetCommand` 写命令并在 `build()` 里 register;
46
+ ② `assets/capabilities/default.json` 的 `commands` 里放行;③ `assets/ui/index.html` 里 `tauri.invoke`。
79
47
 
80
- 框架完整文档:`{{FRAMEWORK_ROOT}}/README.md` 与 `{{FRAMEWORK_ROOT}}/docs/使用文档.md`
48
+ 命令在 `src/main.cj`(`greet` / `timer` + 演示菜单),白名单在 `assets/capabilities/default.json`——
49
+ 两边必须对齐:`cj-tauri check` 的三方比对会交叉核对「能力声明 × 插件自描述 × 实际装配」。
50
+ 插件在某端没有实现时(如 shell/sqlite 在鸿蒙端),骨架照样编得过,运行期调用得到
51
+ 可照做的「端不支持」错误(RFC-002 §4.6.4 的 P-1 桩)。
@@ -55,6 +55,8 @@
55
55
 
56
56
  <script>
57
57
  // 注入的桥(对标 @tauri-apps/api):window.__CJ_TAURI__
58
+ // ③ 改页面从这看起:tauri.invoke 调后端命令、tauri.listen 收后端事件
59
+ // (新命令记得在 src/main.cj 实现,并在 assets/capabilities/default.json 放行)
58
60
  function withBridge(cb) {
59
61
  if (window.__CJ_TAURI__) { cb(window.__CJ_TAURI__); return; }
60
62
  setTimeout(function () { withBridge(cb); }, 50);
@@ -0,0 +1,32 @@
1
+ # cj-tauri 应用清单——整个工程的单一真相(RFC-002 §7)。
2
+ # cj-tauri sync 从这里派生 targets/ 骨架(desktop/ohos);cj-tauri check 校验它并检测骨架漂移。
3
+ [app]
4
+ name = "{{PROJECT_NAME}}"
5
+ version = "0.1.0"
6
+ # 应用标识:桌面是安装 ID,鸿蒙直接是 bundleName(每段须字母开头、只含字母数字下划线)
7
+ id = "{{BUNDLE_NAME}}"
8
+ # 业务包名(cjpm 约束①:toml 模块名必须等于源包名)
9
+ package = "{{PACKAGE_NAME}}"
10
+
11
+ [[windows]]
12
+ label = "main"
13
+ title = "{{PROJECT_NAME}}"
14
+ width = 1000
15
+ height = 700
16
+
17
+ [assets]
18
+ # 骨架 launcher 加载的页面(相对资产根 assets/);dev 模式自动改写到 Vite dev server
19
+ page = "ui/index.html"
20
+
21
+ [capabilities]
22
+ dir = "assets/capabilities"
23
+
24
+ [links]
25
+ # 各目标端**追加**的链接选项(拼在框架默认值之后;留空 = 只用默认)。
26
+ # 什么时候需要它:要调的原生能力在仓颉 SDK 里没有绑定,只能 FFI 直连系统库——
27
+ # 符号必须出现在最终链接那一侧,而那份 cjpm.toml 是 sync 生成的、不能手改。
28
+ # 例:鸿蒙读设备电量走系统 C API(ohbattery_info.h),写 ohos = "-lohbattery_info"
29
+ # 三端分开写是因为同一个库在三端上名字通常不同(-lfoo / foo.lib / -lfoo_ndk.z)。
30
+ desktop-linux = ""
31
+ desktop-windows = ""
32
+ ohos = ""
@@ -1,17 +1,34 @@
1
+ # 业务包:业务代码的唯一真相(RFC-002 §7.3——骨架永远是外壳,业务只有一份)。
2
+ # output-type = "static":桌面骨架(targets/desktop)与鸿蒙入口(targets/ohos/entry)
3
+ # 都以 path 依赖引用本包——同一份业务代码,多个目标各编各的产物。
1
4
  [package]
2
5
  cjc-version = "{{CJC_VERSION}}"
3
6
  name = "{{PACKAGE_NAME}}"
4
- description = "{{PROJECT_NAME}} - cj-tauri 应用"
7
+ description = "{{PROJECT_NAME}} - cj-tauri 业务包"
5
8
  version = "0.1.0"
6
9
  target-dir = ""
7
- output-type = "executable"
10
+ output-type = "static"
8
11
  compile-option = ""
9
12
  override-compile-option = ""
10
13
  link-option = ""
11
14
  package-configuration = {}
12
15
 
13
16
  [dependencies]
14
- # cj-tauri 框架本体(由 cj-tauri create 写入的本机路径)
17
+ # cj-tauri 框架本体(由 cj-tauri create 写入的本机路径;换机器重跑 create 或手改)
15
18
  cjTauri = { path = "{{FRAMEWORK_ROOT_TOML}}" }
16
19
 
17
- {{TARGET_SECTION}}
20
+ [target.x86_64-unknown-linux-gnu.bin-dependencies]
21
+ path-option = ["${CANGJIE_STDX}"]
22
+
23
+ [target.x86_64-w64-mingw32.bin-dependencies]
24
+ path-option = ["${CANGJIE_STDX}"]
25
+
26
+ [target.aarch64-linux-ohos]
27
+ # 鸿蒙目标:交叉编译工具链与 sysroot 由 DevEco 仓颉套件提供,路径全部走环境变量
28
+ # (与框架根 cjpm.toml 同口径;末尾 --dy-std 不可省,原因见框架根 toml 的鸿蒙段注释)
29
+ compile-option = "-B \"${DEVECO_CANGJIE_HOME}/build-tools/third_party/llvm/bin\" -B \"${DEVECO_OH_NATIVE_HOME}/sysroot/usr/lib/aarch64-linux-ohos\" -L \"${DEVECO_OH_NATIVE_HOME}/sysroot/usr/lib/aarch64-linux-ohos\" -L \"${DEVECO_OH_NATIVE_HOME}/llvm/lib/clang/15.0.4/lib/aarch64-linux-ohos\" -L \"${DEVECO_OH_NATIVE_HOME}/llvm/lib/aarch64-linux-ohos\" --sysroot \"${DEVECO_OH_NATIVE_HOME}/sysroot\" --dy-std"
30
+
31
+ [target.aarch64-linux-ohos.bin-dependencies]
32
+ # stdx 必须用鸿蒙版(CANGJIE_STDX_OHOS,桌面版 ABI 不通);CANGJIE_OHOS_LIBS 指 DevEco
33
+ # 套件的 api/lib/linux_ohos_aarch64_cjnative/ohos(仓颉标准库 + ohos API 绑定)
34
+ path-option = ["${CANGJIE_STDX_OHOS}", "${CANGJIE_OHOS_LIBS}", "${AARCH64_MACRO_LIBS}", "${AARCH64_KIT_LIBS}"]
@@ -1,11 +1,21 @@
1
1
  package {{PACKAGE_NAME}}
2
2
 
3
3
  import cjTauri.*
4
+ import cjTauri.plugins.menu.*
4
5
  import stdx.encoding.json.*
5
- import std.fs.File
6
6
  import std.collection.*
7
7
 
8
8
  /**
9
+ * ── 把这个骨架变成你的应用,改三处就够了 ──────────────────────────────
10
+ * ① 写命令:照下面的 GreetCommand 抄一个,并在 build() 里 register;
11
+ * ② 放行:assets/capabilities/default.json 的 commands 里加上命令名
12
+ * (只写代码不放行 = 前端拿到 command not allowed);
13
+ * ③ 改页面:assets/ui/index.html 里用 tauri.invoke 调你的命令。
14
+ * 进阶(插件 / 菜单 / 多窗口)见项目根的 docs/使用文档.md 与 docs/RFC-插件体系.md。
15
+ */
16
+
17
+ /**
18
+ * ① 写命令从这抄:实现 CommandHandler,再在下面 build() 里 register
9
19
  * greet 命令(对标 tauri command)
10
20
  * 前端:tauri.invoke("greet", { name: "..." })
11
21
  */
@@ -25,7 +35,7 @@ public class GreetCommand <: CommandHandler {
25
35
  }
26
36
 
27
37
  /**
28
- * 定时器命令:启动后台线程,每秒向后端推一个 tick 事件(验证 仓颉 → JS 通道)
38
+ * 定时器命令:启动后台线程,每秒向前端推一个 tick 事件(验证 仓颉 → JS 通道)
29
39
  * 前端:tauri.listen("tick", cb) + tauri.invoke("timer")
30
40
  */
31
41
  public class TimerCommand <: CommandHandler {
@@ -67,22 +77,25 @@ func demoMenu(): MenuModel {
67
77
  return MenuModel(items)
68
78
  }
69
79
 
70
- main(): Int64 {
71
- // 1) 装配应用(对标 tauri::Builder):窗口配置 + 注册命令
72
- // 能力清单由框架在 run() 时自动扫描 capabilities/ 目录(对标 Tauri 的 capabilities 目录)
73
- let app = TauriApp()
74
- .window(WindowConfig("cj-tauri 应用", 1000, 700))
75
- .register("greet", GreetCommand())
76
- .register("timer", TimerCommand())
80
+ /**
81
+ * 业务装配点(RFC-002 §4.1):骨架的 launcher(targets/ 下各目标的 src)调用它取 AppSpec。
82
+ *
83
+ * 零平台知识:不碰宿主、不知道页面文件路径、不知道能力目录——那些由清单
84
+ * (cj-tauri.toml)决定,launcher 按清单覆盖(page/window/assets/capabilities)。
85
+ * build() 负责业务自己的部分:命令注册、菜单、插件。
86
+ */
87
+ public func build(): AppSpec {
88
+ return AppSpec()
89
+ .window(WindowConfig("{{PROJECT_NAME}}", 1000, 700))
77
90
  // menu 插件:给前端挂 window.__CJ_TAURI__.menu.setEnabled / setChecked
78
91
  // (插件只声明「我提供什么」,**不自动放行**——要能调,就在 capabilities 里引用
79
92
  // permissions: ["menu:state"],或逐条写 commands)
80
93
  .plugin(MenuPlugin())
81
- // 菜单栏必须在 run() 之前挂:预置类宿主能力要赶在页面加载前定稿
82
- .setMenu(demoMenu())
83
-
84
- // 2) 载入前端页面并启动(阻塞至窗口关闭)
85
- let html = String.fromUtf8(File.readFrom("ui/index.html"))
86
- app.run(html)
87
- return 0
94
+ .wire({ app =>
95
+ // ① 新命令在这里 register;② 别忘了去 capabilities/default.json 放行
96
+ app.register("greet", GreetCommand())
97
+ app.register("timer", TimerCommand())
98
+ // 菜单栏必须在 run 之前挂:预置类宿主能力要赶在页面加载前定稿
99
+ app.setMenu(demoMenu())
100
+ })
88
101
  }
@@ -1,67 +1,56 @@
1
1
  # {{PROJECT_NAME}}
2
2
 
3
- `cj-tauri create {{PROJECT_NAME}} --template react` 生成的工程:**仓颉后端 + React 18 / Vite 前端**。
3
+ 基于 [cj-tauri]({{FRAMEWORK_ROOT}})(仓颉版 Tauri)+ React 18 + Vite 的应用:**仓颉后端 + 系统 WebView 前端**,
4
+ 通过 `window.__CJ_TAURI__` 做 invoke/listen 双向 IPC,并由 capabilities 清单做最小权限管控。
4
5
 
5
- 目录结构:
6
+ ## 目录结构(一份业务代码,骨架按目标派生)
6
7
 
7
8
  ```
8
9
  {{PROJECT_NAME}}/
9
- src/main.cj 后端入口(窗口 + 命令注册 + 页面来源选择)
10
- capabilities/ 能力清单(哪些命令 / 事件允许被前端调用)
11
- ui/ 前端工程(Vite + React)
12
- index.html
13
- vite.config.js
14
- src/App.jsx
15
- src/main.jsx
16
- cjpm.toml 仓颉包配置(cjTauri 依赖路径由 create 写入本机绝对路径)
10
+ ├── cj-tauri.toml # 应用清单——单一真相(id/version/窗口/资产/能力目录)
11
+ ├── cjpm.toml # 业务包(static 库;骨架以 path 依赖引用)
12
+ ├── src/main.cj # 业务装配点 build(): AppSpec(零平台知识)
13
+ ├── assets/
14
+ │ ├── ui/ # React 18 + Vite 前端工程(package.json / vite.config.js / src/)
15
+ │ └── capabilities/default.json # 能力白名单(命令 / 事件 / 权限集)
16
+ └── targets/ # cj-tauri sync 生成的骨架(勿手改;check 判漂移)
17
+ ├── desktop/ # 桌面可执行(launcher 调 build())
18
+ └── ohos/ # 鸿蒙 hap 工程(DevEco + build-hap.sh)
17
19
  ```
18
20
 
19
- ## 开发:`cj-tauri dev`(热重载)
21
+ ## 首次运行(dev,热更新)
20
22
 
21
23
  ```bash
22
- cj-tauri dev
24
+ cd assets/ui && npm install # 前端依赖(需要 Node.js)
25
+ cd ../.. && cj-tauri sync # 派生 targets/ 骨架
26
+ cj-tauri dev # 起 Vite dev server(改 .jsx 保存即刷新)+ 编译 + 启动窗口
23
27
  ```
24
28
 
25
- `dev` 依次做:桥已构建则跳过 → 若 `ui/node_modules` 不存在则 `npm install` → 后台起 Vite dev server
26
- (`127.0.0.1:5173`)→ 探活 → 以环境变量 `CJ_TAURI_DEV_URL` 启动应用。页面来自真实 URL,所以:
27
-
28
- - 改 `ui/src/**.jsx` / `.js`:保存后页面自己更新,**应用不重启**(Vite HMR);
29
- - 改后端 `src/*.cj`:需要重新 `cj-tauri dev`(框架不承诺后端进程内热替换);
30
- - 应用窗口关闭后会一并收掉 dev server。
31
-
32
- 想手动控制前端时,也可以自己起 dev server 再启动应用:
33
-
34
- ```bash
35
- cd ui && npm run dev # 另一个终端
36
- CJ_TAURI_DEV_URL=http://127.0.0.1:5173/ cj-tauri run
37
- ```
38
-
39
- ## 发布:打成一个 HTML 文件
29
+ ## 发布构建
40
30
 
41
31
  ```bash
42
- cd ui && npm install && npm run build # 产出 ui/dist/index.html(js/css/图片全内联)
43
- cd .. && cj-tauri build # 构建桥 + cjpm build
44
- cj-tauri run # 没有 CJ_TAURI_DEV_URL 时读 ui/dist/index.html
32
+ cj-tauri build # 先在 assets/ui 跑 npm run build,再编后端
33
+ cj-tauri run
45
34
  ```
46
35
 
47
- `vite-plugin-singlefile` 保证产物就是**一个** `index.html`,与 `app` 模板的单文件模式等价。
36
+ `vite.config.js` 用 vite-plugin-singlefile:产物是 `assets/ui/dist/index.html`
37
+ (js/css 内联、无外部依赖)——正是清单 `[assets] page` 指向的页面。
48
38
 
49
- ## 前后端怎么通信
39
+ ## 鸿蒙端(PC / 2in1)
50
40
 
51
- 前端拿到的是 `window.__CJ_TAURI__`(与 Tauri 的 `@tauri-apps/api` 同形):
52
-
53
- ```js
54
- window.__CJ_TAURI__.invoke('greet', { name: '仓颉' }); // → Promise
55
- window.__CJ_TAURI__.listen('tick', (payload) => { /* ... */ });
56
- window.__CJ_TAURI__.reload(); // 整页刷新
41
+ ```bash
42
+ export CANGJIE_STDX_OHOS=<鸿蒙版 stdx>/linux_ohos_aarch64_cjnative/dynamic/stdx
43
+ cd targets/ohos && bash build-hap.sh # 编 hap
44
+ cd targets/ohos && bash build-hap.sh --install # 编完装到设备并拉起
57
45
  ```
58
46
 
59
- 能调哪些命令、能收哪些事件,由 `capabilities/default.json` 决定;没声明的命令一律被拒
60
- (`command not allowed: xxx`)。
47
+ 提示:模板不带签名证书——首次在 DevEco 里 File → Project Structure → Signing Configs
48
+ 勾「Automatically generate signature」(要登录华为账号);不签名只能编出
49
+ *-unsigned.hap,装不进设备。
61
50
 
62
- ## 和 vue 模板的差别
51
+ ## 命令与能力
63
52
 
64
- 只有 `ui/` 里换成了 React:`@vitejs/plugin-react` 替掉 `@vitejs/plugin-vue`,入口是 `src/main.jsx`、
65
- 根组件是 `src/App.jsx`;Vite 配置、`src/main.cj`、能力清单、`cj-tauri dev` 的用法完全一致。
66
- `src/main.jsx` 里**没有**用 `React.StrictMode`:开发模式下它会把 effect 跑两遍,
67
- 而这个模板的 effect 里要调 `invoke` / `listen`,双跑容易让人误以为桥重复投递。
53
+ 命令在 `src/main.cj`(`greet` / `timer` + 演示菜单),白名单在 `assets/capabilities/default.json`——
54
+ 两边必须对齐:`cj-tauri check` 的三方比对会交叉核对「能力声明 × 插件自描述 × 实际装配」。
55
+ 插件在某端没有实现时(如 shell/sqlite 在鸿蒙端),骨架照样编得过,运行期调用得到
56
+ 可照做的「端不支持」错误(RFC-002 §4.6.4 的 P-1 桩)。
@@ -1,25 +1,25 @@
1
- <!DOCTYPE html>
2
- <html lang="zh-CN">
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1" />
6
- <title>{{PROJECT_NAME}}</title>
7
- <style>
8
- /* 整页基础样式:组件样式在 App.css,这里给页面底色 + 让内容整列居中,
9
- 调色板与零 Node 模板、examples/hello 一致(#16161d 深色底)。 */
10
- :root { color-scheme: dark; }
11
- /* min-height(不是 height)+ 居中:内容比视口高时 body 跟着长,顶部不会被裁掉。 */
12
- body { box-sizing: border-box; margin: 0; padding: 24px; min-height: 100vh;
13
- display: flex; flex-direction: column; align-items: center; justify-content: center;
14
- background: #16161d; color: #e6e6e6;
15
- font-family: system-ui, -apple-system, "Segoe UI", sans-serif; }
16
- /* 标题 / 提示 / 卡片同一列居中:光靠 body 的 align-items 不够——挂载点只有一个子节点,
17
- 提示行(页面来源、桥状态)很长时会把整列撑宽,卡片反而贴在左边。 */
18
- #root { width: 100%; display: flex; flex-direction: column; align-items: center; }
19
- </style>
20
- </head>
21
- <body>
22
- <div id="root"></div>
23
- <script type="module" src="/src/main.jsx"></script>
24
- </body>
25
- </html>
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>{{PROJECT_NAME}}</title>
7
+ <style>
8
+ /* 整页基础样式:组件样式在 App.css,这里给页面底色 + 让内容整列居中,
9
+ 调色板与零 Node 模板、examples/hello 一致(#16161d 深色底)。 */
10
+ :root { color-scheme: dark; }
11
+ /* min-height(不是 height)+ 居中:内容比视口高时 body 跟着长,顶部不会被裁掉。 */
12
+ body { box-sizing: border-box; margin: 0; padding: 24px; min-height: 100vh;
13
+ display: flex; flex-direction: column; align-items: center; justify-content: center;
14
+ background: #16161d; color: #e6e6e6;
15
+ font-family: system-ui, -apple-system, "Segoe UI", sans-serif; }
16
+ /* 标题 / 提示 / 卡片同一列居中:光靠 body 的 align-items 不够——挂载点只有一个子节点,
17
+ 提示行(页面来源、桥状态)很长时会把整列撑宽,卡片反而贴在左边。 */
18
+ #root { width: 100%; display: flex; flex-direction: column; align-items: center; }
19
+ </style>
20
+ </head>
21
+ <body>
22
+ <div id="root"></div>
23
+ <script type="module" src="/src/main.jsx"></script>
24
+ </body>
25
+ </html>
@@ -1,67 +1,67 @@
1
- /* React 模板的示例样式:与 app-vue 模板的 <style scoped> 逐条对齐(class 名相同)。
2
- Vue 靠 SFC 自带样式块,React 没有 SFC,所以走「JS 里 import 一个 css」——Vite 原生支持。 */
3
- h1 {
4
- color: #7ce7ff;
5
- }
6
- .hint {
7
- font-size: 13px;
8
- opacity: 0.8;
9
- }
10
- .card {
11
- background: #16213e;
12
- border-radius: 12px;
13
- padding: 20px 24px;
14
- width: 560px;
15
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
16
- }
17
- .row {
18
- display: flex;
19
- gap: 8px;
20
- }
21
- input {
22
- flex: 1;
23
- padding: 8px 12px;
24
- border: none;
25
- border-radius: 8px;
26
- background: #0f3460;
27
- color: #eee;
28
- }
29
- button {
30
- padding: 8px 14px;
31
- border: none;
32
- border-radius: 8px;
33
- background: #e94560;
34
- color: #fff;
35
- cursor: pointer;
36
- }
37
- button.ghost {
38
- background: #24476e;
39
- }
40
- button:hover {
41
- opacity: 0.85;
42
- }
43
- .out {
44
- margin-top: 14px;
45
- font-size: 16px;
46
- }
47
- .tick {
48
- margin-top: 6px;
49
- font-size: 13px;
50
- color: #8be9fd;
51
- }
52
- .chk {
53
- margin-top: 12px;
54
- font-size: 13px;
55
- opacity: 0.85;
56
- display: flex;
57
- align-items: center;
58
- gap: 6px;
59
- }
60
- .chk input {
61
- flex: none;
62
- }
63
- .tip {
64
- margin-top: 14px;
65
- font-size: 12px;
66
- opacity: 0.7;
67
- }
1
+ /* React 模板的示例样式:与 app-vue 模板的 <style scoped> 逐条对齐(class 名相同)。
2
+ Vue 靠 SFC 自带样式块,React 没有 SFC,所以走「JS 里 import 一个 css」——Vite 原生支持。 */
3
+ h1 {
4
+ color: #7ce7ff;
5
+ }
6
+ .hint {
7
+ font-size: 13px;
8
+ opacity: 0.8;
9
+ }
10
+ .card {
11
+ background: #16213e;
12
+ border-radius: 12px;
13
+ padding: 20px 24px;
14
+ width: 560px;
15
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
16
+ }
17
+ .row {
18
+ display: flex;
19
+ gap: 8px;
20
+ }
21
+ input {
22
+ flex: 1;
23
+ padding: 8px 12px;
24
+ border: none;
25
+ border-radius: 8px;
26
+ background: #0f3460;
27
+ color: #eee;
28
+ }
29
+ button {
30
+ padding: 8px 14px;
31
+ border: none;
32
+ border-radius: 8px;
33
+ background: #e94560;
34
+ color: #fff;
35
+ cursor: pointer;
36
+ }
37
+ button.ghost {
38
+ background: #24476e;
39
+ }
40
+ button:hover {
41
+ opacity: 0.85;
42
+ }
43
+ .out {
44
+ margin-top: 14px;
45
+ font-size: 16px;
46
+ }
47
+ .tick {
48
+ margin-top: 6px;
49
+ font-size: 13px;
50
+ color: #8be9fd;
51
+ }
52
+ .chk {
53
+ margin-top: 12px;
54
+ font-size: 13px;
55
+ opacity: 0.85;
56
+ display: flex;
57
+ align-items: center;
58
+ gap: 6px;
59
+ }
60
+ .chk input {
61
+ flex: none;
62
+ }
63
+ .tip {
64
+ margin-top: 14px;
65
+ font-size: 12px;
66
+ opacity: 0.7;
67
+ }