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.
Files changed (101) hide show
  1. package/README.md +64 -18
  2. package/cjpm.toml +52 -52
  3. package/cli/cjpm.toml +10 -1
  4. package/cli/src/doctor.cj +4 -2
  5. package/cli/src/main.cj +11 -3
  6. package/cli/src/manifest.cj +558 -0
  7. package/cli/src/project.cj +38 -22
  8. package/cli/src/scaffold.cj +369 -361
  9. package/cli/src/sync.cj +526 -0
  10. package/cli/src/util.cj +168 -159
  11. package/cli/templates/app/README.md +48 -80
  12. package/cli/templates/app/{capabilities → assets/capabilities}/default.json +7 -7
  13. package/cli/templates/app/{ui → assets/ui}/index.html +118 -118
  14. package/cli/templates/app/cj-tauri.toml +22 -0
  15. package/cli/templates/app/cjpm.toml +34 -17
  16. package/cli/templates/app/src/main.cj +90 -88
  17. package/cli/templates/app-react/README.md +56 -67
  18. package/cli/templates/app-react/{capabilities → assets/capabilities}/default.json +7 -7
  19. package/cli/templates/app-react/{ui → assets/ui}/package.json +19 -19
  20. package/cli/templates/app-react/{ui → assets/ui}/src/main.jsx +6 -6
  21. package/cli/templates/app-react/{ui → assets/ui}/vite.config.js +24 -24
  22. package/cli/templates/app-react/cj-tauri.toml +23 -0
  23. package/cli/templates/app-react/cjpm.toml +34 -17
  24. package/cli/templates/app-react/src/main.cj +91 -102
  25. package/cli/templates/app-vue/README.md +56 -60
  26. package/cli/templates/app-vue/{capabilities → assets/capabilities}/default.json +7 -7
  27. package/cli/templates/app-vue/{ui → assets/ui}/package.json +18 -18
  28. package/cli/templates/app-vue/{ui → assets/ui}/src/main.js +4 -4
  29. package/cli/templates/app-vue/{ui → assets/ui}/vite.config.js +24 -24
  30. package/cli/templates/app-vue/cj-tauri.toml +23 -0
  31. package/cli/templates/app-vue/cjpm.toml +34 -17
  32. package/cli/templates/app-vue/src/main.cj +91 -102
  33. package/cli/templates/{ohos-pc → ohos-skeleton}/AppScope/app.json5 +13 -13
  34. package/cli/templates/{ohos-pc → ohos-skeleton}/AppScope/resources/base/element/string.json +8 -8
  35. package/cli/templates/{ohos-pc → ohos-skeleton}/AppScope/resources/base/media/layered_image.json +6 -6
  36. package/cli/templates/{ohos-pc → ohos-skeleton}/README.md +79 -79
  37. package/cli/templates/{ohos-pc → ohos-skeleton}/build-profile.json5 +46 -46
  38. package/cli/templates/{ohos-pc → ohos-skeleton}/entry/build-profile.json5 +26 -26
  39. package/cli/templates/{ohos-pc → ohos-skeleton}/entry/cjpm.toml +43 -43
  40. package/cli/templates/{ohos-pc → ohos-skeleton}/entry/hvigorfile.ts +6 -6
  41. package/cli/templates/{ohos-pc → ohos-skeleton}/entry/oh-package.json5 +9 -9
  42. package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/cangjie/ability_stage.cj +17 -17
  43. package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/cangjie/app_host.cj +94 -94
  44. package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/cangjie/index.cj +167 -167
  45. package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/cangjie/main_ability.cj +139 -139
  46. package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/module.json5 +49 -49
  47. package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/element/color.json +8 -8
  48. package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/element/string.json +16 -16
  49. package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/media/layered_image.json +6 -6
  50. package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/profile/main_pages.json +2 -2
  51. package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/rawfile/capabilities.json +6 -6
  52. package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/rawfile/index.html +92 -92
  53. package/cli/templates/{ohos-pc → ohos-skeleton}/hvigor/hvigor-config.json5 +5 -5
  54. package/cli/templates/{ohos-pc → ohos-skeleton}/hvigorfile.ts +6 -6
  55. package/cli/templates/{ohos-pc → ohos-skeleton}/oh-package.json5 +10 -10
  56. package/package.json +4 -2
  57. package/prebuilt/win32-x64/cj-tauri.exe +0 -0
  58. package/src/app.cj +49 -20
  59. package/src/app_spec.cj +76 -0
  60. package/src/arkweb_script.cj +142 -154
  61. package/src/host.cj +20 -17
  62. package/src/host_arkweb.cj +778 -740
  63. package/src/host_webkit.cj +22 -0
  64. package/src/host_webview2.cj +22 -0
  65. package/src/launch.cj +62 -0
  66. package/src/platform/platform_app_context.cj +77 -0
  67. package/src/platform/platform_assets.cj +33 -0
  68. package/src/platform/platform_discover.cj +176 -0
  69. package/src/platform/platform_env.cj +29 -0
  70. package/src/platform/platform_feature.cj +31 -0
  71. package/src/platform/platform_page_source.cj +87 -0
  72. package/src/platform/platform_target_info.cj +32 -0
  73. package/src/platform_host_provider.cj +87 -0
  74. package/src/plugin.cj +36 -2
  75. package/src/plugins/clipboard/plugin_clipboard.cj +8 -0
  76. package/src/plugins/menu/plugin_menu.cj +158 -150
  77. package/src/plugins/notification/plugin_notification.cj +8 -0
  78. package/src/plugins/serial/plugin_serial.cj +454 -442
  79. package/src/plugins/serial/serial_bridge.cj +194 -186
  80. package/src/plugins/serial/serial_ohos_stub.cj +61 -0
  81. package/src/plugins/shell/plugin_shell.cj +258 -230
  82. package/src/plugins/sqlite/plugin_sqlite.cj +710 -697
  83. package/src/plugins/sqlite/sqlite_ffi.cj +211 -206
  84. package/src/plugins/sqlite/sqlite_ohos_stub.cj +91 -0
  85. package/src/tests/app_spec_test.cj +127 -0
  86. package/src/tests/fake_host.cj +23 -8
  87. package/src/tests/platform_contract_test.cj +251 -0
  88. package/src/tests/plugin_test.cj +585 -542
  89. package/src/version.cj +1 -1
  90. package/src/host_factory.cj +0 -48
  91. /package/cli/templates/app-react/{ui → assets/ui}/index.html +0 -0
  92. /package/cli/templates/app-react/{ui → assets/ui}/src/App.css +0 -0
  93. /package/cli/templates/app-react/{ui → assets/ui}/src/App.jsx +0 -0
  94. /package/cli/templates/app-vue/{ui → assets/ui}/index.html +0 -0
  95. /package/cli/templates/app-vue/{ui → assets/ui}/src/App.vue +0 -0
  96. /package/cli/templates/{ohos-pc → ohos-skeleton}/AppScope/resources/base/media/background.png +0 -0
  97. /package/cli/templates/{ohos-pc → ohos-skeleton}/AppScope/resources/base/media/foreground.png +0 -0
  98. /package/cli/templates/{ohos-pc → ohos-skeleton}/build-hap.sh +0 -0
  99. /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/media/background.png +0 -0
  100. /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/media/foreground.png +0 -0
  101. /package/cli/templates/{ohos-pc → ohos-skeleton}/entry/src/main/resources/base/media/startIcon.png +0 -0
