diff --git a/code/UI/NdkBuildOnMultiThread/.gitignore b/code/UI/NdkBuildOnMultiThread/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..d2ff20141ceed86d87c0ea5d99481973005bab2b --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/.gitignore @@ -0,0 +1,12 @@ +/node_modules +/oh_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +**/.test +/.appanalyzer \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/AppScope/app.json5 b/code/UI/NdkBuildOnMultiThread/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..30162cae2c5ec8aca41c97cf696805785601cf3f --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/AppScope/app.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "app": { + "bundleName": "com.samples.NdkBuildOnMultiThread", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:layered_image", + "label": "$string:app_name" + } +} diff --git a/code/UI/NdkBuildOnMultiThread/AppScope/resources/base/element/string.json b/code/UI/NdkBuildOnMultiThread/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..d71e5ead1ce20b4ac3384d18e6d104f1ea4d83b4 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "MyApplication" + } + ] +} diff --git a/code/UI/NdkBuildOnMultiThread/AppScope/resources/base/media/background.png b/code/UI/NdkBuildOnMultiThread/AppScope/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f Binary files /dev/null and b/code/UI/NdkBuildOnMultiThread/AppScope/resources/base/media/background.png differ diff --git a/code/UI/NdkBuildOnMultiThread/AppScope/resources/base/media/foreground.png b/code/UI/NdkBuildOnMultiThread/AppScope/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..97014d3e10e5ff511409c378cd4255713aecd85f Binary files /dev/null and b/code/UI/NdkBuildOnMultiThread/AppScope/resources/base/media/foreground.png differ diff --git a/code/UI/NdkBuildOnMultiThread/AppScope/resources/base/media/layered_image.json b/code/UI/NdkBuildOnMultiThread/AppScope/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/AppScope/resources/base/media/layered_image.json @@ -0,0 +1,7 @@ +{ + "layered-image": + { + "background" : "$media:background", + "foreground" : "$media:foreground" + } +} \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/README.md b/code/UI/NdkBuildOnMultiThread/README.md new file mode 100644 index 0000000000000000000000000000000000000000..a1c07d7ea0cf2d2eec81165437e619e694f656bf --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/README.md @@ -0,0 +1,219 @@ +# 使用NDK多线程创建UI组件 + +### 介绍 + +本示例介绍如何使用多线程NDK接口在非UI线程创建UI组件,从而优化组件创建耗时和响应时延。 + +### 效果图预览 + + + + + + + +**使用说明** + +1. 点击CreatePageOnMultiThread按钮,触发多线程创建UI页面; +2. 点击CreatePageOnUIThread按钮,触发在UI线程创建UI页面。 + +### 实现思路 + +场景一:点击CreatePageOnMultiThread按钮,跳转到多线程创建的UI页面,页面内的UI组件在非UI线程创建; + +场景二:点击CreatePageOnUIThread按钮,跳转到UI线程创建的UI页面,页面内的UI组件在UI线程创建。 + +1. CAPIComponent自定义组件用于挂载通过NDK创建的组件树。源码参考[Page.ets](./entry/src/main/ets/pages/Page.ets),根据isOnUIThread的状态分别调用CreateNodeTreeOnUIThread在UI线程创建组件和CreateNodeTreeOnMultiThread在多线程创建组件。 +```ts +import { NodeContent, router } from '@kit.ArkUI'; +import entry from 'libentry.so'; + +@Component +struct CAPIComponent { + private rootSlot = new NodeContent(); + @State isOnUIThread: boolean = false; + + aboutToAppear(): void { + if (this.isOnUIThread) { + // 调用C-API接口在UI线程创建组件 + entry.CreateNodeTreeOnUIThread(this.rootSlot, this.getUIContext()); + } else { + // 调用C-API接口多线程创建组件 + entry.CreateNodeTreeOnMultiThread(this.rootSlot, this.getUIContext()); + } + } + + aboutToDisappear(): void { + // 释放已创建的C-API组件 + entry.DisposeNodeTree(this.rootSlot); + } + + build() { + Column() { + // C-API组件挂载点 + ContentSlot(this.rootSlot) + } + .width('100%') + } +} +``` +2. CreateNodeTreeOnMultiThread是对ArkTs暴露的NDK接口,此接口负责多线程创建UI组件。示例中把页面中的每个卡片拆分为一个子任务,分别调用OH_ArkUI_PostAsyncUITask接口在非UI线程创建卡片对应的UI组件树。源码参考[NodeCreator.cpp](./entry/src/main/cpp/node/NodeCreator.cpp) +```cpp +napi_value CreateNodeTreeOnMultiThread(napi_env env, napi_callback_info info) { + size_t argc = 2; + napi_value args[2] = { nullptr, nullptr }; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + ArkUI_NodeContentHandle contentHandle; + int32_t result = OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "OH_ArkUI_GetNodeContentFromNapiValue Failed %{public}d", result); + return nullptr; + } + ArkUI_ContextHandle contextHandle; + result = OH_ArkUI_GetContextFromNapiValue(env, args[1], &contextHandle); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "OH_ArkUI_GetContextFromNapiValue Failed %{public}d", result); + return nullptr; + } + + auto scrollNode = std::make_shared(); + scrollNode->SetScrollBarDisplayMode(ARKUI_SCROLL_BAR_DISPLAY_MODE_OFF); + result = OH_ArkUI_NodeContent_AddNode(contentHandle, scrollNode->GetHandle()); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "OH_ArkUI_NodeContent_AddNode Failed %{public}d", result); + return nullptr; + } + g_nodeMap[contentHandle] = scrollNode; + + auto columnNode = std::make_shared(); + scrollNode->AddChild(columnNode); + + for (int32_t i=0;i(); + columnItem->SetMargin(8,0,8,0); + columnNode->AddChild(columnItem); + AsyncData* asyncData = new AsyncData(); + asyncData->parent = columnItem; + asyncData->cardInfo = g_cardTypeInfos[i]; + // 在非UI线程创建组件树,创建完成后回到主线程挂载到主树上 + result = OH_ArkUI_PostAsyncUITask(contextHandle, asyncData, CreateCardNodeTree, MountNodeTree); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "OH_ArkUI_PostAsyncUITask Failed %{public}d", result); + delete asyncData; + } + } + return nullptr; +} +``` + +3. CreateCardNodeTree会在非UI线程被调用,根据卡片类型创建对应的UI组件树并设置属性。源码参考[NodeCreator.cpp](./entry/src/main/cpp/node/NodeCreator.cpp) + +```cpp +void CreateCardNodeTree(void *asyncUITaskData) { + auto asyncData = static_cast(asyncUITaskData); + if (!asyncData) { + return; + } + + if (asyncData->cardInfo.type == "App") { + AppCardInfo info = asyncData->cardInfo.appCardInfo; + asyncData->child = CreateAppCard(info); + } else if (asyncData->cardInfo.type == "Service") { + ServiceCardInfo info = asyncData->cardInfo.serviceCardInfo;; + asyncData->child = CreateServiceCard(info); + } +} +``` + +4. CreateCardNodeTree执行完成后,MountNodeTree会在UI线程被调用,将子线程创建好的UI组件树挂载到UI主树上,使其可以在页面上显示出来。源码参考[NodeCreator.cpp](./entry/src/main/cpp/node/NodeCreator.cpp) + +```cpp +void MountNodeTree(void *asyncUITaskData) { + auto asyncData = static_cast(asyncUITaskData); + if (!asyncData) { + return; + } + auto parent = asyncData->parent; + auto child = asyncData->child; + parent->AddChild(child); + delete asyncData; +} +``` + +### 性能对比 + +本示例使用了多线程NDK接口在非UI线程创建UI组件,减少了UI线程组件创建布局耗时,优化了页面跳转响应时延。 + +- 使用UI线程创建UI组件 + +![build_on_ui_thread_trace](figures/build_on_ui_thread_trace.png) + +- 使用多线程创建UI组件 + +![build_on_multi_thread_trace](figures/build_on_multi_thread_trace.png) + +| | UI线程创建 | 多线程创建 | 优化比例 | +| -------- | -------- | -------- | -------- | +| UI线程组件创建耗时 | 41.3ms | 5.6ms | 86.4% | +| UI线程组件创建布局耗时 | 157.7ms | 129.9ms | 17.5% | +| 响应时延 | 216.4ms | 56.2ms | 74.0% | + +### 工程结构&模块类型 + + ``` + |entry/src/main/cpp + | |---card + | | |---CardCreator.cpp // UI卡片创建器实现类 + | | |---CardCreator.h // UI卡片创建器声明 + | |---common + | | |---ArkUIBaseNode.h // NativeNode封装类,实现组件树操作 + | | |---ArkUINode.h // 派生ArkUIBaseNode类,实现属性设置操作 + | | |---NativeModule.h // NDK接口集合获取类 + | |---data + | | |---MockData.h // 定义UI卡片内容数据 + | |---node + | | |---NodeCreator.cpp // UI组件树创建器实现 + | | |---NodeCreator.h // UI组件树创建器声明 + | | |---TypedArkUINode.h // 不同类型UI组件封装类 + |entry/src/main/ets + | |---entryablity + | | |---EntryAbility.ts // 程序入口类 + | |---pages + | | |---Index.ets // 首页 + | | |---Page.ets // NDK组件页面 + ``` + +### 参考资料 + +[NDK支持多线程创建组件](https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/ui/ndk-build-on-multi-thread.md) + +[多线程NDK接口说明](https://docs.openharmony.cn/pages/v5.0/zh-cn/application-dev/ui/ndk-build-on-multi-thread-api.md) + +### 相关权限 + +不涉及。 + +### 依赖 + +不涉及。 + +### 约束与限制 + +1.本示例仅支持标准系统上运行。 + +2.本示例为Stage模型,支持API20版本SDK,SDK版本号(API Version 20 Release)。 + +3.本示例需要使用DevEco Studio版本号(DevEco Studio 5.0.0 Release)及以上版本才可编译运行。 + +### 下载 + +如需单独下载本工程,执行如下命令: + +```shell +git init +git config core.sparsecheckout true +echo code/UI/NdkBuildOnMultiThread/ > .git/info/sparse-checkout +git remote add origin https://gitee.com/openharmony/applications_app_samples.git +git pull origin master \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/build-profile.json5 b/code/UI/NdkBuildOnMultiThread/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..0a9a0f05c71cbefa5bf8073ed263bc05b4bd05c2 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/build-profile.json5 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "app": { + "signingConfigs": [ + ], + "products": [ + { + "name": "default", + "signingConfig": "default", + "targetSdkVersion": 20, + "compatibleSdkVersion": 20, + "compileSdkVersion": 20, + "runtimeOS": "OpenHarmony", + "buildOption": { + "strictMode": { + "caseSensitiveCheck": true + } + } + } + ], + "buildModeSet": [ + { + "name": "debug", + }, + { + "name": "release" + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/code-linter.json5 b/code/UI/NdkBuildOnMultiThread/code-linter.json5 new file mode 100644 index 0000000000000000000000000000000000000000..ed05653cca31b61d64cf6471529eaf50d4f70709 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/code-linter.json5 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "files": [ + "**/*.ets" + ], + "ignore": [ + "**/src/ohosTest/**/*", + "**/src/test/**/*", + "**/src/mock/**/*", + "**/node_modules/**/*", + "**/oh_modules/**/*", + "**/build/**/*", + "**/.preview/**/*" + ], + "ruleSet": [ + "plugin:@performance/recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + "@security/no-unsafe-aes": "error", + "@security/no-unsafe-hash": "error", + "@security/no-unsafe-mac": "warn", + "@security/no-unsafe-dh": "error", + "@security/no-unsafe-dsa": "error", + "@security/no-unsafe-ecdsa": "error", + "@security/no-unsafe-rsa-encrypt": "error", + "@security/no-unsafe-rsa-sign": "error", + "@security/no-unsafe-rsa-key": "error", + "@security/no-unsafe-dsa-key": "error", + "@security/no-unsafe-dh-key": "error", + "@security/no-unsafe-3des": "error" + } +} \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/.gitignore b/code/UI/NdkBuildOnMultiThread/entry/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/.gitignore @@ -0,0 +1,6 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/build-profile.json5 b/code/UI/NdkBuildOnMultiThread/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..e058834e4086ef915c4695d303a1b910a1929bd0 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/build-profile.json5 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "apiType": "stageMode", + "buildOption": { + "externalNativeOptions": { + "path": "./src/main/cpp/CMakeLists.txt", + "arguments": "", + "cppFlags": "", + "abiFilters": ["armeabi-v7a", "arm64-v8a", "x86_64"] + } + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": false, + "files": [ + "./obfuscation-rules.txt" + ] + } + } + }, + "nativeLib": { + "debugSymbol": { + "strip": true, + "exclude": [] + } + } + }, + ], + "targets": [ + { + "name": "default" + }, + { + "name": "ohosTest", + } + ] +} \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/hvigorfile.ts b/code/UI/NdkBuildOnMultiThread/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..cfa8a00f74f409d9647f55cdf270ab6aec69fe41 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/hvigorfile.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hapTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins: [] /* Custom plugin to extend the functionality of Hvigor. */ +} \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/obfuscation-rules.txt b/code/UI/NdkBuildOnMultiThread/entry/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/obfuscation-rules.txt @@ -0,0 +1,23 @@ +# Define project specific obfuscation rules here. +# You can include the obfuscation configuration files in the current module's build-profile.json5. +# +# For more details, see +# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5 + +# Obfuscation options: +# -disable-obfuscation: disable all obfuscations +# -enable-property-obfuscation: obfuscate the property names +# -enable-toplevel-obfuscation: obfuscate the names in the global scope +# -compact: remove unnecessary blank spaces and all line feeds +# -remove-log: remove all console.* statements +# -print-namecache: print the name cache that contains the mapping from the old names to new names +# -apply-namecache: reuse the given cache file + +# Keep options: +# -keep-property-name: specifies property names that you want to keep +# -keep-global-name: specifies names that you want to keep in the global scope + +-enable-property-obfuscation +-enable-toplevel-obfuscation +-enable-filename-obfuscation +-enable-export-obfuscation \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/oh-package-lock.json5 b/code/UI/NdkBuildOnMultiThread/entry/oh-package-lock.json5 new file mode 100644 index 0000000000000000000000000000000000000000..ccf050a5468eb3abf8708258709d87eeecad2ad9 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/oh-package-lock.json5 @@ -0,0 +1,18 @@ +{ + "meta": { + "stableOrder": true + }, + "lockfileVersion": 3, + "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", + "specifiers": { + "libentry.so@src/main/cpp/types/libentry": "libentry.so@src/main/cpp/types/libentry" + }, + "packages": { + "libentry.so@src/main/cpp/types/libentry": { + "name": "libentry.so", + "version": "1.0.0", + "resolved": "src/main/cpp/types/libentry", + "registryType": "local" + } + } +} \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/oh-package.json5 b/code/UI/NdkBuildOnMultiThread/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..5d993e5251fd56950970aa593aefef1b8d71e976 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/oh-package.json5 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "name": "entry", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": { + "libentry.so": "file:./src/main/cpp/types/libentry" + } +} \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/CMakeLists.txt b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..cbb2513ae1e999d51c03f207a4a630430db0c214 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/CMakeLists.txt @@ -0,0 +1,19 @@ +# the minimum version of CMake. +cmake_minimum_required(VERSION 3.5.0) +project(myapp) + +set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) + +if(DEFINED PACKAGE_FIND_FILE) + include(${PACKAGE_FIND_FILE}) +endif() + +include_directories(${NATIVERENDER_ROOT_PATH} + ${NATIVERENDER_ROOT_PATH}/include) + +add_library(entry SHARED + napi_init.cpp + node/NodeCreator.cpp + card/CardCreator.cpp + ) +target_link_libraries(entry PUBLIC libace_napi.z.so ace_ndk.z.so hilog_ndk.z.so) \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/card/CardCreator.cpp b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/card/CardCreator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..44a24ab9e54b9f8fdd5fbeaa43b2eb2a1516c683 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/card/CardCreator.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "CardCreator.h" +#include "node/TypedArkUINode.h" + +namespace NativeModule { +std::shared_ptr CreateServiceItem(ServiceItemInfo& info) +{ + auto stackNode = std::make_shared(); + stackNode->SetPercentHeight(0.8); + stackNode->SetPercentWidth(0.3); + stackNode->SetBackgroundColor(0xffeeeeee); + stackNode->SetClip(true); + stackNode->SetMargin(0, 8, 8, 0); + stackNode->SetAlignment(ARKUI_ALIGNMENT_BOTTOM); + stackNode->SetBorderRadius(10); + + auto imageNode = std::make_shared(); + imageNode->SetPercentHeight(1); + imageNode->SetPercentWidth(1); + imageNode->SetSrc(info.backgroundImageSrc.c_str()); + imageNode->SetBackgroundColor(0xffff0000); + imageNode->SetBorderRadius(10); + stackNode->AddChild(imageNode); + + auto colorNode = std::make_shared(); + colorNode->SetPercentHeight(1); + colorNode->SetPercentWidth(1); + colorNode->SetBackgroundColor(info.iconColor);; + colorNode->SetBorderRadius(10); + stackNode->AddChild(colorNode); + + auto columnNode = std::make_shared(); + columnNode->SetPercentHeight(0.4); + columnNode->SetPercentWidth(1); + columnNode->SetBackgroundColor(0xffeeeeee); + stackNode->AddChild(columnNode); + + auto textNode = std::make_shared(); + textNode->SetHeight(20); + textNode->SetWidth(100); + textNode->SetContent(info.DescribeInfo.c_str()); + textNode->SetFontSize(11); + columnNode->AddChild(textNode); + + auto rowNode = std::make_shared(); + rowNode->SetHeight(20); + rowNode->SetWidth(60); + rowNode->SetPosition(20, 20); + columnNode->AddChild(rowNode); + + auto stackNode2 = std::make_shared(); + stackNode2->SetPercentHeight(0.8); + stackNode2->SetPercentWidth(0.3); + stackNode2->SetBackgroundColor(0xffeeeeee); + stackNode2->SetClip(true); + stackNode2->SetBorderRadius(5); + rowNode->AddChild(stackNode2); + + auto image2Node = std::make_shared(); + image2Node->SetPercentHeight(1); + image2Node->SetPercentWidth(1); + image2Node->SetSrc(info.iconSrc.c_str()); + stackNode2->AddChild(image2Node); + + auto colorNode2 = std::make_shared(); + colorNode2->SetPercentHeight(1); + colorNode2->SetPercentWidth(1); + colorNode2->SetBackgroundColor(info.iconColor);; + stackNode2->AddChild(colorNode2); + + auto text2Node = std::make_shared(); + text2Node->SetHeight(20); + text2Node->SetWidth(70); + text2Node->SetFontSize(10); + text2Node->SetContent(info.name.c_str()); + rowNode->AddChild(text2Node); + + return stackNode; +} + +std::shared_ptr CreateAppItem(AppItemInfo& info) +{ + auto appItemColumnNode = std::make_shared(); + appItemColumnNode->SetPercentHeight(1); + appItemColumnNode->SetPercentWidth(1); + appItemColumnNode->SetPadding(5,5,5,5); + appItemColumnNode->SetBackgroundColor(0xffffffff); + + auto stackNode = std::make_shared(); + stackNode->SetPercentHeight(0.8); + stackNode->SetPercentWidth(0.7); + stackNode->SetBackgroundColor(0xffeeeeee); + stackNode->SetClip(true); + stackNode->SetBorderRadius(10); + appItemColumnNode->AddChild(stackNode); + + auto appIconNode = std::make_shared(); + appIconNode->SetPercentHeight(1); + appIconNode->SetPercentWidth(1); + appIconNode->SetSrc(info.iconSrc.c_str()); + appIconNode->SetAutoResize(true); + appIconNode->SetBorderRadius(5); + stackNode->AddChild(appIconNode); + + auto colorNode = std::make_shared(); + colorNode->SetPercentHeight(1); + colorNode->SetPercentWidth(1); + colorNode->SetBackgroundColor(info.iconColor);; + colorNode->SetBorderRadius(10); + stackNode->AddChild(colorNode); + + auto appNameNode = std::make_shared(); + appNameNode->SetPercentHeight(0.2); + appNameNode->SetPercentWidth(0.8); + appNameNode->SetFontSize(10); + appNameNode->SetContent(info.name.c_str()); + appItemColumnNode->AddChild(appNameNode); + + return appItemColumnNode; +} + +std::shared_ptr CreateAppCard(AppCardInfo& info) +{ + auto columnNode = std::make_shared(); + columnNode->SetPercentHeight(0.4); + columnNode->SetPercentWidth(0.95); + columnNode->SetBackgroundColor(0xffffffff); + columnNode->SetBorderRadius(10); + columnNode->SetPadding(5,5,5,5); + + auto titleTextNode = std::make_shared(); + titleTextNode->SetPercentWidth(0.9); + titleTextNode->SetPercentHeight(0.1); + titleTextNode->SetFontSize(16); + titleTextNode->SetContent(info.name.c_str()); + columnNode->AddChild(titleTextNode); + + auto homeGridNode = std::make_shared(); + homeGridNode->SetPercentHeight(0.9); + homeGridNode->SetPercentWidth(1); + homeGridNode->SetColumnTemplate("1fr 1fr 1fr 1fr 1fr"); + homeGridNode->SetColumnGap(3.0); + homeGridNode->SetRowGap(0); + columnNode->AddChild(homeGridNode); + + for (int32_t i = 0; i < info.items.size(); i++) { + auto appItemNode = std::make_shared(); + appItemNode->SetPercentHeight(0.24); + appItemNode->SetPercentWidth(0.2); + homeGridNode->AddChild(appItemNode); + appItemNode->AddChild(CreateAppItem(info.items[i])); + } + + return columnNode; +} + +std::shared_ptr CreateServiceCard(ServiceCardInfo& info) +{ + auto columnNode = std::make_shared(); + columnNode->SetPercentHeight(0.2); + columnNode->SetPercentWidth(0.95); + columnNode->SetBackgroundColor(0xffffffff); + columnNode->SetBorderRadius(10); + columnNode->SetPadding(5,5,5,5); + + auto titleTextNode = std::make_shared(); + titleTextNode->SetPercentWidth(0.9); + titleTextNode->SetPercentHeight(0.1); + titleTextNode->SetFontSize(16); + titleTextNode->SetContent(info.name.c_str()); + columnNode->AddChild(titleTextNode); + + auto scrollNode = std::make_shared(); + scrollNode->SetPercentWidth(1); + scrollNode->SetPercentHeight(0.9); + scrollNode->SetScrollDirection(ARKUI_AXIS_HORIZONTAL); + scrollNode->SetScrollBarDisplayMode(ARKUI_SCROLL_BAR_DISPLAY_MODE_OFF); + columnNode->AddChild(scrollNode); + + auto rowNode = std::make_shared(); + scrollNode->AddChild(rowNode); + + for (int32_t i = 0; i < info.items.size(); i++) { + rowNode->AddChild(CreateServiceItem(info.items[i])); + } + return columnNode; +} +} // namespace NativeModule \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/card/CardCreator.h b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/card/CardCreator.h new file mode 100644 index 0000000000000000000000000000000000000000..1783462a5cbda50f4ce52f01fc3807f1d3e3e677 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/card/CardCreator.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MYAPPLICATION_SERVICECARD_H +#define MYAPPLICATION_SERVICECARD_H + +#include "common/ArkUINode.h" +#include + +namespace NativeModule { +struct ServiceItemInfo { + std::string name; + std::string backgroundImageSrc; + std::string DescribeInfo; + std::string iconSrc; + int64_t iconColor; +}; + +struct AppItemInfo { + std::string name; + std::string iconSrc; + int64_t iconColor; +}; + +struct AppCardInfo { + std::string name; + std::vector items; +}; + +struct ServiceCardInfo { + std::string name; + std::vector items; +}; + +struct CardInfo { + std::string type; + ServiceCardInfo serviceCardInfo; + AppCardInfo appCardInfo; +}; + +std::shared_ptr CreateServiceCard(ServiceCardInfo& info); +std::shared_ptr CreateAppCard(AppCardInfo& info); +} // namespace NativeModule + +#endif //MYAPPLICATION_SERVICECARD_H diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/common/ArkUIBaseNode.h b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/common/ArkUIBaseNode.h new file mode 100644 index 0000000000000000000000000000000000000000..6b4062f608533e3b753cf76bee21bdf2778d2780 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/common/ArkUIBaseNode.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MYAPPLICATION_ARKUIBASENODE_H +#define MYAPPLICATION_ARKUIBASENODE_H + +#include +#include +#include + +#include "NativeModule.h" + +namespace NativeModule { + +class ArkUIBaseNode { +public: + explicit ArkUIBaseNode(ArkUI_NodeHandle handle) + : handle_(handle), nativeModule_(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()) {} + + virtual ~ArkUIBaseNode() { + // 封装析构函数,实现子节点移除功能。 + if (!children_.empty()) { + for (const auto& child : children_) { + nativeModule_->removeChild(handle_, child->GetHandle()); + } + children_.clear(); + } + // 封装析构函数,统一回收节点资源。 + nativeModule_->disposeNode(handle_); + } + + void AddChild(const std::shared_ptr &child) { + children_.emplace_back(child); + OnAddChild(child); + } + + void RemoveChild(const std::shared_ptr &child) { + children_.remove(child); + OnRemoveChild(child); + } + + void InsertChild(const std::shared_ptr &child, int32_t index) { + if (index >= children_.size()) { + AddChild(child); + } else { + auto iter = children_.begin(); + std::advance(iter, index); + children_.insert(iter, child); + OnInsertChild(child, index); + } + } + + ArkUI_NodeHandle GetHandle() const { return handle_; } + +protected: + // 针对父容器子类需要重载下面的函数,实现组件挂载和卸载。 + virtual void OnAddChild(const std::shared_ptr &child) = 0; + virtual void OnRemoveChild(const std::shared_ptr &child) = 0; + virtual void OnInsertChild(const std::shared_ptr &child, int32_t index) = 0; + + ArkUI_NativeNodeAPI_1 *nativeModule_ = nullptr; + ArkUI_NodeHandle handle_; +private: + std::list> children_; +}; +} // namespace NativeModule + +#endif // MYAPPLICATION_ARKUIBASENODE_H \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/common/ArkUINode.h b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/common/ArkUINode.h new file mode 100644 index 0000000000000000000000000000000000000000..e2aa016e781bfdb3555a90b725dbdac348bf194d --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/common/ArkUINode.h @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MYAPPLICATION_ARKUINODE_H +#define MYAPPLICATION_ARKUINODE_H + +#include "ArkUIBaseNode.h" + +namespace NativeModule { + +class ArkUINode : public ArkUIBaseNode { +public: + explicit ArkUINode(ArkUI_NodeHandle handle) : ArkUIBaseNode(handle) {} + + ~ArkUINode() override {} + + // NDK相关通用属性调用封装 + void SetWidth(float width) { + assert(handle_); + ArkUI_NumberValue value[] = {{.f32 = width}}; + ArkUI_AttributeItem item = {value, 1}; + auto result = nativeModule_->setAttribute(handle_, NODE_WIDTH, &item); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUINode SetWidth Failed %{public}d", result); + } + } + void SetPercentWidth(float percent) { + assert(handle_); + ArkUI_NumberValue value[] = {{.f32 = percent}}; + ArkUI_AttributeItem item = {value, 1}; + auto result = nativeModule_->setAttribute(handle_, NODE_WIDTH_PERCENT, &item); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUINode SetPercentWidth Failed %{public}d", result); + } + } + void SetHeight(float height) { + assert(handle_); + ArkUI_NumberValue value[] = {{.f32 = height}}; + ArkUI_AttributeItem item = {value, 1}; + auto result = nativeModule_->setAttribute(handle_, NODE_HEIGHT, &item); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUINode SetHeight Failed %{public}d", result); + } + } + void SetPercentHeight(float percent) { + assert(handle_); + ArkUI_NumberValue value[] = {{.f32 = percent}}; + ArkUI_AttributeItem item = {value, 1}; + auto result = nativeModule_->setAttribute(handle_, NODE_HEIGHT_PERCENT, &item); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUINode SetPercentHeight Failed %{public}d", result); + } + } + void SetPosition(float x, float y) { + assert(handle_); + ArkUI_NumberValue value[] = {{.f32 = x}, {.f32 = y}}; + ArkUI_AttributeItem item = {value, 2}; + auto result = nativeModule_->setAttribute(handle_, NODE_POSITION, &item); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUINode SetPosition Failed %{public}d", result); + } + } + void SetBackgroundColor(uint32_t color) { + assert(handle_); + ArkUI_NumberValue value[] = {{.u32 = color}}; + ArkUI_AttributeItem item = {value, 1}; + auto result = nativeModule_->setAttribute(handle_, NODE_BACKGROUND_COLOR, &item); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUINode SetBackgroundColor Failed %{public}d", result); + } + } + void SetForegroundColor(uint32_t color) { + assert(handle_); + ArkUI_NumberValue value[] = {{.u32 = color}}; + ArkUI_AttributeItem item = {value, 1}; + auto result = nativeModule_->setAttribute(handle_, NODE_FOREGROUND_COLOR, &item); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUINode SetForegroundColor Failed %{public}d", result); + } + } + + void SetBorderRadius(float borderRadius) { + assert(handle_); + ArkUI_NumberValue value[] = {{.f32 = borderRadius}}; + ArkUI_AttributeItem item = {value, 1}; + auto result = nativeModule_->setAttribute(handle_, NODE_BORDER_RADIUS, &item); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUINode SetBorderRadius Failed %{public}d", result); + } + } + void SetMargin(float top, float right, float bottom, float left) { + assert(handle_); + ArkUI_NumberValue value[] = {{.f32 = top}, {.f32 = right}, {.f32 = bottom}, {.f32 = left}}; + ArkUI_AttributeItem item = {value, 4}; + auto result = nativeModule_->setAttribute(handle_, NODE_MARGIN, &item); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUINode SetMargin Failed %{public}d", result); + } + } + void SetPadding(float top, float right, float bottom, float left) { + assert(handle_); + ArkUI_NumberValue value[] = {{.f32 = top}, {.f32 = right}, {.f32 = bottom}, {.f32 = left}}; + ArkUI_AttributeItem item = {value, 4}; + auto result = nativeModule_->setAttribute(handle_, NODE_PADDING, &item); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUINode SetPadding Failed %{public}d", result); + } + } + void SetClip(bool clip) { + assert(handle_); + ArkUI_NumberValue value[] = {{.i32 = clip}}; + ArkUI_AttributeItem item = {value, 1}; + auto result = nativeModule_->setAttribute(handle_, NODE_CLIP, &item); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUINode SetClip Failed %{public}d", result); + } + } + + void SetAlignment(ArkUI_Alignment alignment) { + assert(handle_); + ArkUI_NumberValue value[] = {{.i32 = alignment}}; + ArkUI_AttributeItem item = {value, 1}; + auto result = nativeModule_->setAttribute(handle_, NODE_ALIGNMENT, &item); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUINode SetAlignment Failed %{public}d", result); + } + } + +protected: + // 组件树操作的实现类对接。 + void OnAddChild(const std::shared_ptr &child) override { + auto result = nativeModule_->addChild(handle_, child->GetHandle()); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUINode AddChild Failed %{public}d", result); + } + } + void OnRemoveChild(const std::shared_ptr &child) override { + auto result = nativeModule_->removeChild(handle_, child->GetHandle()); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUINode RemoveChild Failed %{public}d", result); + } + } + void OnInsertChild(const std::shared_ptr &child, int32_t index) override { + auto result = nativeModule_->insertChildAt(handle_, child->GetHandle(), index); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUINode InsertChild Failed %{public}d", result); + } + } +}; +} // namespace NativeModule + +#endif // MYAPPLICATION_ARKUINODE_H diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/common/NativeModule.h b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/common/NativeModule.h new file mode 100644 index 0000000000000000000000000000000000000000..e73064d707f7475d2081abefb8556a2ff7ee1afa --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/common/NativeModule.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MYAPPLICATION_NATIVEMODULE_H +#define MYAPPLICATION_NATIVEMODULE_H + +#include +#include +#include + +namespace NativeModule { + +class NativeModuleInstance { +public: + static NativeModuleInstance *GetInstance() { + static NativeModuleInstance instance; + return &instance; + } + + NativeModuleInstance() { + // 获取NDK接口的函数指针结构体对象,用于后续操作。 + OH_ArkUI_GetModuleInterface(ARKUI_MULTI_THREAD_NATIVE_NODE, ArkUI_NativeNodeAPI_1, arkUINativeNodeApi_); + assert(arkUINativeNodeApi_); + } + // 暴露给其他模块使用。 + ArkUI_NativeNodeAPI_1 *GetNativeNodeAPI() { return arkUINativeNodeApi_; } + +private: + ArkUI_NativeNodeAPI_1 *arkUINativeNodeApi_ = nullptr; +}; + +} // namespace NativeModule + +#endif // MYAPPLICATION_NATIVEMODULE_H diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/data/MockData.h b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/data/MockData.h new file mode 100644 index 0000000000000000000000000000000000000000..4fadc4c2c5c67b0b51045ef586cb910ba9ae304d --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/data/MockData.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MYAPPLICATION_MOCKDATA_H +#define MYAPPLICATION_MOCKDATA_H +#include "card/CardCreator.h" + +namespace NativeModule { + +#define CARD_RED 0xffc94b51 +#define CARD_BLUE 0xff5b97c7 +#define CARD_GREEN 0xff70c06f +#define CARD_YELLOW 0xffcbbb4d +#define CARD_PURPLE 0xffab70b1 + +std::vector g_appItems = { + {"测试文本", "resource://media/startIcon.png", CARD_YELLOW}, + {"测试文本", "resource://media/startIcon.png", CARD_RED}, + {"测试文本", "resource://media/startIcon.png", CARD_PURPLE}, + {"测试文本", "resource://media/startIcon.png", CARD_BLUE}, + {"测试文本", "resource://media/startIcon.png", CARD_GREEN}, + {"测试文本", "resource://media/startIcon.png", CARD_RED}, + {"测试文本", "resource://media/startIcon.png", CARD_BLUE}, + {"测试文本", "resource://media/startIcon.png", CARD_PURPLE}, + {"测试文本", "resource://media/startIcon.png", CARD_BLUE}, + {"测试文本", "resource://media/startIcon.png", CARD_RED}, + {"测试文本", "resource://media/startIcon.png", CARD_BLUE}, + {"测试文本", "resource://media/startIcon.png", CARD_GREEN}, + {"测试文本", "resource://media/startIcon.png", CARD_YELLOW}, + {"测试文本", "resource://media/startIcon.png", CARD_RED}, + {"测试文本", "resource://media/startIcon.png", CARD_BLUE}, + {"测试文本", "resource://media/startIcon.png", CARD_YELLOW}, + {"测试文本", "resource://media/startIcon.png", CARD_PURPLE}, + {"测试文本", "resource://media/startIcon.png", CARD_GREEN}, + {"测试文本", "resource://media/startIcon.png", CARD_RED}, +}; + +std::vector g_serviceItems = { + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_YELLOW}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_RED}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_PURPLE}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_BLUE}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_GREEN}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_BLUE}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_YELLOW}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_BLUE}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_RED}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_YELLOW}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_GREEN}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_BLUE}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本 ", "resource://media/startIcon.png", CARD_YELLOW}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_BLUE}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_RED}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_PURPLE}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_YELLOW}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_GREEN}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_YELLOW}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_RED}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_PURPLE}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_BLUE}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_GREEN}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_BLUE}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_YELLOW}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_BLUE}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_RED}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_YELLOW}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_GREEN}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_BLUE}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_YELLOW}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_BLUE}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_RED}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_PURPLE}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_YELLOW}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_GREEN}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_YELLOW}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_RED}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_PURPLE}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_BLUE}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_GREEN}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_BLUE}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_YELLOW}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_BLUE}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_RED}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_YELLOW}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_GREEN}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_BLUE}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_YELLOW}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_BLUE}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_RED}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_PURPLE}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_YELLOW}, + {"测试文本", "resource://media/startIcon.png", "测试文本 测试文本", "resource://media/startIcon.png", CARD_GREEN}, +}; + +std::vector g_cardTypeInfos = { + {"App" , {} , { "测试文本1", g_appItems }}, + {"Service" , { "测试文本2", g_serviceItems }, {}}, + {"App" , {} , { "测试文本3", g_appItems }}, + {"App" , {} , { "测试文本4", g_appItems }}, + {"Service" , { "测试文本5", g_serviceItems }, {}}, + {"App" , {} , { "测试文本6", g_appItems }}, +}; +} +#endif //MYAPPLICATION_MOCKDATA_H diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/napi_init.cpp b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/napi_init.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c2e6430d4830979cdf4eaaa304da453eaff54d62 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/napi_init.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "napi/native_api.h" +#include "node/NodeCreator.h" + +EXTERN_C_START +static napi_value Init(napi_env env, napi_value exports) +{ + napi_property_descriptor desc[] = { + { "CreateNodeTreeOnUIThread", nullptr, NativeModule::CreateNodeTreeOnUIThread, nullptr, nullptr, nullptr, napi_default, nullptr }, + { "CreateNodeTreeOnMultiThread", nullptr, NativeModule::CreateNodeTreeOnMultiThread, nullptr, nullptr, nullptr, napi_default, nullptr }, + { "DisposeNodeTree", nullptr, NativeModule::DisposeNodeTree, nullptr, nullptr, nullptr, napi_default, nullptr } + }; + napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + return exports; +} +EXTERN_C_END + +static napi_module entryModule = { + .nm_version = 1, + .nm_flags = 0, + .nm_filename = nullptr, + .nm_register_func = Init, + .nm_modname = "entry", + .nm_priv = ((void*)0), + .reserved = { 0 }, +}; + +extern "C" __attribute__((constructor)) void RegisterEntryModule(void) +{ + napi_module_register(&entryModule); +} diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/node/NodeCreator.cpp b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/node/NodeCreator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..03f1f98385f2ba4794e63359e8fa466e9f5e7138 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/node/NodeCreator.cpp @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "node/NodeCreator.h" + +#include +#include +#include +#include +#include "TypedArkUINode.h" +#include "card/CardCreator.h" +#include "data/MockData.h" + +namespace NativeModule { +#define CHILD_NODE_TREE_NUMBER 200 //多线程创建组件树的数量 +struct AsyncData { + napi_env env; + std::shared_ptr parent = nullptr; + std::shared_ptr child = nullptr; + CardInfo cardInfo; +}; + +// 保存ArkTs侧NodeContent指针与Native侧节点树根节点的对应关系。 +std::map> g_nodeMap; + +void CreateCardNodeTree(void *asyncUITaskData) { + auto asyncData = static_cast(asyncUITaskData); + if (!asyncData) { + return; + } + + if (asyncData->cardInfo.type == "App") { + AppCardInfo info = asyncData->cardInfo.appCardInfo; + asyncData->child = CreateAppCard(info); + } else if (asyncData->cardInfo.type == "Service") { + ServiceCardInfo info = asyncData->cardInfo.serviceCardInfo;; + asyncData->child = CreateServiceCard(info); + } +} + +// 组件多线程创建完成后,回到主线程挂载到UI树上 +void MountNodeTree(void *asyncUITaskData) { + auto asyncData = static_cast(asyncUITaskData); + if (!asyncData) { + return; + } + auto parent = asyncData->parent; + auto child = asyncData->child; + parent->AddChild(child); + delete asyncData; +} + +napi_value CreateNodeTreeOnMultiThread(napi_env env, napi_callback_info info) { + size_t argc = 2; + napi_value args[2] = { nullptr, nullptr }; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + ArkUI_NodeContentHandle contentHandle; + int32_t result = OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "OH_ArkUI_GetNodeContentFromNapiValue Failed %{public}d", result); + return nullptr; + } + ArkUI_ContextHandle contextHandle; + result = OH_ArkUI_GetContextFromNapiValue(env, args[1], &contextHandle); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "OH_ArkUI_GetContextFromNapiValue Failed %{public}d", result); + return nullptr; + } + + auto scrollNode = std::make_shared(); + scrollNode->SetScrollBarDisplayMode(ARKUI_SCROLL_BAR_DISPLAY_MODE_OFF); + result = OH_ArkUI_NodeContent_AddNode(contentHandle, scrollNode->GetHandle()); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "OH_ArkUI_NodeContent_AddNode Failed %{public}d", result); + return nullptr; + } + g_nodeMap[contentHandle] = scrollNode; + + auto columnNode = std::make_shared(); + scrollNode->AddChild(columnNode); + + for (int32_t i = 0; i < g_cardTypeInfos.size(); i++) { + //UI线程创建子树根节点,保证scroll的子节点顺序 + auto columnItem = std::make_shared(); + columnItem->SetMargin(8,0,8,0); + columnNode->AddChild(columnItem); + AsyncData* asyncData = new AsyncData(); + asyncData->parent = columnItem; + asyncData->cardInfo = g_cardTypeInfos[i]; + // 在非UI线程创建组件树,创建完成后回到主线程挂载到主树上 + result = OH_ArkUI_PostAsyncUITask(contextHandle, asyncData, CreateCardNodeTree, MountNodeTree); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "OH_ArkUI_PostAsyncUITask Failed %{public}d", result); + delete asyncData; + } + } + return nullptr; +} + +napi_value CreateNodeTreeOnUIThread(napi_env env, napi_callback_info info) { + size_t argc = 2; + napi_value args[2] = { nullptr, nullptr }; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + ArkUI_NodeContentHandle contentHandle; + int32_t result = OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "OH_ArkUI_GetNodeContentFromNapiValue Failed %{public}d", result); + return nullptr; + } + ArkUI_ContextHandle contextHandle; + result = OH_ArkUI_GetContextFromNapiValue(env, args[1], &contextHandle); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "OH_ArkUI_GetContextFromNapiValue Failed %{public}d", result); + return nullptr; + } + + auto scrollNode = std::make_shared(); + scrollNode->SetScrollBarDisplayMode(ARKUI_SCROLL_BAR_DISPLAY_MODE_OFF); + result = OH_ArkUI_NodeContent_AddNode(contentHandle, scrollNode->GetHandle()); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "OH_ArkUI_NodeContent_AddNode Failed %{public}d", result); + return nullptr; + } + g_nodeMap[contentHandle] = scrollNode; + + auto columnNode = std::make_shared(); + scrollNode->AddChild(columnNode); + + for (int32_t i = 0; i < g_cardTypeInfos.size(); i++) { + auto columnItem = std::make_shared(); + columnItem->SetMargin(8,0,8,0); + columnNode->AddChild(columnItem); + AsyncData* asyncData = new AsyncData(); + asyncData->parent = columnItem; + asyncData->cardInfo = g_cardTypeInfos[i]; + // 在UI线程创建组件树 + CreateCardNodeTree(asyncData); + MountNodeTree(asyncData); + } + return nullptr; +} + +napi_value DisposeNodeTree(napi_env env, napi_callback_info info) +{ + size_t argc = 1; + napi_value args[1] = { nullptr }; + napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); + + ArkUI_NodeContentHandle contentHandle; + int32_t result = OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "OH_ArkUI_GetNodeContentFromNapiValue Failed %{public}d", result); + return nullptr; + } + + auto it = g_nodeMap.find(contentHandle); + if (it == g_nodeMap.end()) { + return nullptr; + } + auto rootNode = it->second; + result = OH_ArkUI_NodeContent_RemoveNode(contentHandle, rootNode->GetHandle()); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "OH_ArkUI_NodeContent_RemoveNode Failed %{public}d", result); + return nullptr; + } + g_nodeMap.erase(contentHandle); + return nullptr; +} +} // namespace NativeModule \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/node/NodeCreator.h b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/node/NodeCreator.h new file mode 100644 index 0000000000000000000000000000000000000000..c48f50022e0be85c7b3ba0ebd51d95070cd28405 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/node/NodeCreator.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MYAPPLICATION_CREATENODE_H +#define MYAPPLICATION_CREATENODE_H + +#include + +namespace NativeModule { +napi_value CreateNodeTreeOnUIThread(napi_env env, napi_callback_info info); +napi_value CreateNodeTreeOnMultiThread(napi_env env, napi_callback_info info); +napi_value DisposeNodeTree(napi_env env, napi_callback_info info); +} // namespace NativeModule + +#endif //MYAPPLICATION_CREATENODE_H diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/node/TypedArkUINode.h b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/node/TypedArkUINode.h new file mode 100644 index 0000000000000000000000000000000000000000..20d5e718b42bc0f14f3fee025a1ad3165e8aac34 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/node/TypedArkUINode.h @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef MYAPPLICATION_TYPEDARKUINODE_H +#define MYAPPLICATION_TYPEDARKUINODE_H + +#include "common/ArkUINode.h" + +namespace NativeModule { +class ArkUIScrollNode: public ArkUINode { +public: + ArkUIScrollNode() : + ArkUINode(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()->createNode(ARKUI_NODE_SCROLL)) {} + void SetScrollDirection(ArkUI_Axis scrollDirection) { + ArkUI_NumberValue dir_value[] = {{ .i32 = scrollDirection }}; + ArkUI_AttributeItem dir_item = { dir_value, sizeof(dir_value) / sizeof(ArkUI_NumberValue) }; + auto result = nativeModule_->setAttribute(handle_, NODE_SCROLL_SCROLL_DIRECTION, &dir_item); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUIScrollNode SetScrollDirection Failed %{public}d", result); + } + } + void SetScrollBarDisplayMode(ArkUI_ScrollBarDisplayMode mode) { + ArkUI_NumberValue mode_value[] = {{ .i32 = mode }}; + ArkUI_AttributeItem mode_item = { mode_value, sizeof(mode_value) / sizeof(ArkUI_NumberValue) }; + auto result = nativeModule_->setAttribute(handle_, NODE_SCROLL_BAR_DISPLAY_MODE, &mode_item); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUIScrollNode SetScrollDirection Failed %{public}d", result); + } + } +}; + +class ArkUIRowNode: public ArkUINode { +public: + ArkUIRowNode() : + ArkUINode(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()->createNode(ARKUI_NODE_ROW)) {} +}; + +class ArkUIColumnNode: public ArkUINode { +public: + ArkUIColumnNode() : + ArkUINode(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()->createNode(ARKUI_NODE_COLUMN)) {} +}; + +class ArkUIButtonNode: public ArkUINode { +public: + ArkUIButtonNode() : + ArkUINode(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()->createNode(ARKUI_NODE_BUTTON)) {} + void SetLabel(const char* src) { + ArkUI_AttributeItem label_item = { .string = src }; + auto result = nativeModule_->setAttribute(handle_, NODE_BUTTON_LABEL, &label_item); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUIButtonNode SetLabel Failed %{public}d", result); + } + } +}; + +class ArkUIImageNode: public ArkUINode { +public: + ArkUIImageNode() : + ArkUINode(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()->createNode(ARKUI_NODE_IMAGE)) {} + void SetSrc(const char* src) { + ArkUI_AttributeItem image_src_item = {}; + image_src_item.string = src; + auto result = nativeModule_->setAttribute(handle_, NODE_IMAGE_SRC, &image_src_item); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUIImageNode SetSrc Failed %{public}d", result); + } + } + void SetAutoResize(bool autoResize) { + ArkUI_NumberValue value[] = {{.i32 = autoResize} }; + ArkUI_AttributeItem item = {value, 1}; + auto result = nativeModule_->setAttribute(handle_, NODE_IMAGE_AUTO_RESIZE, &item); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUIImageNode SetAutoResize Failed %{public}d", result); + } + } +}; + +class ArkUIRefreshNode: public ArkUINode { +public: + ArkUIRefreshNode() : + ArkUINode(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()->createNode(ARKUI_NODE_REFRESH)) {} + void SetRefreshing(bool refreshing) { + ArkUI_NumberValue refreshing_value[] = {{ .i32 = refreshing }}; + ArkUI_AttributeItem refreshing_item = { refreshing_value, sizeof(refreshing_value) / sizeof(ArkUI_NumberValue) }; + auto result = nativeModule_->setAttribute(handle_, NODE_REFRESH_REFRESHING, &refreshing_item); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUIRefreshNode SetRefreshing Failed %{public}d", result); + } + } +}; + +class ArkUITextInputNode: public ArkUINode { +public: + ArkUITextInputNode() : + ArkUINode(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()->createNode(ARKUI_NODE_TEXT_INPUT)) {} +}; + +class ArkUITextNode: public ArkUINode { +public: + ArkUITextNode() : + ArkUINode(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()->createNode(ARKUI_NODE_TEXT)) {} + void SetContent(const char* content) { + ArkUI_AttributeItem content_item = { .string = content }; + auto result = nativeModule_->setAttribute(handle_, NODE_TEXT_CONTENT, &content_item); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUITextNode SetContent Failed %{public}d", result); + } + } + void SetFontSize(float size) { + ArkUI_NumberValue size_value[] = {{ .f32 = size }}; + ArkUI_AttributeItem size_item = { size_value, sizeof(size_value) / sizeof(ArkUI_NumberValue) }; + auto result = nativeModule_->setAttribute(handle_, NODE_FONT_SIZE, &size_item); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUIGridNode SetColumnGap Failed %{public}d", result); + } + } +}; + +class ArkUIGridNode: public ArkUINode { +public: + ArkUIGridNode() : + ArkUINode(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()->createNode(ARKUI_NODE_GRID)) {} + void SetColumnTemplate(const char* columnTemplate) { + ArkUI_AttributeItem template_item = { .string = columnTemplate }; + auto result = nativeModule_->setAttribute(handle_, NODE_GRID_COLUMN_TEMPLATE, &template_item); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUIGridNode SetColumnTemplate Failed %{public}d", result); + } + } + void SetColumnGap(float gap) { + ArkUI_NumberValue gap_value[] = {{ .f32 = gap }}; + ArkUI_AttributeItem gap_item = { gap_value, sizeof(gap_value) / sizeof(ArkUI_NumberValue) }; + auto result = nativeModule_->setAttribute(handle_, NODE_GRID_COLUMN_GAP, &gap_item); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUIGridNode SetColumnGap Failed %{public}d", result); + } + } + void SetRowGap(float gap) { + ArkUI_NumberValue gap_value[] = {{ .f32 = gap }}; + ArkUI_AttributeItem gap_item = { gap_value, sizeof(gap_value) / sizeof(ArkUI_NumberValue) }; + auto result = nativeModule_->setAttribute(handle_, NODE_GRID_ROW_GAP, &gap_item); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "ArkUIGridNode SetRowGap Failed %{public}d", result); + } + } +}; + +class ArkUIGridItemNode: public ArkUINode { +public: + ArkUIGridItemNode() : + ArkUINode(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()->createNode(ARKUI_NODE_GRID_ITEM)) {} +}; + +class ArkUIStackNode: public ArkUINode { +public: + ArkUIStackNode() : + ArkUINode(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()->createNode(ARKUI_NODE_STACK)) {} +}; +} // namespace NativeModule + +#endif //MYAPPLICATION_TYPEDARKUINODE_H diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/types/libentry/Index.d.ts b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/types/libentry/Index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..367048081eb30b151ba1c921a5058ea9146837ce --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/types/libentry/Index.d.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { NodeContent, UIContext } from "@kit.ArkUI"; + +export const CreateNodeTreeOnUIThread: (slot: NodeContent, context: UIContext) => void; +export const CreateNodeTreeOnMultiThread: (slot: NodeContent, context: UIContext) => void; +export const DisposeNodeTree: (slot: NodeContent) => void; \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/types/libentry/oh-package.json5 b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/types/libentry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..846e4c7e13ead48abe6019bd40f3a13bf8f9c083 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/main/cpp/types/libentry/oh-package.json5 @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "name": "libentry.so", + "types": "./Index.d.ts", + "version": "1.0.0", + "description": "Please describe the basic information." +} \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/ets/entryability/EntryAbility.ets b/code/UI/NdkBuildOnMultiThread/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..03de9ddeb4315b230a1965f1c50fd9f5e2024ef5 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { window } from '@kit.ArkUI'; + +const DOMAIN = 0x0000; + +export default class EntryAbility extends UIAbility { + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate'); + } + + onDestroy(): void { + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + + windowStage.loadContent('pages/Index', (err) => { + if (err.code) { + hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err)); + return; + } + hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.'); + }); + } + + onWindowStageDestroy(): void { + // Main window is destroyed, release UI related resources + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + } + + onForeground(): void { + // Ability has brought to foreground + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground'); + } + + onBackground(): void { + // Ability has back to background + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground'); + } +} \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/code/UI/NdkBuildOnMultiThread/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..1fca37ecc34e1079aaf6557f1272cd694aa0068c --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; + +const DOMAIN = 0x0000; + +export default class EntryBackupAbility extends BackupExtensionAbility { + async onBackup() { + hilog.info(DOMAIN, 'testTag', 'onBackup ok'); + await Promise.resolve(); + } + + async onRestore(bundleVersion: BundleVersion) { + hilog.info(DOMAIN, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + await Promise.resolve(); + } +} \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/ets/pages/Index.ets b/code/UI/NdkBuildOnMultiThread/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..85b3925cddc6d0b6f416d1372da0dbced7a43024 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { router } from '@kit.ArkUI' + +@Entry +@Component +struct Index { + build() { + Column() { + Button("CreatePageOnMultiThread") + .onClick(() => { + router.pushUrl({ url:"pages/Page", params: { isOnUIThread: false } }) + }) + Button("CreatePageOnUIThread") + .onClick(() => { + router.pushUrl({ url:"pages/Page", params: { isOnUIThread: true } }) + }) + }.width('100%').height('100%') + } +} + diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/ets/pages/Page.ets b/code/UI/NdkBuildOnMultiThread/entry/src/main/ets/pages/Page.ets new file mode 100644 index 0000000000000000000000000000000000000000..f3132eae996ef78ca450e6cf2f085587e654d61e --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/main/ets/pages/Page.ets @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { NodeContent, router } from '@kit.ArkUI'; +import entry from 'libentry.so'; + +@Component +struct CAPIComponent { + private rootSlot = new NodeContent(); + @State isOnUIThread: boolean = false; + + aboutToAppear(): void { + if (this.isOnUIThread) { + // 调用C-API接口在UI线程创建组件 + entry.CreateNodeTreeOnUIThread(this.rootSlot, this.getUIContext()); + } else { + // 调用C-API接口多线程创建组件 + entry.CreateNodeTreeOnMultiThread(this.rootSlot, this.getUIContext()); + } + } + + aboutToDisappear(): void { + // 释放已创建的C-API组件 + entry.DisposeNodeTree(this.rootSlot); + } + + build() { + Column() { + // C-API组件挂载点 + ContentSlot(this.rootSlot) + } + .width('100%') + } +} + +@Component +struct TitleComponent { + @Link message: string; + + build() { + Column() { + Text(this.message) + .fontSize(18) + .fontWeight(FontWeight.Bold) + .width('100%') + .textAlign(TextAlign.Center) + } + .margin(5) + .align(Alignment.Center) + .width('95%') + .height('8%') + .borderRadius(10) + .backgroundColor('#FFFFFF') + } +} + +interface paramsObj{ + isOnUIThread: boolean +} + +@Entry +@Component +struct Page { + isOnUIThread: boolean = false; + @State message: string = "CreateNodeTreeOnMultiThread"; + + aboutToAppear(): void { + const params = router.getParams() as paramsObj; + this.isOnUIThread = params.isOnUIThread; + if (this.isOnUIThread) { + this.message = "CreateNodeTreeOnUIThread"; + } else { + this.message = "CreateNodeTreeOnMultiThread" + } + } + + build() { + Flex() { + Column() { + TitleComponent({message : this.message}) + .width('100%') + .align(Alignment.Center) + CAPIComponent({isOnUIThread : this.isOnUIThread}) + .width('100%') + } + .backgroundColor('#EEEEEE') + .width('100%') + .height('100%') + } + .width('100%') + .height('100%') + } +} \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/module.json5 b/code/UI/NdkBuildOnMultiThread/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..dece7db447b686c5afc03a0ed853c0cf4c87c3a2 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/main/module.json5 @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "phone", + "tablet", + "2in1" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "EntryAbility", + "srcEntry": "./ets/entryability/EntryAbility.ets", + "description": "$string:EntryAbility_desc", + "icon": "$media:layered_image", + "label": "$string:EntryAbility_label", + "startWindowIcon": "$media:startIcon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ], + "extensionAbilities": [ + { + "name": "EntryBackupAbility", + "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets", + "type": "backup", + "exported": false, + "metadata": [ + { + "name": "ohos.extension.backup", + "resource": "$profile:backup_config" + } + ], + } + ] + } +} \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/element/color.json b/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..d66f9a7d4ac61fb8d215239ab3620b7bcd77bf33 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/element/float.json b/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/element/float.json new file mode 100644 index 0000000000000000000000000000000000000000..a8a5d404dcd8b0466194afc3aa25d90a8a327470 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/element/float.json @@ -0,0 +1,8 @@ +{ + "float": [ + { + "name": "page_text_font_size", + "value": "50fp" + } + ] +} diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/element/string.json b/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..f94595515a99e0c828807e243494f57f09251930 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "label" + } + ] +} \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/media/background.png b/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f Binary files /dev/null and b/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/media/background.png differ diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/media/foreground.png b/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..97014d3e10e5ff511409c378cd4255713aecd85f Binary files /dev/null and b/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/media/foreground.png differ diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/media/layered_image.json b/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/media/layered_image.json @@ -0,0 +1,7 @@ +{ + "layered-image": + { + "background" : "$media:background", + "foreground" : "$media:foreground" + } +} \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/media/startIcon.png b/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/media/startIcon.png differ diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/profile/backup_config.json b/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000000000000000000000000000000000000..d742c2f96e7dd0f406f499941f3147345e998f95 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/profile/main_pages.json b/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..a3f40cd0ab918645c59cbb4a1c1feec90d154108 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,6 @@ +{ + "src": [ + "pages/Index", + "pages/Page" + ] +} diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/dark/element/color.json b/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/dark/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..438d5bc43bb23c59c210d586b96635a72da5b64a --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/main/resources/dark/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#000000" + } + ] +} \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/mock/Libentry.mock.ets b/code/UI/NdkBuildOnMultiThread/entry/src/mock/Libentry.mock.ets new file mode 100644 index 0000000000000000000000000000000000000000..eebf1ed910f6a8f2a9e7e565aa71b179b7b8b537 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/mock/Libentry.mock.ets @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const NativeMock: Record = { + 'add': (a: number, b: number) => { + return a + b; + }, +}; + +export default NativeMock; \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/mock/mock-config.json5 b/code/UI/NdkBuildOnMultiThread/entry/src/mock/mock-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..98b0ae79f0090e1fc381d54c959fb32c9f7563f4 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/mock/mock-config.json5 @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +{ + "libentry.so": { + "source": "src/mock/Libentry.mock.ets" + } +} \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/ohosTest/ets/test/Ability.test.ets b/code/UI/NdkBuildOnMultiThread/entry/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..85c78f67579d6e31b5f5aeea463e216b9b141048 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/ohosTest/ets/test/Ability.test.ets @@ -0,0 +1,35 @@ +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; + +export default function abilityTest() { + describe('ActsAbilityTest', () => { + // Defines a test suite. Two parameters are supported: test suite name and test suite function. + beforeAll(() => { + // Presets an action, which is performed only once before all test cases of the test suite start. + // This API supports only one parameter: preset action function. + }) + beforeEach(() => { + // Presets an action, which is performed before each unit test case starts. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: preset action function. + }) + afterEach(() => { + // Presets a clear action, which is performed after each unit test case ends. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: clear action function. + }) + afterAll(() => { + // Presets a clear action, which is performed after all test cases of the test suite end. + // This API supports only one parameter: clear action function. + }) + it('assertContain', 0, () => { + // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. + hilog.info(0x0000, 'testTag', '%{public}s', 'it begin'); + let a = 'abc'; + let b = 'b'; + // Defines a variety of assertion methods, which are used to declare expected boolean conditions. + expect(a).assertContain(b); + expect(a).assertEqual(a); + }) + }) +} \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/ohosTest/ets/test/List.test.ets b/code/UI/NdkBuildOnMultiThread/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..794c7dc4ed66bd98fa3865e07922906e2fcef545 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/ohosTest/ets/test/List.test.ets @@ -0,0 +1,5 @@ +import abilityTest from './Ability.test'; + +export default function testsuite() { + abilityTest(); +} \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/ohosTest/module.json5 b/code/UI/NdkBuildOnMultiThread/entry/src/ohosTest/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c8bd24faff0ff0064a57435f74662f1db5865f88 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/ohosTest/module.json5 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "module": { + "name": "entry_test", + "type": "feature", + "deviceTypes": [ + "phone", + "tablet", + "2in1" + ], + "deliveryWithInstall": true, + "installationFree": false + } +} diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/test/List.test.ets b/code/UI/NdkBuildOnMultiThread/entry/src/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..f1186b1f53c3a70930921c5dbd1417332bec56c9 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/test/List.test.ets @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import localUnitTest from './LocalUnit.test'; + +export default function testsuite() { + localUnitTest(); +} \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/entry/src/test/LocalUnit.test.ets b/code/UI/NdkBuildOnMultiThread/entry/src/test/LocalUnit.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..7fc57c77dbf76d8df08a2b802a55b948e3fcf968 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/entry/src/test/LocalUnit.test.ets @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'; + +export default function localUnitTest() { + describe('localUnitTest', () => { + // Defines a test suite. Two parameters are supported: test suite name and test suite function. + beforeAll(() => { + // Presets an action, which is performed only once before all test cases of the test suite start. + // This API supports only one parameter: preset action function. + }); + beforeEach(() => { + // Presets an action, which is performed before each unit test case starts. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: preset action function. + }); + afterEach(() => { + // Presets a clear action, which is performed after each unit test case ends. + // The number of execution times is the same as the number of test cases defined by **it**. + // This API supports only one parameter: clear action function. + }); + afterAll(() => { + // Presets a clear action, which is performed after all test cases of the test suite end. + // This API supports only one parameter: clear action function. + }); + it('assertContain', 0, () => { + // Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function. + let a = 'abc'; + let b = 'b'; + // Defines a variety of assertion methods, which are used to declare expected boolean conditions. + expect(a).assertContain(b); + expect(a).assertEqual(a); + }); + }); +} \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/figures/build_on_multi_thread.png b/code/UI/NdkBuildOnMultiThread/figures/build_on_multi_thread.png new file mode 100644 index 0000000000000000000000000000000000000000..237fc6fa4f40eaac45ec59c795b5639abf900d99 Binary files /dev/null and b/code/UI/NdkBuildOnMultiThread/figures/build_on_multi_thread.png differ diff --git a/code/UI/NdkBuildOnMultiThread/figures/build_on_multi_thread_trace.png b/code/UI/NdkBuildOnMultiThread/figures/build_on_multi_thread_trace.png new file mode 100644 index 0000000000000000000000000000000000000000..f1d7a10313bfe90da5f807b01363f9aead09578c Binary files /dev/null and b/code/UI/NdkBuildOnMultiThread/figures/build_on_multi_thread_trace.png differ diff --git a/code/UI/NdkBuildOnMultiThread/figures/build_on_ui_thread.png b/code/UI/NdkBuildOnMultiThread/figures/build_on_ui_thread.png new file mode 100644 index 0000000000000000000000000000000000000000..7a1ca5379cc5bb33fb586d4f0e95972e4cd608ba Binary files /dev/null and b/code/UI/NdkBuildOnMultiThread/figures/build_on_ui_thread.png differ diff --git a/code/UI/NdkBuildOnMultiThread/figures/build_on_ui_thread_trace.png b/code/UI/NdkBuildOnMultiThread/figures/build_on_ui_thread_trace.png new file mode 100644 index 0000000000000000000000000000000000000000..d40c5e6fbcba37d412b307fcc91797cb084a5921 Binary files /dev/null and b/code/UI/NdkBuildOnMultiThread/figures/build_on_ui_thread_trace.png differ diff --git a/code/UI/NdkBuildOnMultiThread/figures/mainPage.png b/code/UI/NdkBuildOnMultiThread/figures/mainPage.png new file mode 100644 index 0000000000000000000000000000000000000000..dfaa4ffa7096d4561dd2d15319caf062186ed6c0 Binary files /dev/null and b/code/UI/NdkBuildOnMultiThread/figures/mainPage.png differ diff --git a/code/UI/NdkBuildOnMultiThread/hvigor/hvigor-config.json5 b/code/UI/NdkBuildOnMultiThread/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..ceec1b15918a4125d23843d27513bc20e557847c --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/hvigor/hvigor-config.json5 @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "modelVersion": "5.0.5", + "dependencies": { + }, + "execution": { + // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | false ]. Default: "normal" */ + // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */ + // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */ + // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */ + // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */ + }, + "logging": { + // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */ + }, + "debugging": { + // "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */ + }, + "nodeOptions": { + // "maxOldSpaceSize": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/ + // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/ + } +} diff --git a/code/UI/NdkBuildOnMultiThread/hvigorfile.ts b/code/UI/NdkBuildOnMultiThread/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..e3340f07e45ddc5dcadbb87012668555def2e6e0 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/hvigorfile.ts @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { appTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins: [] /* Custom plugin to extend the functionality of Hvigor. */ +} \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/oh-package-lock.json5 b/code/UI/NdkBuildOnMultiThread/oh-package-lock.json5 new file mode 100644 index 0000000000000000000000000000000000000000..e66b2da5feca3c3cbab26d52e800d062d528d440 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/oh-package-lock.json5 @@ -0,0 +1,27 @@ +{ + "meta": { + "stableOrder": true + }, + "lockfileVersion": 3, + "ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.", + "specifiers": { + "@ohos/hamock@1.0.0": "@ohos/hamock@1.0.0", + "@ohos/hypium@1.0.21": "@ohos/hypium@1.0.21" + }, + "packages": { + "@ohos/hamock@1.0.0": { + "name": "@ohos/hamock", + "version": "1.0.0", + "integrity": "sha512-K6lDPYc6VkKe6ZBNQa9aoG+ZZMiwqfcR/7yAVFSUGIuOAhPvCJAo9+t1fZnpe0dBRBPxj2bxPPbKh69VuyAtDg==", + "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hamock/-/hamock-1.0.0.har", + "registryType": "ohpm" + }, + "@ohos/hypium@1.0.21": { + "name": "@ohos/hypium", + "version": "1.0.21", + "integrity": "sha512-iyKGMXxE+9PpCkqEwu0VykN/7hNpb+QOeIuHwkmZnxOpI+dFZt6yhPB7k89EgV1MiSK/ieV/hMjr5Z2mWwRfMQ==", + "resolved": "https://ohpm.openharmony.cn/ohpm/@ohos/hypium/-/hypium-1.0.21.har", + "registryType": "ohpm" + } + } +} \ No newline at end of file diff --git a/code/UI/NdkBuildOnMultiThread/oh-package.json5 b/code/UI/NdkBuildOnMultiThread/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..bb713889dcf243763a520796f6a8bd779efa08b6 --- /dev/null +++ b/code/UI/NdkBuildOnMultiThread/oh-package.json5 @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +{ + "modelVersion": "5.0.5", + "description": "Please describe the basic information.", + "dependencies": { + }, + "devDependencies": { + "@ohos/hypium": "1.0.21", + "@ohos/hamock": "1.0.0" + } +}