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,176 +1,176 @@
1
- <script setup>
2
- import { onMounted, ref } from 'vue';
3
-
4
- const name = ref('world');
5
- const result = ref('等待 invoke…');
6
- const tick = ref('');
7
- const menuMsg = ref('');
8
- const sidebar = ref(true);
9
- const href = ref('');
10
- const bridgeOk = ref(false);
11
-
12
- // 桥(window.__CJ_TAURI__)由宿主注入,注入时机随平台/页面来源而异:Linux 宿主注入在文档开始,
13
- // 但发行态单文件里的内联 <script type="module"> 解析完就执行,谁先谁后与加载方式有关。
14
- // 所以统一「等桥出现再初始化」,不要在模块作用域直接读。
15
- let bridge = null;
16
-
17
- function waitForBridge(timeoutMs = 3000) {
18
- return new Promise((resolve) => {
19
- const t0 = Date.now();
20
- const tick = () => {
21
- if (window.__CJ_TAURI__) return resolve(window.__CJ_TAURI__);
22
- if (Date.now() - t0 >= timeoutMs) return resolve(null);
23
- setTimeout(tick, 20);
24
- };
25
- tick();
26
- });
27
- }
28
-
29
- onMounted(async () => {
30
- href.value = location.href;
31
- bridge = await waitForBridge();
32
- if (!bridge) {
33
- result.value = '未找到 window.__CJ_TAURI__';
34
- return;
35
- }
36
- bridgeOk.value = true;
37
- bridge.listen('tick', (payload) => {
38
- tick.value = '事件 tick #' + payload.n + ' 来自仓颉后端';
39
- });
40
- // 原生菜单 → 页面(capabilities 里要声明 menu:click)
41
- bridge.listen('menu:click', (p) => {
42
- menuMsg.value = '菜单被点: ' + p.id + '(enabled=' + p.enabled + ', checked=' + p.checked + ')';
43
- });
44
- });
45
-
46
- async function greet() {
47
- if (!bridge) {
48
- result.value = '桥未就绪';
49
- return;
50
- }
51
- try {
52
- const data = await bridge.invoke('greet', { name: name.value });
53
- result.value = 'invoke OK: ' + data;
54
- } catch (err) {
55
- result.value = 'invoke FAIL: ' + err.message;
56
- }
57
- }
58
-
59
- async function startTimer() {
60
- if (bridge) await bridge.invoke('timer');
61
- }
62
-
63
- function reload() {
64
- if (bridge) bridge.reload();
65
- }
66
-
67
- // 页面 → 原生菜单:menu 插件的前端 shim(window.__CJ_TAURI__.menu,注入在 document start)
68
- async function toggleSidebar(e) {
69
- const checked = e.target.checked;
70
- if (!bridge || !bridge.menu) {
71
- result.value = '未注入 menu 插件 shim(页面来自 runUrl 时插件 JS 不在本进程)';
72
- return;
73
- }
74
- try {
75
- await bridge.menu.setChecked({ id: 'view.sidebar', checked });
76
- result.value = '原生菜单「侧边栏」已同步为 ' + checked;
77
- } catch (err) {
78
- result.value = 'menu.setChecked FAIL: ' + err.message;
79
- }
80
- }
81
- </script>
82
-
83
- <template>
84
- <h1>cj-tauri · Vue 3 + Vite</h1>
85
- <p class="hint">
86
- 页面来源:<code>{{ href }}</code><br />
87
- 桥状态:{{ bridgeOk ? '已注入 __CJ_TAURI__' : '未注入' }}
88
- </p>
89
-
90
- <div class="card">
91
- <div class="row">
92
- <input v-model="name" placeholder="输入名字" />
93
- <button @click="greet">greet</button>
94
- <button class="ghost" @click="startTimer">timer</button>
95
- <button class="ghost" @click="reload">reload</button>
96
- </div>
97
- <div class="out">{{ result }}</div>
98
- <div class="tick">{{ tick }}</div>
99
- <div class="tick">{{ menuMsg }}</div>
100
- <div class="chk">
101
- <input type="checkbox" :checked="sidebar" @change="toggleSidebar" />
102
- <span>侧边栏(对应原生菜单「视图 → 侧边栏」)</span>
103
- </div>
104
- <p class="tip">
105
- 改这个文件(<code>ui/src/App.vue</code>)保存,页面会在不重启应用的情况下更新。
106
- </p>
107
- </div>
108
- </template>
109
-
110
- <style scoped>
111
- h1 {
112
- color: #7ce7ff;
113
- }
114
- .hint {
115
- font-size: 13px;
116
- opacity: 0.8;
117
- }
118
- .card {
119
- background: #16213e;
120
- border-radius: 12px;
121
- padding: 20px 24px;
122
- width: 560px;
123
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
124
- }
125
- .row {
126
- display: flex;
127
- gap: 8px;
128
- }
129
- input {
130
- flex: 1;
131
- padding: 8px 12px;
132
- border: none;
133
- border-radius: 8px;
134
- background: #0f3460;
135
- color: #eee;
136
- }
137
- button {
138
- padding: 8px 14px;
139
- border: none;
140
- border-radius: 8px;
141
- background: #e94560;
142
- color: #fff;
143
- cursor: pointer;
144
- }
145
- button.ghost {
146
- background: #24476e;
147
- }
148
- button:hover {
149
- opacity: 0.85;
150
- }
151
- .out {
152
- margin-top: 14px;
153
- font-size: 16px;
154
- }
155
- .tick {
156
- margin-top: 6px;
157
- font-size: 13px;
158
- color: #8be9fd;
159
- }
160
- .chk {
161
- margin-top: 12px;
162
- font-size: 13px;
163
- opacity: 0.85;
164
- display: flex;
165
- align-items: center;
166
- gap: 6px;
167
- }
168
- .chk input {
169
- flex: none;
170
- }
171
- .tip {
172
- margin-top: 14px;
173
- font-size: 12px;
174
- opacity: 0.7;
175
- }
176
- </style>
1
+ <script setup>
2
+ import { onMounted, ref } from 'vue';
3
+
4
+ const name = ref('world');
5
+ const result = ref('等待 invoke…');
6
+ const tick = ref('');
7
+ const menuMsg = ref('');
8
+ const sidebar = ref(true);
9
+ const href = ref('');
10
+ const bridgeOk = ref(false);
11
+
12
+ // 桥(window.__CJ_TAURI__)由宿主注入,注入时机随平台/页面来源而异:Linux 宿主注入在文档开始,
13
+ // 但发行态单文件里的内联 <script type="module"> 解析完就执行,谁先谁后与加载方式有关。
14
+ // 所以统一「等桥出现再初始化」,不要在模块作用域直接读。
15
+ let bridge = null;
16
+
17
+ function waitForBridge(timeoutMs = 3000) {
18
+ return new Promise((resolve) => {
19
+ const t0 = Date.now();
20
+ const tick = () => {
21
+ if (window.__CJ_TAURI__) return resolve(window.__CJ_TAURI__);
22
+ if (Date.now() - t0 >= timeoutMs) return resolve(null);
23
+ setTimeout(tick, 20);
24
+ };
25
+ tick();
26
+ });
27
+ }
28
+
29
+ onMounted(async () => {
30
+ href.value = location.href;
31
+ bridge = await waitForBridge();
32
+ if (!bridge) {
33
+ result.value = '未找到 window.__CJ_TAURI__';
34
+ return;
35
+ }
36
+ bridgeOk.value = true;
37
+ bridge.listen('tick', (payload) => {
38
+ tick.value = '事件 tick #' + payload.n + ' 来自仓颉后端';
39
+ });
40
+ // 原生菜单 → 页面(capabilities 里要声明 menu:click)
41
+ bridge.listen('menu:click', (p) => {
42
+ menuMsg.value = '菜单被点: ' + p.id + '(enabled=' + p.enabled + ', checked=' + p.checked + ')';
43
+ });
44
+ });
45
+
46
+ async function greet() {
47
+ if (!bridge) {
48
+ result.value = '桥未就绪';
49
+ return;
50
+ }
51
+ try {
52
+ const data = await bridge.invoke('greet', { name: name.value });
53
+ result.value = 'invoke OK: ' + data;
54
+ } catch (err) {
55
+ result.value = 'invoke FAIL: ' + err.message;
56
+ }
57
+ }
58
+
59
+ async function startTimer() {
60
+ if (bridge) await bridge.invoke('timer');
61
+ }
62
+
63
+ function reload() {
64
+ if (bridge) bridge.reload();
65
+ }
66
+
67
+ // 页面 → 原生菜单:menu 插件的前端 shim(window.__CJ_TAURI__.menu,注入在 document start)
68
+ async function toggleSidebar(e) {
69
+ const checked = e.target.checked;
70
+ if (!bridge || !bridge.menu) {
71
+ result.value = '未注入 menu 插件 shim(页面来自 runUrl 时插件 JS 不在本进程)';
72
+ return;
73
+ }
74
+ try {
75
+ await bridge.menu.setChecked({ id: 'view.sidebar', checked });
76
+ result.value = '原生菜单「侧边栏」已同步为 ' + checked;
77
+ } catch (err) {
78
+ result.value = 'menu.setChecked FAIL: ' + err.message;
79
+ }
80
+ }
81
+ </script>
82
+
83
+ <template>
84
+ <h1>cj-tauri · Vue 3 + Vite</h1>
85
+ <p class="hint">
86
+ 页面来源:<code>{{ href }}</code><br />
87
+ 桥状态:{{ bridgeOk ? '已注入 __CJ_TAURI__' : '未注入' }}
88
+ </p>
89
+
90
+ <div class="card">
91
+ <div class="row">
92
+ <input v-model="name" placeholder="输入名字" />
93
+ <button @click="greet">greet</button>
94
+ <button class="ghost" @click="startTimer">timer</button>
95
+ <button class="ghost" @click="reload">reload</button>
96
+ </div>
97
+ <div class="out">{{ result }}</div>
98
+ <div class="tick">{{ tick }}</div>
99
+ <div class="tick">{{ menuMsg }}</div>
100
+ <div class="chk">
101
+ <input type="checkbox" :checked="sidebar" @change="toggleSidebar" />
102
+ <span>侧边栏(对应原生菜单「视图 → 侧边栏」)</span>
103
+ </div>
104
+ <p class="tip">
105
+ 改这个文件(<code>ui/src/App.vue</code>)保存,页面会在不重启应用的情况下更新。
106
+ </p>
107
+ </div>
108
+ </template>
109
+
110
+ <style scoped>
111
+ h1 {
112
+ color: #7ce7ff;
113
+ }
114
+ .hint {
115
+ font-size: 13px;
116
+ opacity: 0.8;
117
+ }
118
+ .card {
119
+ background: #16213e;
120
+ border-radius: 12px;
121
+ padding: 20px 24px;
122
+ width: 560px;
123
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
124
+ }
125
+ .row {
126
+ display: flex;
127
+ gap: 8px;
128
+ }
129
+ input {
130
+ flex: 1;
131
+ padding: 8px 12px;
132
+ border: none;
133
+ border-radius: 8px;
134
+ background: #0f3460;
135
+ color: #eee;
136
+ }
137
+ button {
138
+ padding: 8px 14px;
139
+ border: none;
140
+ border-radius: 8px;
141
+ background: #e94560;
142
+ color: #fff;
143
+ cursor: pointer;
144
+ }
145
+ button.ghost {
146
+ background: #24476e;
147
+ }
148
+ button:hover {
149
+ opacity: 0.85;
150
+ }
151
+ .out {
152
+ margin-top: 14px;
153
+ font-size: 16px;
154
+ }
155
+ .tick {
156
+ margin-top: 6px;
157
+ font-size: 13px;
158
+ color: #8be9fd;
159
+ }
160
+ .chk {
161
+ margin-top: 12px;
162
+ font-size: 13px;
163
+ opacity: 0.85;
164
+ display: flex;
165
+ align-items: center;
166
+ gap: 6px;
167
+ }
168
+ .chk input {
169
+ flex: none;
170
+ }
171
+ .tip {
172
+ margin-top: 14px;
173
+ font-size: 12px;
174
+ opacity: 0.7;
175
+ }
176
+ </style>
@@ -0,0 +1,33 @@
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 加载的页面:Vite 打出来的单文件产物(vite-plugin-singlefile 内联 js/css)。
19
+ # dev 模式自动改写到 Vite dev server(热更新);发布构建才用这个产物。
20
+ page = "ui/dist/index.html"
21
+
22
+ [capabilities]
23
+ dir = "assets/capabilities"
24
+
25
+ [links]
26
+ # 各目标端**追加**的链接选项(拼在框架默认值之后;留空 = 只用默认)。
27
+ # 什么时候需要它:要调的原生能力在仓颉 SDK 里没有绑定,只能 FFI 直连系统库——
28
+ # 符号必须出现在最终链接那一侧,而那份 cjpm.toml 是 sync 生成的、不能手改。
29
+ # 例:鸿蒙读设备电量走系统 C API(ohbattery_info.h),写 ohos = "-lohbattery_info"
30
+ # 三端分开写是因为同一个库在三端上名字通常不同(-lfoo / foo.lib / -lfoo_ndk.z)。
31
+ desktop-linux = ""
32
+ desktop-windows = ""
33
+ 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 应用(Vue 3 + Vite 前端)"
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,8 +1,8 @@
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.*
6
6
  import std.collection.*