@@ -1,17 +1,34 @@
1
- [package]
2
- cjc-version = "{{CJC_VERSION}}"
3
- name = "{{PACKAGE_NAME}}"
4
- description = "{{PROJECT_NAME}} - cj-tauri 应用(Vue 3 + Vite 前端)"
5
- version = "0.1.0"
6
- target-dir = ""
7
- output-type = "executable"
8
- compile-option = ""
9
- override-compile-option = ""
10
- link-option = ""
11
- package-configuration = {}
12
-
13
- [dependencies]
14
- # cj-tauri 框架本体(由 cj-tauri create 写入的本机路径)
15
- cjTauri = { path = "{{FRAMEWORK_ROOT_TOML}}" }
16
-
17
- {{TARGET_SECTION}}
1
+ # 业务包:业务代码的唯一真相(RFC-002 §7.3——骨架永远是外壳,业务只有一份)。
2
+ # output-type = "static":桌面骨架(targets/desktop)与鸿蒙入口(targets/ohos/entry)
3
+ # 都以 path 依赖引用本包——同一份业务代码,多个目标各编各的产物。
4
+ [package]
5
+ cjc-version = "{{CJC_VERSION}}"
6
+ name = "{{PACKAGE_NAME}}"
7
+ description = "{{PROJECT_NAME}} - cj-tauri 业务包"
8
+ version = "0.1.0"
9
+ target-dir = ""
10
+ output-type = "static"
11
+ compile-option = ""
12
+ override-compile-option = ""
13
+ link-option = ""
14
+ package-configuration = {}
15
+
16
+ [dependencies]
17
+ # cj-tauri 框架本体(由 cj-tauri create 写入的本机路径;换机器重跑 create 或手改)
18
+ cjTauri = { path = "{{FRAMEWORK_ROOT_TOML}}" }
19
+
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,102 +1,91 @@
1
- package {{PACKAGE_NAME}}
2
-
3
- import cjTauri.*
4
- import stdx.encoding.json.*
5
- import std.fs.*
6
- import std.collection.*
7
-
8
- /**
9
- * greet 命令(对标 tauri command)
10
- * 前端:tauri.invoke("greet", { name: "..." })
11
- */
12
- public class GreetCommand <: CommandHandler {
13
- public init() {}
14
-
15
- public func handle(cmd: String, args: JsonObject, ipc: IpcContext): JsonValue {
16
- var name = "world"
17
- if (let Some(n) <- args.get("name")) {
18
- match (n.kind()) {
19
- case JsonKind.JsString => name = n.asString().getValue()
20
- case _ => ()
21
- }
22
- }
23
- return JsonString("Hello, ${name}! 来自仓颉后端")
24
- }
25
- }
26
-
27
- /**
28
- * 定时器命令:启动后台线程,每秒向后端推一个 tick 事件(验证 仓颉 → JS 通道)
29
- * 前端:tauri.listen("tick", cb) + tauri.invoke("timer")
30
- */
31
- public class TimerCommand <: CommandHandler {
32
- private var counter: Int64 = 0
33
- private var started: Bool = false
34
-
35
- public init() {}
36
-
37
- public func handle(cmd: String, args: JsonObject, ipc: IpcContext): JsonValue {
38
- if (!this.started) {
39
- this.started = true
40
- spawn {
41
- while (true) {
42
- sleep(Duration.second)
43
- this.counter += 1
44
- var payload = JsonObject()
45
- payload.put("n", JsonInt(this.counter))
46
- ipc.emit("tick", payload)
47
- }
48
- }
49
- }
50
- return JsonString("timer started")
51
- }
52
- }
53
-
54
- /**
55
- * 演示菜单:一个普通项 + 一个带勾选项的子菜单
56
- *
57
- * 两个方向都在页面上看得到:
58
- * 菜单 → 页面:点「打个招呼」,宿主把事件推给前端(页面 listen("menu:click") 显示 id)
59
- * 页面 → 菜单:勾选页面上的复选框,走 menu 插件改「侧边栏」这一项的勾选状态
60
- */
61
- func demoMenu(): MenuModel {
62
- var view = ArrayList<MenuItem>()
63
- view.add(MenuItem.checkbox("view.sidebar", "侧边栏", true))
64
- var items = ArrayList<MenuItem>()
65
- items.add(MenuItem.normal("file.hello", "打个招呼"))
66
- items.add(MenuItem.submenu("视图", view))
67
- return MenuModel(items)
68
- }
69
-
70
- main(): Int64 {
71
- // 1) 装配应用(对标 tauri::Builder):窗口配置 + 注册命令
72
- // 能力清单由框架在 run() 时自动扫描 capabilities/ 目录(对标 Tauri 的 capabilities 目录)
73
- let app = TauriApp()
74
- .window(WindowConfig("{{PROJECT_NAME}}", 1000, 700))
75
- .register("greet", GreetCommand())
76
- .register("timer", TimerCommand())
77
- // menu 插件:给前端挂 window.__CJ_TAURI__.menu.setEnabled / setChecked
78
- // (插件只声明「我提供什么」,**不自动放行**——要能调,就在 capabilities 里引用
79
- // permissions: ["menu:state"],或逐条写 commands)
80
- .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
102
- }
1
+ package {{PACKAGE_NAME}}
2
+
3
+ import cjTauri.*
4
+ import cjTauri.plugins.menu.*
5
+ import stdx.encoding.json.*
6
+ import std.collection.*
7
+
8
+ /**
9
+ * greet 命令(对标 tauri command)
10
+ * 前端:tauri.invoke("greet", { name: "..." })
11
+ */
12
+ public class GreetCommand <: CommandHandler {
13
+ public init() {}
14
+
15
+ public func handle(cmd: String, args: JsonObject, ipc: IpcContext): JsonValue {
16
+ var name = "world"
17
+ if (let Some(n) <- args.get("name")) {
18
+ match (n.kind()) {
19
+ case JsonKind.JsString => name = n.asString().getValue()
20
+ case _ => ()
21
+ }
22
+ }
23
+ return JsonString("Hello, ${name}! 来自仓颉后端")
24
+ }
25
+ }
26
+
27
+ /**
28
+ * 定时器命令:启动后台线程,每秒向前端推一个 tick 事件(验证 仓颉 → JS 通道)
29
+ * 前端:tauri.listen("tick", cb) + tauri.invoke("timer")
30
+ */
31
+ public class TimerCommand <: CommandHandler {
32
+ private var counter: Int64 = 0
33
+ private var started: Bool = false
34
+
35
+ public init() {}
36
+
37
+ public func handle(cmd: String, args: JsonObject, ipc: IpcContext): JsonValue {
38
+ if (!this.started) {
39
+ this.started = true
40
+ spawn {
41
+ while (true) {
42
+ sleep(Duration.second)
43
+ this.counter += 1
44
+ var payload = JsonObject()
45
+ payload.put("n", JsonInt(this.counter))
46
+ ipc.emit("tick", payload)
47
+ }
48
+ }
49
+ }
50
+ return JsonString("timer started")
51
+ }
52
+ }
53
+
54
+ /**
55
+ * 演示菜单:一个普通项 + 一个带勾选项的子菜单
56
+ *
57
+ * 两个方向都在页面上看得到:
58
+ * 菜单 → 页面:点「打个招呼」,宿主把事件推给前端(页面 listen("menu:click") 显示 id)
59
+ * 页面 → 菜单:勾选页面上的复选框,走 menu 插件改「侧边栏」这一项的勾选状态
60
+ */
61
+ func demoMenu(): MenuModel {
62
+ var view = ArrayList<MenuItem>()
63
+ view.add(MenuItem.checkbox("view.sidebar", "侧边栏", true))
64
+ var items = ArrayList<MenuItem>()
65
+ items.add(MenuItem.normal("file.hello", "打个招呼"))
66
+ items.add(MenuItem.submenu("视图", view))
67
+ return MenuModel(items)
68
+ }
69
+
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()
80
+ .window(WindowConfig("{{PROJECT_NAME}}", 1000, 700))
81
+ // menu 插件:给前端挂 window.__CJ_TAURI__.menu.setEnabled / setChecked
82
+ // (插件只声明「我提供什么」,**不自动放行**——要能调,就在 capabilities 里引用
83
+ // permissions: ["menu:state"],或逐条写 commands)
84
+ .plugin(MenuPlugin())
85
+ .wire({ app =>
86
+ app.register("greet", GreetCommand())
87
+ app.register("timer", TimerCommand())
88
+ // 菜单栏必须在 run 之前挂:预置类宿主能力要赶在页面加载前定稿
89
+ app.setMenu(demoMenu())
90
+ })
91
+ }
@@ -1,13 +1,13 @@
1
- {
2
- "app": {
3
- /* bundleName 是应用在设备上的唯一 ID:两个应用写同一个 bundleName 会互相覆盖安装。
4
- 改它必须重新签名——DevEco 的「自动签名」会按新包名重新申请 profile。 */
5
- "bundleName": "{{BUNDLE_NAME}}",
6
- "vendor": "{{PROJECT_NAME}}",
7
- "versionCode": 1000000,
8
- "versionName": "1.0.0",
9
- "buildVersion": "1",
10
- "icon": "$media:layered_image",
11
- "label": "$string:app_name"
12
- }
13
- }
1
+ {
2
+ "app": {
3
+ /* bundleName 是应用在设备上的唯一 ID:两个应用写同一个 bundleName 会互相覆盖安装。
4
+ 改它必须重新签名——DevEco 的「自动签名」会按新包名重新申请 profile。 */
5
+ "bundleName": "{{BUNDLE_NAME}}",
6
+ "vendor": "{{PROJECT_NAME}}",
7
+ "versionCode": 1000000,
8
+ "versionName": "1.0.0",
9
+ "buildVersion": "1",
10
+ "icon": "$media:layered_image",
11
+ "label": "$string:app_name"
12
+ }
13
+ }
@@ -1,8 +1,8 @@
1
- {
2
- "string": [
3
- {
4
- "name": "app_name",
5
- "value": "{{APP_LABEL}}"
6
- }
7
- ]
8
- }
1
+ {
2
+ "string": [
3
+ {
4
+ "name": "app_name",
5
+ "value": "{{APP_LABEL}}"
6
+ }
7
+ ]
8
+ }
@@ -1,6 +1,6 @@
1
- {
2
- "layered-image": {
3
- "background": "$media:background",
4
- "foreground": "$media:foreground"
5
- }
6
- }
1
+ {
2
+ "layered-image": {
3
+ "background": "$media:background",
4
+ "foreground": "$media:foreground"
5
+ }
6
+ }
@@ -1,79 +1,79 @@
1
- # {{PROJECT_NAME}} — 仓颉 + ArkWeb 鸿蒙 PC 应用
2
-
3
- 用 [cj-tauri](https://atomgit.com/qq8864/cj-tauri) 生成的鸿蒙 PC(2in1)应用工程:
4
- **仓颉后端(静态编译)+ 系统 ArkWeb 前端(HTML/CSS/JS)**,IPC、能力校验、命令分发与桌面版同一套框架代码。
5
-
6
- ## 目录
7
-
8
- ```
9
- {{PROJECT_NAME}}/
10
- ├─ AppScope/app.json5 应用级配置(bundleName = {{BUNDLE_NAME}})
11
- ├─ build-profile.json5 工程级构建配置(签名留空,见下)
12
- ├─ build-hap.sh 构建入口(编 hap / 装到设备)
13
- ├─ entry/
14
- │ ├─ cjpm.toml cjTauri 依赖 + aarch64-linux-ohos 目标段
15
- │ ├─ build-profile.json5 cangjieOptions.checkDeviceTypes=false(放行 2in1)
16
- │ └─ src/main/
17
- │ ├─ module.json5 deviceTypes: 2in1 / tablet / phone
18
- │ ├─ cangjie/
19
- │ │ ├─ ability_stage.cj AbilityStage
20
- │ │ ├─ main_ability.cj UIAbility:沙箱、rawfile 读取、窗口尺寸、loadContent
21
- │ │ ├─ index.cj ArkWeb 宿主组件(javaScriptProxy 双向桥)
22
- │ │ └─ app_host.cj 框架装配 + demo 命令(greet / timer)
23
- │ └─ resources/rawfile/
24
- │ ├─ index.html 页面(改这里)
25
- │ └─ capabilities.json 能力清单(改这里)
26
- ```
27
-
28
- 页面与能力清单是 **hap 里的真文件**(rawfile),运行期由 Ability 读成字符串交给框架——
29
- 所以 DevEco 里直接点 Build 也能编过,不需要先跑生成脚本。
30
-
31
- ## 构建 / 装到设备
32
-
33
- ```bash
34
- # 1) 鸿蒙版 stdx(构建期要链它)
35
- export CANGJIE_STDX_OHOS=<stdx>/linux_ohos_aarch64_cjnative/dynamic/stdx
36
-
37
- # 2) DevEco 安装根(脚本会自动探测几个常见位置,探测不到就自己给)
38
- export DEVECO_WIN='D:\Program Files\Huawei\DevEco Studio'
39
-
40
- # 3) 编 hap
41
- bash build-hap.sh
42
-
43
- # 4) 编完装到设备并拉起(需要设备已连上、应用已签名)
44
- bash build-hap.sh --install
45
- ```
46
-
47
- 改了鸿蒙侧仓颉代码却没生效时:`bash build-hap.sh --clean`(hvigor 与框架 cjpm 各有一份增量缓存)。
48
-
49
- ## 签名
50
-
51
- 模板**不带证书**(调试证书由每台机器的 DevEco 本机生成、与华为账号绑定,不该入库)。
52
- 首次打开请在 DevEco 里 File → Project Structure → Signing Configs,
53
- 勾上「Automatically generate signature」。不签名也能编(产物是 `*-unsigned.hap`),但装不进设备。
54
-
55
- ## 改应用
56
-
57
- - **加命令**:在 `app_host.cj` 里写 `CommandHandler` → `.register("名字", XxxCommand())` →
58
- 在 `entry/src/main/resources/rawfile/capabilities.json` 的 `commands` 里声明。三处缺一处就用不了
59
- (只缺注册 → `command not registered`;只缺清单 → `command not allowed`)。
60
- - **改页面**:`entry/src/main/resources/rawfile/index.html`,前端只经 `window.__CJ_TAURI__`
61
- 的 `invoke` / `listen`,并且要**等桥出现**(ArkWeb 没有 document-start 注入)。
62
- - **联网**:`module.json5` 已声明 `ohos.permission.INTERNET`;用不到就删掉。
63
- - **窗口尺寸**:`main_ability.cj` **默认不动窗口**——鸿蒙 PC 按桌面形态给的那扇窗(本机 3120×2080 屏上
64
- `2090×1394 px`,约屏宽 2/3)就是合适的大小,`logDefaultWindowRect()` 只把它读出来打一行 hilog 当凭证。
65
- 别在 `onWindowStageCreate` 里 `resize()`:系统先按默认尺寸建窗、你的 resize 紧接着改它,用户看到的是
66
- 「先弹一个尺寸、随即变成另一个」,观感就是窗口莫名跳一下(这是本模板撤掉两版自定尺寸的原因)。
67
- **真要固定尺寸**就自己调 `windowStage.getMainWindow().resize(w, h)`,两个坑记着:`resize()` 收的是**像素**
68
- 不是 vp(写 vp 量级会得到一扇很小的窗);`densityPixels` 是 **Float32**,跟 `Float64` 直接相乘编不过,
69
- 先化成整数百分比再算。
70
- 上述「系统给的就是桌面窗」的前提是 `entry/build-profile.json5` 的 `deviceTypes` 为 `2in1` 且
71
- `cangjieOptions.checkDeviceTypes=false`——写成 phone/tablet 时系统按手机应用塞进竖屏兼容窗(约 600 宽)。
72
-
73
- ## 已知边界
74
-
75
- - 只做了单窗口:`index.cj` 的 `EntryView` 挂一扇窗(label = `main`)。多窗口要按 label 各挂一个宿主。
76
- - 鸿蒙侧 `javaScriptProxy` 的**返回值传不回页面**,回投靠页面心跳 + `runJavaScript` 推送
77
- (已在 `index.cj` 的 `onProxyPost` 里做好,业务代码不用管)。
78
- - `app.run(html)` 的 `quit()` 只置退出意图,进程仍归系统管(需要真退就 `hdc shell aa force-stop`)。
79
- - 更多平台细节与踩坑:`docs/鸿蒙ArkWeb接入踩坑.md`(框架仓库内)。
1
+ # {{PROJECT_NAME}} — 仓颉 + ArkWeb 鸿蒙 PC 应用
2
+
3
+ 用 [cj-tauri](https://atomgit.com/qq8864/cj-tauri) 生成的鸿蒙 PC(2in1)应用工程:
4
+ **仓颉后端(静态编译)+ 系统 ArkWeb 前端(HTML/CSS/JS)**,IPC、能力校验、命令分发与桌面版同一套框架代码。
5
+
6
+ ## 目录
7
+
8
+ ```
9
+ {{PROJECT_NAME}}/
10
+ ├─ AppScope/app.json5 应用级配置(bundleName = {{BUNDLE_NAME}})
11
+ ├─ build-profile.json5 工程级构建配置(签名留空,见下)
12
+ ├─ build-hap.sh 构建入口(编 hap / 装到设备)
13
+ ├─ entry/
14
+ │ ├─ cjpm.toml cjTauri 依赖 + aarch64-linux-ohos 目标段
15
+ │ ├─ build-profile.json5 cangjieOptions.checkDeviceTypes=false(放行 2in1)
16
+ │ └─ src/main/
17
+ │ ├─ module.json5 deviceTypes: 2in1 / tablet / phone
18
+ │ ├─ cangjie/
19
+ │ │ ├─ ability_stage.cj AbilityStage
20
+ │ │ ├─ main_ability.cj UIAbility:沙箱、rawfile 读取、窗口尺寸、loadContent
21
+ │ │ ├─ index.cj ArkWeb 宿主组件(javaScriptProxy 双向桥)
22
+ │ │ └─ app_host.cj 框架装配 + demo 命令(greet / timer)
23
+ │ └─ resources/rawfile/
24
+ │ ├─ index.html 页面(改这里)
25
+ │ └─ capabilities.json 能力清单(改这里)
26
+ ```
27
+
28
+ 页面与能力清单是 **hap 里的真文件**(rawfile),运行期由 Ability 读成字符串交给框架——
29
+ 所以 DevEco 里直接点 Build 也能编过,不需要先跑生成脚本。
30
+
31
+ ## 构建 / 装到设备
32
+
33
+ ```bash
34
+ # 1) 鸿蒙版 stdx(构建期要链它)
35
+ export CANGJIE_STDX_OHOS=<stdx>/linux_ohos_aarch64_cjnative/dynamic/stdx
36
+
37
+ # 2) DevEco 安装根(脚本会自动探测几个常见位置,探测不到就自己给)
38
+ export DEVECO_WIN='D:\Program Files\Huawei\DevEco Studio'
39
+
40
+ # 3) 编 hap
41
+ bash build-hap.sh
42
+
43
+ # 4) 编完装到设备并拉起(需要设备已连上、应用已签名)
44
+ bash build-hap.sh --install
45
+ ```
46
+
47
+ 改了鸿蒙侧仓颉代码却没生效时:`bash build-hap.sh --clean`(hvigor 与框架 cjpm 各有一份增量缓存)。
48
+
49
+ ## 签名
50
+
51
+ 模板**不带证书**(调试证书由每台机器的 DevEco 本机生成、与华为账号绑定,不该入库)。
52
+ 首次打开请在 DevEco 里 File → Project Structure → Signing Configs,
53
+ 勾上「Automatically generate signature」。不签名也能编(产物是 `*-unsigned.hap`),但装不进设备。
54
+
55
+ ## 改应用
56
+
57
+ - **加命令**:在 `app_host.cj` 里写 `CommandHandler` → `.register("名字", XxxCommand())` →
58
+ 在 `entry/src/main/resources/rawfile/capabilities.json` 的 `commands` 里声明。三处缺一处就用不了
59
+ (只缺注册 → `command not registered`;只缺清单 → `command not allowed`)。
60
+ - **改页面**:`entry/src/main/resources/rawfile/index.html`,前端只经 `window.__CJ_TAURI__`
61
+ 的 `invoke` / `listen`,并且要**等桥出现**(ArkWeb 没有 document-start 注入)。
62
+ - **联网**:`module.json5` 已声明 `ohos.permission.INTERNET`;用不到就删掉。
63
+ - **窗口尺寸**:`main_ability.cj` **默认不动窗口**——鸿蒙 PC 按桌面形态给的那扇窗(本机 3120×2080 屏上
64
+ `2090×1394 px`,约屏宽 2/3)就是合适的大小,`logDefaultWindowRect()` 只把它读出来打一行 hilog 当凭证。
65
+ 别在 `onWindowStageCreate` 里 `resize()`:系统先按默认尺寸建窗、你的 resize 紧接着改它,用户看到的是
66
+ 「先弹一个尺寸、随即变成另一个」,观感就是窗口莫名跳一下(这是本模板撤掉两版自定尺寸的原因)。
67
+ **真要固定尺寸**就自己调 `windowStage.getMainWindow().resize(w, h)`,两个坑记着:`resize()` 收的是**像素**
68
+ 不是 vp(写 vp 量级会得到一扇很小的窗);`densityPixels` 是 **Float32**,跟 `Float64` 直接相乘编不过,
69
+ 先化成整数百分比再算。
70
+ 上述「系统给的就是桌面窗」的前提是 `entry/build-profile.json5` 的 `deviceTypes` 为 `2in1` 且
71
+ `cangjieOptions.checkDeviceTypes=false`——写成 phone/tablet 时系统按手机应用塞进竖屏兼容窗(约 600 宽)。
72
+
73
+ ## 已知边界
74
+
75
+ - 只做了单窗口:`index.cj` 的 `EntryView` 挂一扇窗(label = `main`)。多窗口要按 label 各挂一个宿主。
76
+ - 鸿蒙侧 `javaScriptProxy` 的**返回值传不回页面**,回投靠页面心跳 + `runJavaScript` 推送
77
+ (已在 `index.cj` 的 `onProxyPost` 里做好,业务代码不用管)。
78
+ - `app.run(html)` 的 `quit()` 只置退出意图,进程仍归系统管(需要真退就 `hdc shell aa force-stop`)。
79
+ - 更多平台细节与踩坑:`docs/鸿蒙ArkWeb接入踩坑.md`(框架仓库内)。
@@ -1,46 +1,46 @@
1
- {
2
- "app": {
3
- /* 签名留空:模板不随包分发证书(调试证书由每台机器的 DevEco 本机生成、与华为账号绑定,
4
- 既不该入库也无法跨机器通用)。
5
- 在 DevEco 里 File → Project Structure → Signing Configs 勾上
6
- 「Automatically generate signature」,那一步会把 signingConfigs 填满。
7
- 不签名也能 `assembleHap`(产物是 *-unsigned.hap),但装不进设备。 */
8
- "signingConfigs": [],
9
- "products": [
10
- {
11
- "name": "default",
12
- "targetSdkVersion": "6.1.1(24)",
13
- "compatibleSdkVersion": "6.1.1(24)",
14
- "runtimeOS": "HarmonyOS",
15
- "buildOption": {
16
- "strictMode": {
17
- "caseSensitiveCheck": true,
18
- "useNormalizedOHMUrl": true
19
- }
20
- }
21
- }
22
- ],
23
- "buildModeSet": [
24
- {
25
- "name": "debug",
26
- },
27
- {
28
- "name": "release"
29
- }
30
- ]
31
- },
32
- "modules": [
33
- {
34
- "name": "entry",
35
- "srcPath": "./entry",
36
- "targets": [
37
- {
38
- "name": "default",
39
- "applyToProducts": [
40
- "default"
41
- ]
42
- }
43
- ]
44
- }
45
- ]
46
- }
1
+ {
2
+ "app": {
3
+ /* 签名留空:模板不随包分发证书(调试证书由每台机器的 DevEco 本机生成、与华为账号绑定,
4
+ 既不该入库也无法跨机器通用)。
5
+ 在 DevEco 里 File → Project Structure → Signing Configs 勾上
6
+ 「Automatically generate signature」,那一步会把 signingConfigs 填满。
7
+ 不签名也能 `assembleHap`(产物是 *-unsigned.hap),但装不进设备。 */
8
+ "signingConfigs": [],
9
+ "products": [
10
+ {
11
+ "name": "default",
12
+ "targetSdkVersion": "6.1.1(24)",
13
+ "compatibleSdkVersion": "6.1.1(24)",
14
+ "runtimeOS": "HarmonyOS",
15
+ "buildOption": {
16
+ "strictMode": {
17
+ "caseSensitiveCheck": true,
18
+ "useNormalizedOHMUrl": true
19
+ }
20
+ }
21
+ }
22
+ ],
23
+ "buildModeSet": [
24
+ {
25
+ "name": "debug",
26
+ },
27
+ {
28
+ "name": "release"
29
+ }
30
+ ]
31
+ },
32
+ "modules": [
33
+ {
34
+ "name": "entry",
35
+ "srcPath": "./entry",
36
+ "targets": [
37
+ {
38
+ "name": "default",
39
+ "applyToProducts": [
40
+ "default"
41
+ ]
42
+ }
43
+ ]
44
+ }
45
+ ]
46
+ }
@@ -1,26 +1,26 @@
1
- {
2
- "apiType": "stageMode",
3
- "buildOption": {
4
- "cangjieOptions": {
5
- "path": "./cjpm.toml",
6
- /* 关掉「deviceTypes 只能写 phone/tablet」这条门禁(DevEco 仓颉插件的
7
- cangjie-pre-build.js 里 `cangjieOptions?.checkDeviceTypes !== false` 才校验)。
8
- 不关的话 module.json5 写 "2in1" 会直接判 01103012(Only phone and tablet devices
9
- are supported)——而只有声明 2in1,鸿蒙 PC 才按桌面应用开窗,否则塞进手机形态的
10
- 竖屏兼容窗(实测约 600 宽)。 */
11
- "checkDeviceTypes": false
12
- },
13
- "nativeLib": {
14
- "filter": {
15
- "enableOverride": true
16
- }
17
- }
18
- },
19
- "buildOptionSet": [
20
- ],
21
- "targets": [
22
- {
23
- "name": "default"
24
- }
25
- ]
26
- }
1
+ {
2
+ "apiType": "stageMode",
3
+ "buildOption": {
4
+ "cangjieOptions": {
5
+ "path": "./cjpm.toml",
6
+ /* 关掉「deviceTypes 只能写 phone/tablet」这条门禁(DevEco 仓颉插件的
7
+ cangjie-pre-build.js 里 `cangjieOptions?.checkDeviceTypes !== false` 才校验)。
8
+ 不关的话 module.json5 写 "2in1" 会直接判 01103012(Only phone and tablet devices
9
+ are supported)——而只有声明 2in1,鸿蒙 PC 才按桌面应用开窗,否则塞进手机形态的
10
+ 竖屏兼容窗(实测约 600 宽)。 */
11
+ "checkDeviceTypes": false
12
+ },
13
+ "nativeLib": {
14
+ "filter": {
15
+ "enableOverride": true
16
+ }
17
+ }
18
+ },
19
+ "buildOptionSet": [
20
+ ],
21
+ "targets": [
22
+ {
23
+ "name": "default"
24
+ }
25
+ ]
26
+ }