已合并
Add Cangjie-ArkTS-FFI Examples for 6.0 #392
Nixiaoxiang创建于 2025年12月23日
Add Cangjie-ArkTS-FFI Examples for 6.0 #392
已合并
Nixiaoxiang创建于 2025年12月23日
共 35 个文件变更+1272-0
@@ -0,0 +1,18 @@
1+/node_modules
2+/oh_modules
3+/local.properties
4+/.idea
5+**/build
6+/.hvigor
7+.cxx
8+/.clangd
9+/.clang-format
10+/.clang-tidy
11+**/.test
12+/.appanalyzer
13+**/cj_res
14+**/*.cj.macrocall
15+**/ability_mainability_entry.cj
16+**/module_**_entry.cj
17+**/IDL_Dependencies_List~
18+**/build-script-cache
@@ -0,0 +1,10 @@
1+{
2+ "app": {
3+ "bundleName": "com.example.cjcallarktsdemo",
4+ "vendor": "example",
5+ "versionCode": 1000000,
6+ "versionName": "1.0.0",
7+ "icon": "$media:calendar",
8+ "label": "$string:app_name"
9+ }
10+}
@@ -0,0 +1,8 @@
1+{
2+ "string": [
3+ {
4+ "name": "app_name",
5+ "value": "CJCallArkTSDemo"
6+ }
7+ ]
8+}
@@ -0,0 +1,42 @@
1+{
2+ "app": {
3+ "signingConfigs": [],
4+ "products": [
5+ {
6+ "name": "default",
7+ "signingConfig": "default",
8+ "targetSdkVersion": "6.0.0(20)",
9+ "compatibleSdkVersion": "6.0.0(20)",
10+ "runtimeOS": "HarmonyOS",
11+ "buildOption": {
12+ "strictMode": {
13+ "caseSensitiveCheck": true,
14+ "useNormalizedOHMUrl": true
15+ }
16+ }
17+ }
18+ ],
19+ "buildModeSet": [
20+ {
21+ "name": "debug",
22+ },
23+ {
24+ "name": "release"
25+ }
26+ ]
27+ },
28+ "modules": [
29+ {
30+ "name": "entry",
31+ "srcPath": "./entry",
32+ "targets": [
33+ {
34+ "name": "default",
35+ "applyToProducts": [
36+ "default"
37+ ]
38+ }
39+ ]
40+ }
41+ ]
42+}
@@ -0,0 +1,33 @@
1+{
2+ "files": [
3+ "**/*.ets",
4+ "**/*.cj"
5+ ],
6+ "ignore": [
7+ "**/src/ohosTest/**/*",
8+ "**/src/test/**/*",
9+ "**/src/mock/**/*",
10+ "**/node_modules/**/*",
11+ "**/oh_modules/**/*",
12+ "**/build/**/*",
13+ "**/.preview/**/*"
14+ ],
15+ "ruleSet": [
16+ "plugin:@performance/recommended",
17+ "plugin:@typescript-eslint/recommended"
18+ ],
19+ "rules": {
20+ "@security/no-unsafe-aes": "error",
21+ "@security/no-unsafe-hash": "error",
22+ "@security/no-unsafe-mac": "warn",
23+ "@security/no-unsafe-dh": "error",
24+ "@security/no-unsafe-dsa": "error",
25+ "@security/no-unsafe-ecdsa": "error",
26+ "@security/no-unsafe-rsa-encrypt": "error",
27+ "@security/no-unsafe-rsa-sign": "error",
28+ "@security/no-unsafe-rsa-key": "error",
29+ "@security/no-unsafe-dsa-key": "error",
30+ "@security/no-unsafe-dh-key": "error",
31+ "@security/no-unsafe-3des": "error"
32+ }
33+}
@@ -0,0 +1,8 @@
1+/node_modules
2+/oh_modules
3+/.preview
4+/build
5+/.cxx
6+/.test
7+**/IDL_Dependencies_List~
8+**/build-script-cache
@@ -0,0 +1,20 @@
1+{
2+ "apiType": "stageMode",
3+ "buildOption": {
4+ "cangjieOptions": {
5+ "path": "./cjpm.toml"
6+ },
7+ "nativeLib": {
8+ "filter": {
9+ "enableOverride": true
10+ }
11+ }
12+ },
13+ "buildOptionSet": [
14+ ],
15+ "targets": [
16+ {
17+ "name": "default"
18+ }
19+ ]
20+}
@@ -0,0 +1,3 @@
1+version = 0
2+ 
3+[requires]
@@ -0,0 +1,35 @@
1+[package]
2+ cjc-version = "0.48.2"
3+ compile-option = "--dy-std --cfg=\"${COMPILE_CONDITION_ENTRY}\""
4+ description = "CangjieUI Application"
5+ link-option = ""
6+ name = "ohos_app_cangjie_entry"
7+ output-type = "dynamic"
8+ src-dir = "./src/main/cangjie"
9+ target-dir = ""
10+ version = "1.0.0"
11+ package-configuration = {}
12+ scripts = {}
13+ 
14+[profile]
15+ [profile.build]
16+ incremental = true
17+ lto = ""
18+ [profile.build.combined]
19+ ohos_app_cangjie_entry = "dynamic"
20+ [profile.customized-option]
21+ debug = "-g -Woff all -Won apilevel-check"
22+ release = "--fast-math -O2 -s -Woff all -Won apilevel-check"
23+ [profile.test]
24+ 
25+[target.aarch64-linux-ohos]
26+ 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\""
27+[target.aarch64-linux-ohos.bin-dependencies]
28+ path-option = ["${AARCH64_LIBS}", "${AARCH64_MACRO_LIBS}", "${AARCH64_KIT_LIBS}"]
29+ package-option = {}
30+ 
31+[target.x86_64-linux-ohos]
32+ compile-option = "-B \"${DEVECO_CANGJIE_HOME}/build-tools/third_party/llvm/bin\" -B \"${DEVECO_OH_NATIVE_HOME}/sysroot/usr/lib/x86_64-linux-ohos\" -L \"${DEVECO_OH_NATIVE_HOME}/sysroot/usr/lib/x86_64-linux-ohos\" -L \"${DEVECO_OH_NATIVE_HOME}/llvm/lib/clang/15.0.4/lib/x86_64-linux-ohos\" -L \"${DEVECO_OH_NATIVE_HOME}/llvm/lib/x86_64-linux-ohos\" --sysroot \"${DEVECO_OH_NATIVE_HOME}/sysroot\""
33+[target.x86_64-linux-ohos.bin-dependencies]
34+ path-option = ["${X86_64_OHOS_LIBS}", "${X86_64_OHOS_MACRO_LIBS}", "${X86_64_OHOS_KIT_LIBS}"]
35+ 
@@ -0,0 +1,6 @@
1+import { hapTasks } from '@ohos/hvigor-ohos-plugin';
2+ 
3+export default {
4+ system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
5+ plugins: [] /* Custom plugin to extend the functionality of Hvigor. */
6+}
@@ -0,0 +1,10 @@
1+{
2+ "name": "entry",
3+ "version": "1.0.0",
4+ "description": "Please describe the basic information.",
5+ "main": "",
6+ "author": "",
7+ "license": "",
8+ "dependencies": {}
9+}
10+ 
@@ -0,0 +1,10 @@
1+package ohos_app_cangjie_entry
2+ 
3+import ohos.ability.AbilityStage
4+import ohos_app_cangjie_entry.utils.appLog
5+ 
6+class MyAbilityStage <: AbilityStage {
7+ public override func onCreate(): Unit {
8+ appLog.info("MyAbilityStage onCreated.")
9+ }
10+}
@@ -0,0 +1,27 @@
1+package ohos_app_cangjie_entry
2+ 
3+import ohos.base.*
4+import ohos.ability.*
5+import ohos.window.*
6+import ohos_app_cangjie_entry.services.CalendarService
7+ 
8+class MainAbility <: UIAbility {
9+ public init() {
10+ super()
11+ registerSelf()
12+ }
13+ 
14+ public override func onCreate(want: Want, launchParam: LaunchParam): Unit {
15+ AppLog.info("MainAbility OnCreated.${want.abilityName}")
16+ match (launchParam.launchReason) {
17+ case LaunchReason.START_ABILITY => AppLog.info("START_ABILITY")
18+ case _ => ()
19+ }
20+ CalendarService.initialize(context)
21+ }
22+ 
23+ public override func onWindowStageCreate(windowStage: WindowStage): Unit {
24+ AppLog.info("MainAbility onWindowStageCreate.")
25+ windowStage.loadContent("EntryView")
26+ }
27+}
@@ -0,0 +1,243 @@
1+/**
2+ * Created on 2025/12/22
3+ */
4+package ohos_app_cangjie_entry.services
5+ 
6+import std.time.DateTime
7+import std.collection.ArrayList
8+ 
9+import ohos.ark_interop.*
10+import ohos.base.AsyncError
11+import ohos.concurrency.launch
12+import ohos.ability_access_ctrl.*
13+import ohos.ability.UIAbilityContext
14+import ohos.ability.getStageContext
15+import ohos.ark_interop_helper.getJSContext
16+ 
17+import ohos_app_cangjie_entry.utils.appLog
18+ 
19+public class EventInfo <: Hashable & Equatable<EventInfo> {
20+ public let id: Int64
21+ public let title: String
22+ public let startTime: Int64
23+ 
24+ public init(id: Int64, title: String, startTime: Int64) {
25+ this.id = id
26+ this.title = title
27+ this.startTime = startTime
28+ }
29+ 
30+ // 实现Hashable和Equatable接口,以便在ForEach等组件中使用
31+ public func hashCode(): Int64 {
32+ this.id
33+ }
34+ 
35+ public operator func ==(that: EventInfo): Bool {
36+ this.id == that.id
37+ }
38+ 
39+ public operator func !=(that: EventInfo): Bool {
40+ this.id != that.id
41+ }
42+}
43+ 
44+public class CalendarService {
45+ private static var abilityCtx: ?UIAbilityContext = None
46+ private static var runtime: JSRuntime = JSRuntime()
47+ 
48+ /**
49+ * 初始化服务,获取并保存 UIAbilityContext
50+ */
51+ public static func initialize(abilityContext: UIAbilityContext): Unit {
52+ abilityCtx = abilityContext
53+ }
54+ 
55+ /**
56+ * 申请日历读写权限
57+ * 以下设置必须被添加到 "module"@module.json5
58+ "requestPermissions": [
59+ {
60+ "name": "ohos.permission.READ_CALENDAR",
61+ "reason": "$string:app_name",
62+ "usedScene": {
63+ "when": "always"
64+ }
65+ },
66+ {
67+ "name": "ohos.permission.WRITE_CALENDAR",
68+ "reason": "$string:app_name",
69+ "usedScene": {
70+ "when": "always"
71+ }
72+ }
73+ ]
74+ */
75+ public static func requestPermissions(onComplete: (Bool) -> Unit): Unit {
76+ let abiCtx: UIAbilityContext = abilityCtx ?? throw Exception("failed to fetch UIAbilityContext, run initialize() first.")
77+ 
78+ let permissions: Array<String> = [
79+ "ohos.permission.READ_CALENDAR",
80+ "ohos.permission.WRITE_CALENDAR"
81+ ]
82+ 
83+ let atManager: AtManager = AbilityAccessCtrl.createAtManager()
84+ 
85+ atManager.requestPermissionsFromUser(getStageContext(abiCtx), permissions) {
86+ err: ?AsyncError, data: ?PermissionRequestResult =>
87+ if (err.isSome() || data.isNone()) {
88+ appLog.error("failed to require permissions.")
89+ launch { onComplete(false) }
90+ return
91+ }
92+ let result: PermissionRequestResult = data.getOrThrow()
93+ var allGranted: Bool = true
94+ for (i in 0..result.permissions.size) {
95+ let p: String = result.permissions[i]
96+ let r: Int32 = result.authResults[i]
97+ if (r == 0) {
98+ appLog.info("permission ${p} is required.")
99+ } else {
100+ appLog.warn("permission ${p} is rejected.")
101+ allGranted = false
102+ }
103+ }
104+ let res: Bool = allGranted
105+ launch { onComplete(res) }
106+ }
107+ }
108+ 
109+ public static func addEvent(title: String, description: String, onComplete: (Int64) -> Unit): Unit {
110+ appLog.info("try to add an event: ${title}")
111+ let callback = { ctx: JSContext, calendar: JSObject =>
112+ // 调用 ArkTS 类成员方法 Calendar.addEvent 来在日历中添加事件。
113+ // 根据 Event 的 API 文档,创建一个事件对象,作为传入的参数。
114+ let eventObj = createEventObject(title, description, ctx)
115+ // 该方法是异步方法,需要异步回调。
116+ let promise = calendar.callMethod("addEvent", eventObj.toJSValue()).asPromise()
117+ promise.then(
118+ // onFulfilled
119+ ctx.function { innerCtx: JSContext, innerCallInfo: JSCallInfo =>
120+ // 从 JSCallInfo 中获取方法返回的事件 ID,是整型的。
121+ let eventId = Int64(innerCallInfo[0].asNumber().toFloat64())
122+ appLog.info("successfully added an event. event id: ${eventId}")
123+ onComplete(eventId)
124+ innerCtx.undefined().toJSValue()
125+ },
126+ // onRejected
127+ onRejected: ctx.function { innerCtx: JSContext, _: JSCallInfo =>
128+ appLog.error("failed to add an event!")
129+ onComplete(-1)
130+ innerCtx.undefined().toJSValue()
131+ }
132+ )
133+ }
134+ withCalendar(onSuccess: callback, onFailure: { => onComplete(-1) })
135+ }
136+ 
137+ public static func getEvents(onResult: (ArrayList<EventInfo>) -> Unit): Unit {
138+ appLog.info("try to get events...")
139+ let callback = { ctx: JSContext, calendar: JSObject =>
140+ let promise: JSPromise = calendar.callMethod("getEvents").asPromise()
141+ promise.then(
142+ ctx.function { innerCtx: JSContext, innerCallinfo: JSCallInfo =>
143+ let jsEvents: JSArray = innerCallinfo[0].asArray()
144+ let events: ArrayList<EventInfo> = ArrayList<EventInfo>()
145+ 
146+ for (i in 0..jsEvents.size) {
147+ let jsEvent: JSObject = jsEvents[i].asObject()
148+ let id: Int64 = Int64(jsEvent.getProperty("id").asNumber().toFloat64())
149+ let title: String = jsEvent.getProperty("title").asString().toString()
150+ let startTime: Int64 = Int64(jsEvent.getProperty("startTime").asNumber().toFloat64())
151+ events.add(EventInfo(id, title, startTime))
152+ }
153+ appLog.info("successfully got ${events.size} events.")
154+ onResult(events)
155+ innerCtx.undefined().toJSValue()
156+ },
157+ onRejected: ctx.function { innerCtx: JSContext, _: JSCallInfo =>
158+ appLog.error("failed to get events!")
159+ onResult(ArrayList<EventInfo>())
160+ innerCtx.undefined().toJSValue()
161+ }
162+ )
163+ }
164+ withCalendar(onSuccess: callback, onFailure: { => onResult(ArrayList<EventInfo>()) })
165+ }
166+ 
167+ public static func deleteEvent(eventId: Int64, onComplete: (Bool) -> Unit): Unit {
168+ appLog.info("try to delete event: ${eventId}")
169+ let callback = { ctx: JSContext, calendar: JSObject =>
170+ let eventIdValue: JSValue = ctx.number(Float64(eventId)).toJSValue()
171+ let promise: JSPromise = calendar.callMethod("deleteEvent", eventIdValue).asPromise()
172+ promise.then(
173+ ctx.function { innerCtx: JSContext, _: JSCallInfo =>
174+ appLog.info("successfully deleted event id: ${eventId}")
175+ onComplete(true)
176+ innerCtx.undefined().toJSValue()
177+ },
178+ onRejected: ctx.function { innerCtx: JSContext, _: JSCallInfo =>
179+ appLog.error("failed to delete event id: ${eventId}")
180+ onComplete(false)
181+ innerCtx.undefined().toJSValue()
182+ }
183+ )
184+ }
185+ withCalendar(onSuccess: callback, onFailure: { => onComplete(false) })
186+ }
187+ 
188+ private static func withCalendar(onSuccess!: (JSContext, JSObject) -> Unit, onFailure!: () -> Unit): Unit {
189+ let localAbilityCtx = abilityCtx ?? throw Exception("AbilityContext is not initialized!")
190+ 
191+ let jsContext: JSContext = runtime.mainContext // 互操作上下文
192+ 
193+ // 加载 calendarManager 模块
194+ let module: JSValue = jsContext.requireSystemNativeModule("calendarManager")
195+ if (module.isUndefined()) {
196+ appLog.error("load module 'calendarManager' failed!")
197+ onFailure()
198+ return
199+ }
200+ 
201+ // 调用 JS 同步接口 getCalendarManager 获取 CalendarManager 对象
202+ let tsContext: JSValue = getJSContext(runtime, localAbilityCtx) // 应用上下文
203+ let callResult: JSValue = module.asObject().callMethod("getCalendarManager", tsContext)
204+ if (callResult.isUndefined()) {
205+ appLog.error("getCalendarManager failed!")
206+ onFailure()
207+ return
208+ }
209+ let manager: JSObject = callResult.asObject()
210+ 
211+ // 调用 JS 异步接口 getCalendar,得到 JS Promise 对象,最终在 then 回调中获取 Calendar 对象
212+ let calendarPromise: JSPromise = manager.callMethod("getCalendar").asPromise()
213+ calendarPromise.then(
214+ // onFulfilled
215+ jsContext.function { ctx, callInfo =>
216+ let calendar: JSObject = callInfo[0].asObject()
217+ onSuccess(ctx, calendar)
218+ ctx.undefined().toJSValue()
219+ },
220+ // onRejected
221+ onRejected: jsContext.function { ctx, _ =>
222+ appLog.error("failed to get calendar!")
223+ onFailure()
224+ ctx.undefined().toJSValue()
225+ }
226+ )
227+ }
228+ 
229+ private static func createEventObject(title: String, description: String, ctx: JSContext): JSObject {
230+ let eventObj: JSObject = ctx.object()
231+ 
232+ let curTimeStamp: Int64 = DateTime.now().toUnixTimeStamp().toMilliseconds()
233+ let oneHour: Int64 = 3600 * 1000
234+ 
235+ eventObj.setProperty("title", ctx.string(title).toJSValue())
236+ eventObj.setProperty("description", ctx.string(description).toJSValue())
237+ eventObj.setProperty("type", ctx.number(0.0).toJSValue()) // 0 代表 EventType.NORMAL
238+ eventObj.setProperty("startTime", ctx.number(Float64(curTimeStamp)).toJSValue())
239+ eventObj.setProperty("endTime", ctx.number(Float64(curTimeStamp + oneHour)).toJSValue())
240+ 
241+ eventObj
242+ }
243+}
@@ -0,0 +1,8 @@
1+/**
2+ * Created on 2025/12/22
3+ */
4+package ohos_app_cangjie_entry.utils
5+ 
6+import ohos.hilog.HilogChannel
7+ 
8+public let appLog: HilogChannel = HilogChannel(0, 0, "CJ_DEMO")
@@ -0,0 +1,69 @@
1+/**
2+ * Created on 2025/12/22
3+ */
4+package ohos_app_cangjie_entry.views
5+ 
6+import ohos.base.*
7+import ohos.component.*
8+ 
9+extend Column {
10+ // 卡片容器样式
11+ func sectionCard() {
12+ this.width(100.percent)
13+ .padding(20)
14+ .borderRadius(15)
15+ .margin(bottom: 15)
16+ .backgroundColor(Color.WHITE)
17+ .alignItems(HorizontalAlign.Start)
18+ }
19+}
20+ 
21+extend Text {
22+ // 标题样式
23+ func sectionTitle() {
24+ this.fontSize(20)
25+ .fontWeight(FontWeight.Medium)
26+ .margin(bottom: 5)
27+ }
28+}
29+ 
30+extend TextInput {
31+ // 文本输入框样式
32+ func inputFieldStyle() {
33+ this.fontSize(16)
34+ .backgroundColor(0xF1F3F5)
35+ .borderRadius(10)
36+ .padding(10)
37+ .margin(bottom: 10)
38+ .height(50)
39+ }
40+}
41+ 
42+extend Button {
43+ // 操作按钮样式
44+ func actionButton() {
45+ this.width(100.percent)
46+ .height(50)
47+ .fontSize(18)
48+ .fontWeight(FontWeight.Medium)
49+ .borderRadius(12)
50+ }
51+}
52+ 
53+extend Divider {
54+ // 标准分割线样式
55+ func standardDivider() {
56+ this.strokeWidth(1)
57+ .color(0xEFEFEF)
58+ .margin(top: 10, bottom: 10)
59+ }
60+}
61+ 
62+extend ListItem {
63+ // 列表项样式
64+ func listItemStyle() {
65+ this.padding(10)
66+ .borderRadius(8)
67+ .backgroundColor(0xFAFAFA)
68+ }
69+}
@@ -0,0 +1,151 @@
1+/**
2+ * Created on 2025/12/22
3+ */
4+package ohos_app_cangjie_entry.views
5+ 
6+import std.collection.ArrayList
7+ 
8+import ohos.base.*
9+import ohos.component.*
10+import ohos.state_manage.*
11+import ohos.state_macro_manage.*
12+import ohos_app_cangjie_entry.services.*
13+import ohos_app_cangjie_entry.utils.appLog
14+ 
15+@Entry
16+@Component
17+public class EntryView {
18+ @State var eventTitle: String = ""
19+ @State var eventDescription: String = ""
20+ @State var eventList: ObservedArrayList<EventInfo> = ObservedArrayList<EventInfo>()
21+ @State var isLoading: Bool = true
22+ 
23+ let scroller: Scroller = Scroller()
24+ 
25+ protected override func aboutToAppear() {
26+ loadEvents()
27+ }
28+ 
29+ func loadEvents() {
30+ isLoading = true
31+ CalendarService.requestPermissions { granted: Bool =>
32+ if (granted) {
33+ CalendarService.getEvents() { events: ArrayList<EventInfo> =>
34+ eventList.clear()
35+ for (event in events) {
36+ eventList.append(event)
37+ }
38+ isLoading = false
39+ }
40+ } else {
41+ appLog.warn("Permissions denied by user. Cannot load events.")
42+ eventList.clear()
43+ isLoading = false
44+ }
45+ }
46+ }
47+ 
48+ func addEventToList() {
49+ var title: String = this.eventTitle
50+ if (title == "") {
51+ title = "默认事件"
52+ }
53+ let description: String = this.eventDescription
54+ 
55+ this.eventTitle = ""
56+ this.eventDescription = ""
57+ 
58+ CalendarService.addEvent(title, description) { id: Int64 =>
59+ if (id > 0) {
60+ appLog.info("Event added, refreshing list...")
61+ this.loadEvents()
62+ } else {
63+ appLog.error("Failed to add event from UI.")
64+ }
65+ }
66+ }
67+ 
68+ func deleteEventFromList(eventId: Int64) {
69+ CalendarService.deleteEvent(eventId) { success: Bool =>
70+ if (success) {
71+ appLog.info("Event deleted, refreshing list...")
72+ this.loadEvents()
73+ } else {
74+ appLog.error("Failed to delete event from UI.")
75+ }
76+ }
77+ }
78+ 
79+ func build() {
80+ Column {
81+ Text("日程管理演示")
82+ .fontSize(22)
83+ .width(100.percent)
84+ .textAlign(TextAlign.Center)
85+ .margin(top: 10, bottom: 20)
86+ .fontWeight(FontWeight.Medium)
87+ 
88+ Column {
89+ Text("添加新日程")
90+ .sectionTitle()
91+ 
92+ Divider()
93+ .standardDivider()
94+ 
95+ TextInput(placeholder: "请输入日程标题", text: eventTitle)
96+ .inputFieldStyle()
97+ .onChange { value: String => this.eventTitle = value }
98+ 
99+ TextInput(placeholder: "请输入日程描述", text: eventDescription)
100+ .inputFieldStyle()
101+ .onChange { value: String => this.eventDescription = value }
102+ 
103+ Button("立即添加")
104+ .actionButton()
105+ .backgroundColor(0x007DFF)
106+ .onClick { _ => addEventToList() }
107+ }
108+ .sectionCard()
109+ 
110+ Column {
111+ Text("日程列表")
112+ .sectionTitle()
113+ 
114+ Divider()
115+ .standardDivider()
116+ 
117+ Column {
118+ if (isLoading) {
119+ Text("正在加载日程...")
120+ .margin(20)
121+ .height(100.percent)
122+ .fontColor(Color.GRAY)
123+ } else if (eventList.isEmpty()) {
124+ Text("暂无日程")
125+ .margin(20)
126+ .height(100.percent)
127+ .fontColor(Color.GRAY)
128+ } else {
129+ List(space: 10, scroller: scroller) {
130+ ForEach(eventList, { item: EventInfo, _: Int64 =>
131+ ListItem {
132+ EventListItem(item: item, onDelete: { => deleteEventFromList(item.id) })
133+ }
134+ .listItemStyle()
135+ })
136+ }
137+ .width(100.percent)
138+ .scrollBar(BarState.Off)
139+ }
140+ }
141+ .height(49.percent)
142+ .width(100.percent)
143+ }
144+ .sectionCard()
145+ }
146+ .width(100.percent)
147+ .height(100.percent)
148+ .backgroundColor(0xF1F3F5)
149+ .padding(top: 20, bottom: 10.vp, left: 10.vp, right: 10.vp)
150+ }
151+}
@@ -0,0 +1,46 @@
1+/**
2+ * Created on 2025/12/22
3+ */
4+package ohos_app_cangjie_entry.views
5+ 
6+import std.time.*
7+ 
8+import ohos.base.*
9+import ohos.component.*
10+import ohos.state_manage.*
11+import ohos.state_macro_manage.*
12+ 
13+import ohos_app_cangjie_entry.services.EventInfo
14+ 
15+@Component
16+class EventListItem {
17+ @Prop var item: EventInfo
18+ var onDelete: () -> Unit
19+ 
20+ let timeFormat: String = "yyyy/MM/dd HH:mm"
21+ 
22+ func build() {
23+ Row {
24+ Column {
25+ Text(item.title)
26+ .fontSize(16)
27+ .fontWeight(FontWeight.Medium)
28+ Text("${DateTime.fromUnixTimeStamp(Duration.millisecond * item.startTime).format(timeFormat)}")
29+ .fontSize(12)
30+ .margin(top: 4)
31+ .fontColor(Color.GRAY)
32+ }
33+ .alignItems(HorizontalAlign.Start)
34+ 
35+ Button("删除")
36+ .height(36)
37+ .borderRadius(8)
38+ .fontColor(Color.WHITE)
39+ .backgroundColor(0xec0000)
40+ .onClick { _ => onDelete() }
41+ }
42+ .height(48)
43+ .width(100.percent)
44+ .justifyContent(FlexAlign.SpaceBetween)
45+ }
46+}
@@ -0,0 +1,54 @@
1+{
2+ "module": {
3+ "name": "entry",
4+ "type": "entry",
5+ "description": "$string:module_desc",
6+ "mainElement": "EntryAbility",
7+ "deviceTypes": [
8+ "phone",
9+ "tablet",
10+ "2in1"
11+ ],
12+ "requestPermissions": [
13+ {
14+ "name": "ohos.permission.READ_CALENDAR",
15+ "reason": "$string:app_name",
16+ "usedScene": {
17+ "when": "always"
18+ }
19+ },
20+ {
21+ "name": "ohos.permission.WRITE_CALENDAR",
22+ "reason": "$string:app_name",
23+ "usedScene": {
24+ "when": "always"
25+ }
26+ }
27+ ],
28+ "deliveryWithInstall": true,
29+ "installationFree": false,
30+ "srcEntry": "ohos_app_cangjie_entry.MyAbilityStage",
31+ "abilities": [
32+ {
33+ "name": "EntryAbility",
34+ "srcEntry": "ohos_app_cangjie_entry.MainAbility",
35+ "description": "$string:EntryAbility_desc",
36+ "icon": "$media:calendar",
37+ "label": "$string:EntryAbility_label",
38+ "startWindowIcon": "$media:calendar",
39+ "startWindowBackground": "$color:start_window_background",
40+ "exported": true,
41+ "skills": [
42+ {
43+ "entities": [
44+ "entity.system.home"
45+ ],
46+ "actions": [
47+ "action.system.home"
48+ ]
49+ }
50+ ]
51+ }
52+ ]
53+ }
54+}
@@ -0,0 +1,8 @@
1+{
2+ "color": [
3+ {
4+ "name": "start_window_background",
5+ "value": "#FFFFFF"
6+ }
7+ ]
8+}
@@ -0,0 +1,16 @@
1+{
2+ "string": [
3+ {
4+ "name": "module_desc",
5+ "value": "module description"
6+ },
7+ {
8+ "name": "EntryAbility_desc",
9+ "value": "description"
10+ },
11+ {
12+ "name": "EntryAbility_label",
13+ "value": "Calendar"
14+ }
15+ ]
16+}
@@ -0,0 +1,40 @@
1+[package]
2+ cjc-version = "0.48.2"
3+ compile-option = "--dy-std --cfg=\"${COMPILE_CONDITION_ENTRY}\""
4+ description = "CangjieUI Application"
5+ link-option = "--unresolved-symbols=ignore-all"
6+ name = "ohos_app_cangjie_entry_test"
7+ output-type = "dynamic"
8+ src-dir = "."
9+ target-dir = ""
10+ version = "1.0.0"
11+ package-configuration = {}
12+ scripts = {}
13+ 
14+[dependencies]
15+ [dependencies.ohos_app_cangjie_entry]
16+ path = "../../../"
17+ version = "1.0.0"
18+ 
19+[profile]
20+ [profile.build]
21+ incremental = true
22+ lto = ""
23+ [profile.customized-option]
24+ debug = "-g -Woff all -Won apilevel-check"
25+ release = "--fast-math -O2 -s -Woff all -Won apilevel-check"
26+ withoutCoverage = "--cfg=\"coverage=false\""
27+ withCoverage = "--cfg=\"coverage=true\""
28+ [profile.test]
29+ 
30+[target.aarch64-linux-ohos]
31+ 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\""
32+[target.aarch64-linux-ohos.bin-dependencies]
33+ path-option = ["${AARCH64_LIBS}", "${AARCH64_MACRO_LIBS}", "${AARCH64_KIT_LIBS}"]
34+ package-option = {}
35+ 
36+[target.x86_64-linux-ohos]
37+ compile-option = "-B \"${DEVECO_CANGJIE_HOME}/build-tools/third_party/llvm/bin\" -B \"${DEVECO_OH_NATIVE_HOME}/sysroot/usr/lib/x86_64-linux-ohos\" -L \"${DEVECO_OH_NATIVE_HOME}/sysroot/usr/lib/x86_64-linux-ohos\" -L \"${DEVECO_OH_NATIVE_HOME}/llvm/lib/clang/15.0.4/lib/x86_64-linux-ohos\" -L \"${DEVECO_OH_NATIVE_HOME}/llvm/lib/x86_64-linux-ohos\" --sysroot \"${DEVECO_OH_NATIVE_HOME}/sysroot\""
38+[target.x86_64-linux-ohos.bin-dependencies]
39+ path-option = ["${X86_64_OHOS_LIBS}", "${X86_64_OHOS_MACRO_LIBS}", "${X86_64_OHOS_KIT_LIBS}"]
40+ 
@@ -0,0 +1,14 @@
1+/**
2+ * Created on 2025/2/26
3+ */
4+package ohos_app_cangjie_entry_test
5+ 
6+import std.unittest.expectEqual
7+import std.unittest.testmacro.Expect
8+ 
9+func unittest() {
10+ let a = "abc"
11+ let b = "b"
12+ @Expect(a.contains(b))
13+ @Expect(a, a)
14+}
@@ -0,0 +1,17 @@
1+package ohos_app_cangjie_entry_test
2+ 
3+import std.unittest.TestClass
4+import std.unittest.TestPackage
5+import std.unittest.TestSuite
6+import std.unittest.UnitTestCase
7+import std.unittest.common.Configuration
8+import std.unittest.testmacro.Test
9+import std.unittest.testmacro.TestCase
10+ 
11+@Test
12+class TestExample00 {
13+ @TestCase
14+ func test00(): Unit {
15+ unittest()
16+ }
17+}
@@ -0,0 +1,9 @@
1+package ohos_app_cangjie_entry_test
2+ 
3+import ohos_app_cangjie_entry_test.unittest_support.registerTestSuite
4+ 
5+private let register = testsuite()
6+ 
7+func testsuite() {
8+ registerTestSuite {TestExample00()}
9+}
@@ -0,0 +1,246 @@
1+package ohos_app_cangjie_entry_test.unittest_support
2+ 
3+import ohos.test_runner.TestRunner
4+import ohos.hilog.HilogChannel
5+import ohos.ability_delegator_registry.AbilityDelegatorRegistry
6+import std.unittest.XmlReporter
7+import std.fs.Path
8+import std.fs.Directory
9+import std.collection.filter
10+import std.fs.FileInfo
11+import std.collection.first
12+import std.fs.File
13+import std.collection.forEach
14+import std.convert.Parsable
15+import ohos.bundle_manager.BundleManager
16+import ohos.bundle_manager.BundleFlag
17+import std.collection.any
18+import std.collection.HashMap
19+import std.unittest.TestClass
20+import std.collection.ArrayList
21+import std.unittest.TestSuite
22+import ohos.ability.Want
23+import std.process.Process
24+import ohos.ui_test.UITest
25+import std.unittest.common.Configuration
26+ 
27+@When[coverage == "true"]
28+foreign func __gcov_dump(): Unit
29+ 
30+@When[coverage == "true"]
31+public func gcov_dump(coveragePath: String): Unit {
32+ let logger = HilogChannel(0, 0, "CangjieTest")
33+ logger.info("execute test with coverage")
34+ unsafe { __gcov_dump() }
35+ let abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
36+ abilityDelegator.print("GENERATE_COVERAGE: ${coveragePath}")
37+}
38+ 
39+@When[coverage == "false"]
40+public func gcov_dump(coveragePath: String): Unit {
41+ let logger = HilogChannel(0, 0, "CangjieTest")
42+ logger.info("execute test without coverage")
43+}
44+ 
45+public func registerTestSuite(testClassInstanceGenerator: () -> TestClass): Unit {
46+ OpenHarmonyTestRunner
47+ .testClassInstanceGenerators
48+ .add(testClassInstanceGenerator)
49+}
50+ 
51+public class OpenHarmonyTestRunner <: TestRunner {
52+ private static let logger = HilogChannel(0, 0, "CangjieTest")
53+ public static let testSuiteMap = HashMap<String, TestSuite>()
54+ public static let testClassInstanceGenerators = ArrayList<() -> TestClass>()
55+ private static func getDetailedInfoOf(e: Exception): String {
56+ let sb = StringBuilder("exception: ${e.toString()}\n")
57+ e.getStackTrace() |>
58+ forEach {
59+ s => sb.append(" at ${s.declaringClass}.${s.methodName}(${s.fileName}:${s.lineNumber})\n")
60+ }
61+ sb.toString()
62+ }
63+ 
64+ private func executeTestClass(testClassName: String): Unit {
65+ let abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
66+ logger.info("EXECUTE_CLASS_START: \"${testClassName}\"")
67+ abilityDelegator.print("EXECUTE_CLASS_START: \"${testClassName}\"")
68+ let testSuite = match (OpenHarmonyTestRunner
69+ .testSuiteMap
70+ .get(testClassName)) {
71+ case None => return
72+ case Some(testClassInstanceGenerator) => testClassInstanceGenerator
73+ }
74+ 
75+ testSuite
76+ .runTests()
77+ .reportTo(XmlReporter(Path("/data/storage/el1/base")))
78+ 
79+ let testReportXmlFileName = "test-default.${testClassName}.xml"
80+ match (Directory.readFrom("/data/storage/el1/base/tests") |>
81+ filter {fileInfo => fileInfo.name == testReportXmlFileName} |> first) {
82+ case None => logger.error("${testReportXmlFileName} not found.")
83+ case Some(testReportXmlFileInfo) =>
84+ let testReportXmlFilePath = testReportXmlFileInfo.path
85+ let testReportXmlFileContent = File.readFrom(testReportXmlFilePath)
86+ let xmlReport = String.fromUtf8(testReportXmlFileContent)
87+ logger.info("XML_REPORT_CONTENT_LENGTH: ${xmlReport.size}")
88+ logger.info(xmlReport)
89+ abilityDelegator.print("XML_REPORT_CONTENT_LENGTH: ${xmlReport.size}")
90+ abilityDelegator.print(xmlReport)
91+ logger.info("EXECUTE_CLASS_END: \"${testClassName}\"")
92+ abilityDelegator.print("EXECUTE_CLASS_END: \"${testClassName}\"")
93+ reportTestReport("test-default.${testClassName}.xml")
94+ }
95+ }
96+ private func executeAllTestClasses(): Unit {
97+ for (testClassName in OpenHarmonyTestRunner
98+ .testSuiteMap
99+ .keys()) {
100+ executeTestClass(testClassName)
101+ }
102+ }
103+ private func executeTestCase(testClassName: String, testCaseName: String): Unit {
104+ let abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
105+ abilityDelegator.print("EXECUTE_CLASS_START: \"${testClassName}\"")
106+ logger.info("EXECUTE_METHOD_START: \"${testClassName}#${testCaseName}\"")
107+ let testSuite = match (OpenHarmonyTestRunner
108+ .testSuiteMap
109+ .get(testClassName)) {
110+ case None => return
111+ case Some(testClassInstanceGenerator) => testClassInstanceGenerator
112+ }
113+ let configuration = Configuration()
114+ configuration.setByName("filter", "${testClassName}.${testCaseName}")
115+ testSuite
116+ .runTests(configuration)
117+ .reportTo(XmlReporter(Path("/data/storage/el1/base")))
118+ 
119+ let testReportXmlFileName = "test-default.${testClassName}.xml"
120+ match (Directory.readFrom("/data/storage/el1/base/tests") |>
121+ filter {fileInfo => fileInfo.name == testReportXmlFileName} |> first) {
122+ case None => logger.error("${testReportXmlFileName} not found.")
123+ case Some(testReportXmlFileInfo) =>
124+ let testReportXmlFilePath = testReportXmlFileInfo.path
125+ let testReportXmlFileContent = File.readFrom(testReportXmlFilePath)
126+ let xmlReport = String.fromUtf8(testReportXmlFileContent)
127+ logger.info("XML_REPORT_CONTENT_LENGTH: ${xmlReport.size}")
128+ logger.info(xmlReport)
129+ abilityDelegator.print("XML_REPORT_CONTENT_LENGTH: ${xmlReport.size}")
130+ abilityDelegator.print(xmlReport)
131+ logger.info("EXECUTE_METHOD_END: \"${testClassName}#${testCaseName}\"")
132+ abilityDelegator.print("EXECUTE_CLASS_END: \"${testClassName}\"")
133+ reportTestReport("test-default.${testClassName}.xml")
134+ }
135+ }
136+ private func reportTestReport(testReportName: String): Unit {
137+ let abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
138+ let abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments()
139+ let bundleName = abilityDelegatorArguments.bundleName
140+ abilityDelegator.print("REPORT_TEST_RESULT: /data/app/el1/100/base/${bundleName}/tests/${testReportName}")
141+ }
142+ public override func onPrepare(): Unit {
143+ logger.info("OpenHarmonyTestRunner onPrepare")
144+ for (testClassInstanceGenerator in OpenHarmonyTestRunner.testClassInstanceGenerators) {
145+ let testClassInstance = try {
146+ testClassInstanceGenerator()
147+ } catch (e: Exception) {
148+ logger.error("exception occurred during testsuite generation:\n${getDetailedInfoOf(e)}")
149+ continue
150+ }
151+ let testSuite = testClassInstance.asTestSuite()
152+ let testSuiteName = testSuite.name
153+ logger.info("Registering TestSuite ${testSuiteName}")
154+ OpenHarmonyTestRunner
155+ .testSuiteMap
156+ .add(testSuiteName, testSuite)
157+ }
158+ }
159+ public override func onRun(): Unit {
160+ logger.info("OpenHarmonyTestRunner onRun")
161+ let abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments()
162+ let abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
163+ UITest.setup()
164+ logger.info("bundleName = ${abilityDelegatorArguments.bundleName}")
165+ logger.info("abilityDelegatorArguments.testRunnerClassName = ${abilityDelegatorArguments.testRunnerClassName}")
166+ logger.info("abilityDelegatorArguments.testCaseNames = ${abilityDelegatorArguments.testCaseNames}")
167+ logger.info("abilityDelegatorArguments.parameters = ${abilityDelegatorArguments.parameters}")
168+ logger.info("Started running tests.")
169+ abilityDelegator.print("OpenHarmonyTestRunner onRun")
170+ let parameters = abilityDelegatorArguments.parameters
171+ let bundleName = abilityDelegatorArguments.bundleName
172+ let bundleInfo = BundleManager.getBundleInfoForSelf(
173+ BundleFlag
174+ .GET_BUNDLE_INFO_WITH_HAP_MODULE
175+ .getValue() | BundleFlag
176+ .GET_BUNDLE_INFO_WITH_APPLICATION
177+ .getValue())
178+ let moduleName = match (parameters.get("-m")) {
179+ case None =>
180+ abilityDelegator.finishTest("Module name was not specified.", -1)
181+ return
182+ case Some(moduleName) =>
183+ if (bundleInfo.hapModulesInfo |> any {hapModuleInfo => hapModuleInfo.name == moduleName}) {
184+ moduleName
185+ } else {
186+ abilityDelegator.finishTest(
187+ "No module with name \"${moduleName}\" was found in bundle ${bundleName}.", -1)
188+ return
189+ }
190+ }
191+ let abilityName = match (bundleInfo.hapModulesInfo |> filter {hapModuleInfo => hapModuleInfo.name == moduleName} |>
192+ first) {
193+ case None =>
194+ abilityDelegator.finishTest("No module with name \"${moduleName}\" was found in bundle ${bundleName}.",
195+ -1)
196+ return
197+ case Some(hapModuleInfo) =>
198+ let mainElementName = hapModuleInfo.mainElementName
199+ logger.info("mainElementName = ${mainElementName}")
200+ mainElementName
201+ }
202+ let want = Want(bundleName: bundleName, moduleName: moduleName, abilityName: abilityName)
203+ abilityDelegator
204+ .startAbility(want)
205+ .get()
206+ let timeOut = match (parameters.get("-s timeout")) {
207+ case None => None<Int64>
208+ case Some(timeOutText) => match (Int64.tryParse(timeOutText)) {
209+ case None =>
210+ abilityDelegator.finishTest("The parameter \"timeout\": ${timeOutText} is invalid", -1)
211+ return
212+ case Some(timeOutValue) => timeOutValue
213+ }
214+ }
215+ spawn {
216+ try {
217+ match (parameters.get("-s class")) {
218+ case None => executeAllTestClasses()
219+ case Some(text) => text.split(",", removeEmpty: true) |>
220+ forEach {
221+ t: String =>
222+ let pair = t.split("#", removeEmpty: true)
223+ let testClassName = match (pair.get(0)) {
224+ case None => return
225+ case Some(text) => text.trimAscii()
226+ }
227+ match (pair.get(1)) {
228+ case None => executeTestClass(testClassName)
229+ case Some(testCaseName) => executeTestCase(testClassName, testCaseName)
230+ }
231+ }
232+ }
233+ } catch (e: Exception) {
234+ logger.error("an exception occurred:\n${getDetailedInfoOf(e)}")
235+ }
236+ Process
237+ .current
238+ .setEnv("GCOV_PREFIX", "/data/storage/el1/base/cov")
239+ gcov_dump("/data/app/el1/100/base/${bundleName}/cov/")
240+ 
241+ abilityDelegator.finishTest("Test finished.", 0)
242+ }
243+ }
244+}
245+ 
246+let _ = TestRunner.registerCreator("OpenHarmonyTestRunner") {OpenHarmonyTestRunner()}
@@ -0,0 +1,21 @@
1+[package]
2+ cjc-version = "0.48.2"
3+ compile-option = "--dy-std --cfg=\"${COMPILE_CONDITION_ENTRY}\""
4+ description = "CangjieUI Application"
5+ link-option = ""
6+ name = "ohos_app_cangjie_entry_local_test"
7+ output-type = "dynamic"
8+ src-dir = "."
9+ target-dir = ""
10+ version = "1.0.0"
11+ package-configuration = {}
12+ scripts = {}
13+ 
14+[profile]
15+ [profile.build]
16+ incremental = true
17+ lto = ""
18+ [profile.customized-option]
19+ debug = "-g -Woff all -Won apilevel-check"
20+ release = "--fast-math -O2 -s -Woff all -Won apilevel-check"
21+ [profile.test]
@@ -0,0 +1,14 @@
1+/**
2+ * Created on 2025/2/26
3+ */
4+package ohos_app_cangjie_entry_local_test
5+ 
6+import std.unittest.expectEqual
7+import std.unittest.testmacro.Expect
8+ 
9+func unittest() {
10+ let a = "abc"
11+ let b = "b"
12+ @Expect(a.contains(b))
13+ @Expect(a, a)
14+}
@@ -0,0 +1,17 @@
1+package ohos_app_cangjie_entry_local_test
2+ 
3+import std.unittest.TestClass
4+import std.unittest.TestPackage
5+import std.unittest.TestSuite
6+import std.unittest.UnitTestCase
7+import std.unittest.common.Configuration
8+import std.unittest.testmacro.Test
9+import std.unittest.testmacro.TestCase
10+ 
11+@Test
12+class TestExample00 {
13+ @TestCase
14+ func test00(): Unit {
15+ unittest()
16+ }
17+}
@@ -0,0 +1,23 @@
1+{
2+ "modelVersion": "6.0.0",
3+ "dependencies": {
4+ },
5+ "execution": {
6+ // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | "ultrafine" | false ]. Default: "normal" */
7+ // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */
8+ // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */
9+ // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */
10+ // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */
11+ // "optimizationStrategy": "memory" /* Define the optimization strategy. Value: [ "memory" | "performance" ]. Default: "memory" */
12+ },
13+ "logging": {
14+ // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */
15+ },
16+ "debugging": {
17+ // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */
18+ },
19+ "nodeOptions": {
20+ // "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/
21+ // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/
22+ }
23+}
@@ -0,0 +1,6 @@
1+import { appTasks } from '@ohos/hvigor-ohos-plugin';
2+ 
3+export default {
4+ system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
5+ plugins: [] /* Custom plugin to extend the functionality of Hvigor. */
6+}
@@ -0,0 +1,28 @@
1+{
2+ "meta": {
3+ "stableOrder": true,
4+ "enableUnifiedLockfile": false
5+ },
6+ "lockfileVersion": 3,
7+ "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
8+ "specifiers": {
9+ "@ohos/hamock@1.0.0": "@ohos/hamock@1.0.0",
10+ "@ohos/hypium@1.0.24": "@ohos/hypium@1.0.24"
11+ },
12+ "packages": {
13+ "@ohos/hamock@1.0.0": {
14+ "name": "",
15+ "version": "1.0.0",
16+ "integrity": "sha512-K6lDPYc6VkKe6ZBNQa9aoG+ZZMiwqfcR/7yAVFSUGIuOAhPvCJAo9+t1fZnpe0dBRBPxj2bxPPbKh69VuyAtDg==",
17+ "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hamock/-/hamock-1.0.0.har",
18+ "registryType": "ohpm"
19+ },
20+ "@ohos/hypium@1.0.24": {
21+ "name": "",
22+ "version": "1.0.24",
23+ "integrity": "sha512-3dCqc+BAR5LqEGG2Vtzi8O3r7ci/3fYU+FWjwvUobbfko7DUnXGOccaror0yYuUhJfXzFK0aZNMGSnXaTwEnbw==",
24+ "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hypium/-/hypium-1.0.24.har",
25+ "registryType": "ohpm"
26+ }
27+ }
28+}
@@ -0,0 +1,10 @@
1+{
2+ "modelVersion": "6.0.0",
3+ "description": "Please describe the basic information.",
4+ "dependencies": {
5+ },
6+ "devDependencies": {
7+ "@ohos/hypium": "1.0.24",
8+ "@ohos/hamock": "1.0.0"
9+ }
10+}