7
7
 
8
8
  /**
@@ -25,7 +25,7 @@ public class GreetCommand <: CommandHandler {
25
25
  }
26
26
 
27
27
  /**
28
- * 定时器命令:启动后台线程,每秒向后端推一个 tick 事件(验证 仓颉 → JS 通道)
28
+ * 定时器命令:启动后台线程,每秒向前端推一个 tick 事件(验证 仓颉 → JS 通道)
29
29
  * 前端:tauri.listen("tick", cb) + tauri.invoke("timer")
30
30
  */
31
31
  public class TimerCommand <: CommandHandler {
@@ -67,36 +67,25 @@ func demoMenu(): MenuModel {
67
67
  return MenuModel(items)
68
68
  }
69
69
 
70
- main(): Int64 {
71
- // 1) 装配应用(对标 tauri::Builder):窗口配置 + 注册命令
72
- // 能力清单由框架在 run() 时自动扫描 capabilities/ 目录(对标 Tauri 的 capabilities 目录)
73
- let app = TauriApp()
70
+ /**
71
+ * 业务装配点(RFC-002 §4.1):骨架的 launcher(targets/ 下各目标的 src)调用它取 AppSpec。
72
+ *
73
+ * 零平台知识:不碰宿主、不知道页面文件路径、不知道能力目录——那些由清单
74
+ * (cj-tauri.toml)决定,launcher 按清单覆盖(page/window/assets/capabilities)。
75
+ * dev 模式页面来自 Vite dev server(框架按 CJ_TAURI_DEV_URL 自动改写),
76
+ * 发布构建加载 assets/ui/dist 的单文件产物——两种跑法业务代码完全一致。
77
+ */
78
+ public func build(): AppSpec {
79
+ return AppSpec()
74
80
  .window(WindowConfig("{{PROJECT_NAME}}", 1000, 700))
75
- .register("greet", GreetCommand())
76
- .register("timer", TimerCommand())
77
81
  // menu 插件:给前端挂 window.__CJ_TAURI__.menu.setEnabled / setChecked
78
82
  // (插件只声明「我提供什么」,**不自动放行**——要能调,就在 capabilities 里引用
79
83
  // permissions: ["menu:state"],或逐条写 commands)
80
84
  .plugin(MenuPlugin())
81
- // 菜单栏必须在 run() / runUrl() 之前挂:预置类宿主能力要赶在页面加载前定稿
82
- .setMenu(demoMenu())
83
-
84
- // 2) 页面来源二选一,对应本模板的两种跑法:
85
- // dev : cj-tauri dev 起了 Vite dev server 并注入 CJ_TAURI_DEV_URL
86
- // → 页面来自真实 URL,改 .vue 保存即热更新,应用不用重启
87
- // 发布 : 读 Vite 打出来的单文件 ui/dist/index.html(js/css 已内联,无外部依赖)
88
- if (let Some(url) <- TauriApp.devUrl()) {
89
- eprintln("[app] dev 模式,页面来自 ${url}")
90
- app.runUrl(url)
91
- } else {
92
- let dist = "ui/dist/index.html"
93
- if (!exists(dist)) {
94
- eprintln("[app] 找不到 ${dist}")
95
- eprintln(" 开发: 在项目根跑 cj-tauri dev(会自动 npm install + 起 dev server)")
96
- eprintln(" 发布: cd ui && npm run build")
97
- return 1
98
- }
99
- app.run(String.fromUtf8(File.readFrom(dist)))
100
- }
101
- return 0
85
+ .wire({ app =>
86
+ app.register("greet", GreetCommand())
87
+ app.register("timer", TimerCommand())
88
+ // 菜单栏必须在 run 之前挂:预置类宿主能力要赶在页面加载前定稿
89
+ app.setMenu(demoMenu())
90
+ })
102
91
  }
@@ -46,6 +46,11 @@ bash build-hap.sh --install
46
46
 
47
47
  改了鸿蒙侧仓颉代码却没生效时:`bash build-hap.sh --clean`(hvigor 与框架 cjpm 各有一份增量缓存)。
48
48
 
49
+ **DevEco IDE 内点 Build 不经过 build-hap.sh**:assets 自动同步段(工程根 assets/ → rawfile)在
50
+ 命令行入口里,IDE 构建不会执行——在 IDE 里改了 `assets/ui` 或 `assets/capabilities` 后,
51
+ 要么回命令行跑一次 `bash build-hap.sh`,要么重跑 `cj-tauri sync ohos`;直接 IDE 构建装出来的是旧页
52
+ (判据:hap 内 `unzip -p *.hap resources/rawfile/ui/index.html` 不含你的改动)。
53
+
49
54
  ## 签名
50
55
 
51
56
  模板**不带证书**(调试证书由每台机器的 DevEco 本机生成、与华为账号绑定,不该入库)。
@@ -154,6 +154,21 @@ if [ "$do_clean" = "1" ]; then
154
154
  rm -rf "$ROOT_DIR/entry/build"
155
155
  fi
156
156
 
157
+ # assets 同步:唯一真相在工程根 assets/(RFC-002 §7),构建前拷进骨架 rawfile——
158
+ # 页面与能力清单是 hap 的 rawfile 真文件,只改 assets 不 sync 直接构建会装出**旧页**:
159
+ # 页面自检照跑、改动静默丢失(2026-10-25 真机实测,探针行全无、又无失败行)。
160
+ # 有 sync 生成的工程根(cj-tauri.toml 在上三级)才做这一步;手工工程自行维护 rawfile。
161
+ APP_ROOT="$ROOT_DIR/../.."
162
+ if [ -f "$APP_ROOT/cj-tauri.toml" ] && [ -d "$APP_ROOT/assets" ]; then
163
+ RAWFILE="$ROOT_DIR/entry/src/main/resources/rawfile"
164
+ mkdir -p "$RAWFILE/ui" "$RAWFILE/capabilities"
165
+ # 先清再拷:cp -r src dst 在 dst 已存在时会把 src 拷成 dst/ui/ui/(嵌套目录),页面静默变旧
166
+ rm -rf "$RAWFILE/ui" "$RAWFILE/capabilities"
167
+ cp -r "$APP_ROOT/assets/ui" "$RAWFILE/ui"
168
+ cp -r "$APP_ROOT/assets/capabilities" "$RAWFILE/capabilities"
169
+ echo "[ohos] assets 已从工程根同步到 rawfile(ui/ + capabilities/)"
170
+ fi
171
+
157
172
  # **必须 `--no-daemon`**:hvigor 的常驻 daemon 里 CompileCangjie 用的是它启动时那份 env,
158
173
  # 本脚本 export 的 PATH / CANGJIE_HOME 根本进不去(表现是「手跑 cjpm 成功、hvigor 一跑就 opt 崩」)。
159
174
  mkdir -p .buildlog
@@ -25,6 +25,14 @@
25
25
 
26
26
  [target.aarch64-linux-ohos]
27
27
  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\""
28
+ # -lpasteboard -ludmf:框架的剪贴板宿主能力(`src/clipboard_bridge.cj` 鸿蒙段)用原生
29
+ # `OH_Pasteboard_*` / `OH_Udmf*` / `OH_UdsPlainText_*` C API。两组符号分属两个库
30
+ # (`OH_Pasteboard_*` 在 libpasteboard、其余在 libudmf),所以两个都要给。
31
+ # 最终链接发生在**本模块**(output-type = dynamic),所以开关必须在这儿落地——
32
+ # 只写在框架自己的 cjpm.toml 里不生效,缺了模块里就留一堆 `U OH_Pasteboard_*`,
33
+ # 表现是应用启动即 SIGSEGV(模块加载期解析不到符号)。
34
+ # 库在同 sysroot 的 `usr/lib/aarch64-linux-ohos`,上面 compile-option 的 `-L` 已指着它。
35
+ link-option = "-lpasteboard -ludmf"
28
36
  [target.aarch64-linux-ohos.bin-dependencies]
29
37
  # 鸿蒙版 stdx:这里写**相对路径**,指向工程根上的 `stdx` 联接(build-hap.sh 用
30
38
  # CANGJIE_STDX_OHOS 建,不入库)。两条实测依据: