cj-tauri 1.1.2 → 2.0.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 +64 -18
- package/cjpm.toml +52 -52
- package/cli/cjpm.toml +10 -1
- package/cli/src/doctor.cj +4 -2
- package/cli/src/main.cj +11 -3
- package/cli/src/manifest.cj +558 -0
- package/cli/src/project.cj +38 -22
- package/cli/src/scaffold.cj +369 -361
- package/cli/src/sync.cj +526 -0
- package/cli/src/util.cj +168 -159
- package/cli/templates/app/README.md +48 -80
- package/cli/templates/app/{capabilities → assets/capabilities}/default.json +7 -7
- package/cli/templates/app/{ui → assets/ui}/index.html +118 -118
- package/cli/templates/app/cj-tauri.toml +22 -0
- package/cli/templates/app/cjpm.toml +34 -17
- package/cli/templates/app/src/main.cj +90 -88
- package/cli/templates/app-react/README.md +56 -67
- package/cli/templates/app-react/{capabilities → assets/capabilities}/default.json +7 -7
- package/cli/templates/app-react/{ui → assets/ui}/package.json +19 -19
- package/cli/templates/app-react/{ui → assets/ui}/src/main.jsx +6 -6
- package/cli/templates/app-react/{ui → assets/ui}/vite.config.js +24 -24
- package/cli/templates/app-react/cj-tauri.toml +23 -0
- package/cli/templates/app-react/cjpm.toml +34 -17
- package/cli/templates/app-react/src/main.cj +91 -102
- package/cli/templates/app-vue/README.md +56 -60
- package/cli/templates/app-vue/{capabilities → assets/capabilities}/default.json +7 -7
- package/cli/templates/app-vue/{ui → assets/ui}/package.json +18 -18
- package/cli/templates/app-vue/{ui → assets/ui}/src/main.js +4 -4
- package/cli/templates/app-vue/{ui → assets/ui}/vite.config.js +24 -24
- package/cli/templates/app-vue/cj-tauri.toml +23 -0
- package/cli/templates/app-vue/cjpm.toml +34 -17
- package/cli/templates/app-vue/src/main.cj +91 -102
- package/cli/templates/{ohos-pc → ohos-skeleton}/AppScope/app.json5 +13 -13
- package/cli/templates/{ohos-pc → ohos-skeleton}/AppScope/resources/base/element/string.json +8 -8
- package/cli/templates/{ohos-pc → ohos-skeleton}/AppScope/resources/base/media/layered_image.json +6 -6
- package/cli/templates/{ohos-pc → ohos-skeleton}/README.md +79 -79
- package/cli/templates/{ohos-pc → ohos-skeleton}/build-profile.json5 +46 -46
- package/cli/templates/{ohos-pc → ohos-skeleton}/entry/build-profile.json5 +26 -26
- package/cli/templates/{ohos-pc → ohos-skeleton}/entry/cjpm.toml +43 -43
- package/cli/templates/{ohos-pc → ohos-skeleton}/entry/hvigorfile.ts +6 -6
- package/cli/templates/{ohos-pc → ohos-skeleton}/entry/oh-package.json5 +9 -9
- package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/cangjie/ability_stage.cj +17 -17
- package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/cangjie/app_host.cj +94 -94
- package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/cangjie/index.cj +167 -167
- package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/cangjie/main_ability.cj +139 -139
- package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/module.json5 +49 -49
- package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/element/color.json +8 -8
- package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/element/string.json +16 -16
- package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/media/layered_image.json +6 -6
- package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/profile/main_pages.json +2 -2
- package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/rawfile/capabilities.json +6 -6
- package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/rawfile/index.html +92 -92
- package/cli/templates/{ohos-pc → ohos-skeleton}/hvigor/hvigor-config.json5 +5 -5
- package/cli/templates/{ohos-pc → ohos-skeleton}/hvigorfile.ts +6 -6
- package/cli/templates/{ohos-pc → ohos-skeleton}/oh-package.json5 +10 -10
- package/package.json +4 -2
- package/prebuilt/win32-x64/cj-tauri.exe +0 -0
- package/src/app.cj +49 -20
- package/src/app_spec.cj +76 -0
- package/src/arkweb_script.cj +142 -154
- package/src/host.cj +20 -17
- package/src/host_arkweb.cj +778 -740
- package/src/host_webkit.cj +22 -0
- package/src/host_webview2.cj +22 -0
- package/src/launch.cj +62 -0
- 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 +36 -2
- package/src/plugins/clipboard/plugin_clipboard.cj +8 -0
- package/src/plugins/menu/plugin_menu.cj +158 -150
- package/src/plugins/notification/plugin_notification.cj +8 -0
- package/src/plugins/serial/plugin_serial.cj +454 -442
- package/src/plugins/serial/serial_bridge.cj +194 -186
- package/src/plugins/serial/serial_ohos_stub.cj +61 -0
- package/src/plugins/shell/plugin_shell.cj +258 -230
- package/src/plugins/sqlite/plugin_sqlite.cj +710 -697
- package/src/plugins/sqlite/sqlite_ffi.cj +211 -206
- package/src/plugins/sqlite/sqlite_ohos_stub.cj +91 -0
- package/src/tests/app_spec_test.cj +127 -0
- package/src/tests/fake_host.cj +23 -8
- package/src/tests/platform_contract_test.cj +251 -0
- package/src/tests/plugin_test.cj +585 -542
- package/src/version.cj +1 -1
- package/src/host_factory.cj +0 -48
- /package/cli/templates/app-react/{ui → assets/ui}/index.html +0 -0
- /package/cli/templates/app-react/{ui → assets/ui}/src/App.css +0 -0
- /package/cli/templates/app-react/{ui → assets/ui}/src/App.jsx +0 -0
- /package/cli/templates/app-vue/{ui → assets/ui}/index.html +0 -0
- /package/cli/templates/app-vue/{ui → assets/ui}/src/App.vue +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}/build-hap.sh +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/startIcon.png +0 -0
package/cli/src/util.cj
CHANGED
|
@@ -1,159 +1,168 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* cj-tauri CLI:通用工具层
|
|
3
|
-
*
|
|
4
|
-
* 路径与字符串处理统一按 UTF-8 字节做 ASCII 分隔符扫描,切分点都在 ASCII 边界上,
|
|
5
|
-
* 对含中文的路径安全(仓颉迭代 String 得到的是码点,这里显式走字节以避免码点/字节混淆)。
|
|
6
|
-
*/
|
|
7
|
-
package cli
|
|
8
|
-
|
|
9
|
-
import std.fs.*
|
|
10
|
-
|
|
11
|
-
// ===== 字节级字符判定 =====
|
|
12
|
-
|
|
13
|
-
func isPathSep(b: UInt8): Bool {
|
|
14
|
-
return b == 0x2F || b == 0x5C // '/' or '\'
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
func isSpaceByte(b: UInt8): Bool {
|
|
18
|
-
return b == 0x20 || b == 0x09 || b == 0x0D || b == 0x0A
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
func isAsciiDigit(b: UInt8): Bool {
|
|
22
|
-
return b >= 0x30 && b <= 0x39
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
func isAsciiAlpha(b: UInt8): Bool {
|
|
26
|
-
return (b >= 0x41 && b <= 0x5A) || (b >= 0x61 && b <= 0x7A)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
func toUpperByte(b: UInt8): UInt8 {
|
|
30
|
-
if (b >= 0x61 && b <= 0x7A) {
|
|
31
|
-
return b - 0x20
|
|
32
|
-
}
|
|
33
|
-
return b
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
func toLowerByte(b: UInt8): UInt8 {
|
|
37
|
-
if (b >= 0x41 && b <= 0x5A) {
|
|
38
|
-
return b + 0x20
|
|
39
|
-
}
|
|
40
|
-
return b
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// ===== 路径 =====
|
|
44
|
-
|
|
45
|
-
/** 拼接路径(统一用 '/',Windows 亦兼容) */
|
|
46
|
-
func joinPath(a: String, b: String): String {
|
|
47
|
-
let ab = a.toArray()
|
|
48
|
-
if (ab.size == 0) {
|
|
49
|
-
return b
|
|
50
|
-
}
|
|
51
|
-
if (isPathSep(ab[ab.size - 1])) {
|
|
52
|
-
return a + b
|
|
53
|
-
}
|
|
54
|
-
return a + "/" + b
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/** 去掉末尾的路径分隔符 */
|
|
58
|
-
func stripTrailingSep(p: String): String {
|
|
59
|
-
let b = p.toArray()
|
|
60
|
-
var n = b.size
|
|
61
|
-
while (n > 1 && isPathSep(b[n - 1])) {
|
|
62
|
-
n--
|
|
63
|
-
}
|
|
64
|
-
return String.fromUtf8(b[0..n])
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/** 父目录;已到根或无法解析时返回 None */
|
|
68
|
-
func parentDir(p: String): Option<String> {
|
|
69
|
-
let s = stripTrailingSep(p)
|
|
70
|
-
let b = s.toArray()
|
|
71
|
-
var i = b.size
|
|
72
|
-
while (i > 0) {
|
|
73
|
-
i--
|
|
74
|
-
if (isPathSep(b[i])) {
|
|
75
|
-
if (i == 0) {
|
|
76
|
-
return Some(String.fromUtf8(b[0..1])) // "/"
|
|
77
|
-
}
|
|
78
|
-
// Windows 盘符根 "C:/"
|
|
79
|
-
if (i == 2 && b[1] == 0x3A) {
|
|
80
|
-
return Some(String.fromUtf8(b[0..3]))
|
|
81
|
-
}
|
|
82
|
-
return Some(String.fromUtf8(b[0..i]))
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
return None
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/** 最后一段(文件/目录名) */
|
|
89
|
-
func baseName(p: String): String {
|
|
90
|
-
let s = stripTrailingSep(p)
|
|
91
|
-
let b = s.toArray()
|
|
92
|
-
var i = b.size
|
|
93
|
-
while (i > 0) {
|
|
94
|
-
i--
|
|
95
|
-
if (isPathSep(b[i])) {
|
|
96
|
-
return String.fromUtf8(b[i + 1..b.size])
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
return s
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/** 去掉首尾 ASCII 空白(含 \r) */
|
|
103
|
-
func trimAscii(s: String): String {
|
|
104
|
-
let b = s.toArray()
|
|
105
|
-
var start = 0
|
|
106
|
-
var end = b.size
|
|
107
|
-
while (start < end && isSpaceByte(b[start])) {
|
|
108
|
-
start++
|
|
109
|
-
}
|
|
110
|
-
while (end > start && isSpaceByte(b[end - 1])) {
|
|
111
|
-
end--
|
|
112
|
-
}
|
|
113
|
-
if (start == 0 && end == b.size) {
|
|
114
|
-
return s
|
|
115
|
-
}
|
|
116
|
-
return String.fromUtf8(b[start..end])
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/** 路径含空格时给出告警(cjpm 的 link-option 以空格分隔,无法转义) */
|
|
120
|
-
func warnIfSpacey(label: String, p: String): Unit {
|
|
121
|
-
let b = p.toArray()
|
|
122
|
-
for (x in b) {
|
|
123
|
-
if (x == 0x20) {
|
|
124
|
-
eprintln("[cj-tauri] 告警: ${label} 路径含空格,cjpm 的 link-option 可能解析失败: ${p}")
|
|
125
|
-
return
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// ===== 文件 =====
|
|
131
|
-
|
|
132
|
-
func readText(p: String): String {
|
|
133
|
-
return String.fromUtf8(File.readFrom(p))
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/** 覆盖写(File.create 对已存在文件会抛异常,故先删) */
|
|
137
|
-
func writeText(p: String, content: String): Unit {
|
|
138
|
-
if (exists(p)) {
|
|
139
|
-
remove(p)
|
|
140
|
-
}
|
|
141
|
-
let f = File.create(p)
|
|
142
|
-
f.write(content.toArray())
|
|
143
|
-
f.close()
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
func ensureDir(p: String): Unit {
|
|
147
|
-
if (!exists(p)) {
|
|
148
|
-
Directory.create(p, recursive: true)
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
func listDir(p: String): Array<FileInfo> {
|
|
153
|
-
return Directory.readFrom(p)
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/** TOML 基本字符串转义:反斜杠与双引号 */
|
|
157
|
-
func escapeTomlString(p: String): String {
|
|
158
|
-
return p.replace("\\", "\\\\").replace("\"", "\\\"")
|
|
159
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* cj-tauri CLI:通用工具层
|
|
3
|
+
*
|
|
4
|
+
* 路径与字符串处理统一按 UTF-8 字节做 ASCII 分隔符扫描,切分点都在 ASCII 边界上,
|
|
5
|
+
* 对含中文的路径安全(仓颉迭代 String 得到的是码点,这里显式走字节以避免码点/字节混淆)。
|
|
6
|
+
*/
|
|
7
|
+
package cli
|
|
8
|
+
|
|
9
|
+
import std.fs.*
|
|
10
|
+
|
|
11
|
+
// ===== 字节级字符判定 =====
|
|
12
|
+
|
|
13
|
+
func isPathSep(b: UInt8): Bool {
|
|
14
|
+
return b == 0x2F || b == 0x5C // '/' or '\'
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
func isSpaceByte(b: UInt8): Bool {
|
|
18
|
+
return b == 0x20 || b == 0x09 || b == 0x0D || b == 0x0A
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
func isAsciiDigit(b: UInt8): Bool {
|
|
22
|
+
return b >= 0x30 && b <= 0x39
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
func isAsciiAlpha(b: UInt8): Bool {
|
|
26
|
+
return (b >= 0x41 && b <= 0x5A) || (b >= 0x61 && b <= 0x7A)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
func toUpperByte(b: UInt8): UInt8 {
|
|
30
|
+
if (b >= 0x61 && b <= 0x7A) {
|
|
31
|
+
return b - 0x20
|
|
32
|
+
}
|
|
33
|
+
return b
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
func toLowerByte(b: UInt8): UInt8 {
|
|
37
|
+
if (b >= 0x41 && b <= 0x5A) {
|
|
38
|
+
return b + 0x20
|
|
39
|
+
}
|
|
40
|
+
return b
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ===== 路径 =====
|
|
44
|
+
|
|
45
|
+
/** 拼接路径(统一用 '/',Windows 亦兼容) */
|
|
46
|
+
func joinPath(a: String, b: String): String {
|
|
47
|
+
let ab = a.toArray()
|
|
48
|
+
if (ab.size == 0) {
|
|
49
|
+
return b
|
|
50
|
+
}
|
|
51
|
+
if (isPathSep(ab[ab.size - 1])) {
|
|
52
|
+
return a + b
|
|
53
|
+
}
|
|
54
|
+
return a + "/" + b
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** 去掉末尾的路径分隔符 */
|
|
58
|
+
func stripTrailingSep(p: String): String {
|
|
59
|
+
let b = p.toArray()
|
|
60
|
+
var n = b.size
|
|
61
|
+
while (n > 1 && isPathSep(b[n - 1])) {
|
|
62
|
+
n--
|
|
63
|
+
}
|
|
64
|
+
return String.fromUtf8(b[0..n])
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** 父目录;已到根或无法解析时返回 None */
|
|
68
|
+
func parentDir(p: String): Option<String> {
|
|
69
|
+
let s = stripTrailingSep(p)
|
|
70
|
+
let b = s.toArray()
|
|
71
|
+
var i = b.size
|
|
72
|
+
while (i > 0) {
|
|
73
|
+
i--
|
|
74
|
+
if (isPathSep(b[i])) {
|
|
75
|
+
if (i == 0) {
|
|
76
|
+
return Some(String.fromUtf8(b[0..1])) // "/"
|
|
77
|
+
}
|
|
78
|
+
// Windows 盘符根 "C:/"
|
|
79
|
+
if (i == 2 && b[1] == 0x3A) {
|
|
80
|
+
return Some(String.fromUtf8(b[0..3]))
|
|
81
|
+
}
|
|
82
|
+
return Some(String.fromUtf8(b[0..i]))
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return None
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** 最后一段(文件/目录名) */
|
|
89
|
+
func baseName(p: String): String {
|
|
90
|
+
let s = stripTrailingSep(p)
|
|
91
|
+
let b = s.toArray()
|
|
92
|
+
var i = b.size
|
|
93
|
+
while (i > 0) {
|
|
94
|
+
i--
|
|
95
|
+
if (isPathSep(b[i])) {
|
|
96
|
+
return String.fromUtf8(b[i + 1..b.size])
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return s
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** 去掉首尾 ASCII 空白(含 \r) */
|
|
103
|
+
func trimAscii(s: String): String {
|
|
104
|
+
let b = s.toArray()
|
|
105
|
+
var start = 0
|
|
106
|
+
var end = b.size
|
|
107
|
+
while (start < end && isSpaceByte(b[start])) {
|
|
108
|
+
start++
|
|
109
|
+
}
|
|
110
|
+
while (end > start && isSpaceByte(b[end - 1])) {
|
|
111
|
+
end--
|
|
112
|
+
}
|
|
113
|
+
if (start == 0 && end == b.size) {
|
|
114
|
+
return s
|
|
115
|
+
}
|
|
116
|
+
return String.fromUtf8(b[start..end])
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** 路径含空格时给出告警(cjpm 的 link-option 以空格分隔,无法转义) */
|
|
120
|
+
func warnIfSpacey(label: String, p: String): Unit {
|
|
121
|
+
let b = p.toArray()
|
|
122
|
+
for (x in b) {
|
|
123
|
+
if (x == 0x20) {
|
|
124
|
+
eprintln("[cj-tauri] 告警: ${label} 路径含空格,cjpm 的 link-option 可能解析失败: ${p}")
|
|
125
|
+
return
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ===== 文件 =====
|
|
131
|
+
|
|
132
|
+
func readText(p: String): String {
|
|
133
|
+
return String.fromUtf8(File.readFrom(p))
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** 覆盖写(File.create 对已存在文件会抛异常,故先删) */
|
|
137
|
+
func writeText(p: String, content: String): Unit {
|
|
138
|
+
if (exists(p)) {
|
|
139
|
+
remove(p)
|
|
140
|
+
}
|
|
141
|
+
let f = File.create(p)
|
|
142
|
+
f.write(content.toArray())
|
|
143
|
+
f.close()
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
func ensureDir(p: String): Unit {
|
|
147
|
+
if (!exists(p)) {
|
|
148
|
+
Directory.create(p, recursive: true)
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
func listDir(p: String): Array<FileInfo> {
|
|
153
|
+
return Directory.readFrom(p)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** TOML 基本字符串转义:反斜杠与双引号 */
|
|
157
|
+
func escapeTomlString(p: String): String {
|
|
158
|
+
return p.replace("\\", "\\\\").replace("\"", "\\\"")
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* 写进生成 TOML 的路径一律转正斜杠。
|
|
163
|
+
* 为什么:Windows 的 `E:\a\b` 在 TOML 基本字符串里是转义序列,`\a` / `\t` 会让 cjpm 解析期直接
|
|
164
|
+
* `errLexEscape` 失败(AGENTS §4「生成 toml 的脚本用正斜杠」);正斜杠 cjpm 与 gcc/ld 都认。
|
|
165
|
+
*/
|
|
166
|
+
func toTomlPath(p: String): String {
|
|
167
|
+
return p.replace("\\", "/")
|
|
168
|
+
}
|
|
@@ -1,80 +1,48 @@
|
|
|
1
|
-
# {{PROJECT_NAME}}
|
|
2
|
-
|
|
3
|
-
基于 [cj-tauri]({{FRAMEWORK_ROOT}})(仓颉版 Tauri)的应用:**仓颉后端 + 系统 WebView 前端**,
|
|
4
|
-
通过 `window.__CJ_TAURI__` 做 invoke/listen 双向 IPC,并由
|
|
5
|
-
|
|
6
|
-
##
|
|
7
|
-
|
|
8
|
-
```
|
|
9
|
-
{{PROJECT_NAME}}/
|
|
10
|
-
├──
|
|
11
|
-
├──
|
|
12
|
-
├──
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
cj-tauri
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
#
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
`
|
|
47
|
-
|
|
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
|
-
```
|
|
77
|
-
|
|
78
|
-
## 文档
|
|
79
|
-
|
|
80
|
-
框架完整文档:`{{FRAMEWORK_ROOT}}/README.md` 与 `{{FRAMEWORK_ROOT}}/docs/使用文档.md`
|
|
1
|
+
# {{PROJECT_NAME}}
|
|
2
|
+
|
|
3
|
+
基于 [cj-tauri]({{FRAMEWORK_ROOT}})(仓颉版 Tauri)的应用:**仓颉后端 + 系统 WebView 前端**,
|
|
4
|
+
通过 `window.__CJ_TAURI__` 做 invoke/listen 双向 IPC,并由 capabilities 清单做最小权限管控。
|
|
5
|
+
|
|
6
|
+
## 目录结构(一份业务代码,骨架按目标派生)
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
{{PROJECT_NAME}}/
|
|
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)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## 运行
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
cj-tauri sync # 派生 targets/ 骨架(首次;重跑幂等)
|
|
25
|
+
cj-tauri dev # 构建 C 桥 + 编译 + 启动窗口
|
|
26
|
+
cj-tauri build # 仅构建
|
|
27
|
+
cj-tauri run # 运行已构建产物
|
|
28
|
+
cj-tauri check # 清单校验 + 骨架漂移 + 插件三方比对
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## 鸿蒙端(PC / 2in1)
|
|
32
|
+
|
|
33
|
+
```bash
|
|
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 # 编完装到设备并拉起
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
提示:模板不带签名证书——首次在 DevEco 里 File → Project Structure → Signing Configs
|
|
40
|
+
勾「Automatically generate signature」(要登录华为账号);不签名只能编出
|
|
41
|
+
*-unsigned.hap,装不进设备。
|
|
42
|
+
|
|
43
|
+
## 命令与能力
|
|
44
|
+
|
|
45
|
+
命令在 `src/main.cj`(`greet` / `timer` + 演示菜单),白名单在 `assets/capabilities/default.json`——
|
|
46
|
+
两边必须对齐:`cj-tauri check` 的三方比对会交叉核对「能力声明 × 插件自描述 × 实际装配」。
|
|
47
|
+
插件在某端没有实现时(如 shell/sqlite 在鸿蒙端),骨架照样编得过,运行期调用得到
|
|
48
|
+
可照做的「端不支持」错误(RFC-002 §4.6.4 的 P-1 桩)。
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
{
|
|
2
|
-
"identifier": "default",
|
|
3
|
-
"windows": ["main"],
|
|
4
|
-
"commands": ["greet", "timer", "system:version", "system:ping", "system:echo", "system:devtools"],
|
|
5
|
-
"permissions": ["menu:state"],
|
|
6
|
-
"events": ["tick", "menu:click"]
|
|
7
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"identifier": "default",
|
|
3
|
+
"windows": ["main"],
|
|
4
|
+
"commands": ["greet", "timer", "system:version", "system:ping", "system:echo", "system:devtools"],
|
|
5
|
+
"permissions": ["menu:state"],
|
|
6
|
+
"events": ["tick", "menu:click"]
|
|
7
|
+
}
|