diff --git a/ArkUIKit/NativeNodeUtilsSample/.gitignore b/ArkUIKit/NativeNodeUtilsSample/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..d2ff20141ceed86d87c0ea5d99481973005bab2b --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/.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/ArkUIKit/NativeNodeUtilsSample/AppScope/app.json5 b/ArkUIKit/NativeNodeUtilsSample/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c6907772e67d9a0d30ef45cc03574fc28cab6bbf --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/AppScope/app.json5 @@ -0,0 +1,24 @@ +/* + * 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.example.nativenodesample", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:layered_image", + "label": "$string:app_name" + } +} diff --git a/ArkUIKit/NativeNodeUtilsSample/AppScope/resources/base/element/string.json b/ArkUIKit/NativeNodeUtilsSample/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..f6fca8ec8cc62fae2ac637de6e4699aee074425f --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "NativeNodeSample" + } + ] +} diff --git a/ArkUIKit/NativeNodeUtilsSample/AppScope/resources/base/media/background.png b/ArkUIKit/NativeNodeUtilsSample/AppScope/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f Binary files /dev/null and b/ArkUIKit/NativeNodeUtilsSample/AppScope/resources/base/media/background.png differ diff --git a/ArkUIKit/NativeNodeUtilsSample/AppScope/resources/base/media/foreground.png b/ArkUIKit/NativeNodeUtilsSample/AppScope/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..97014d3e10e5ff511409c378cd4255713aecd85f Binary files /dev/null and b/ArkUIKit/NativeNodeUtilsSample/AppScope/resources/base/media/foreground.png differ diff --git a/ArkUIKit/NativeNodeUtilsSample/AppScope/resources/base/media/layered_image.json b/ArkUIKit/NativeNodeUtilsSample/AppScope/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/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/ArkUIKit/NativeNodeUtilsSample/README_zh.md b/ArkUIKit/NativeNodeUtilsSample/README_zh.md new file mode 100644 index 0000000000000000000000000000000000000000..bfcfa928d00b6c3b5c52e38b202ca0096278da7a --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/README_zh.md @@ -0,0 +1,77 @@ +# ArkUI使用NODE IMAGE指南文档示例 + +### 介绍 + +本示例通过使用[ArkUI指南文档](https://gitcode.com/openharmony/docs/tree/master/zh-cn/application-dev/ui)中各场景的开发示例,展示在工程中,帮助开发者更好的理解并合理使用ArkUI提供的组件以及组件属性。通过该工程可以创建IMAGE组件并可以设置、获取、重置组件对应节点属性,对已创建的IMAGE组件进行销毁操作。该工程中代码详细描述可参考[显示图片 (Image)](https://gitcode.com/openharmony/docs/blob/OpenHarmony-5.0.0-Release/zh-cn/application-dev/ui/arkts-graphics-display.md)。 + +### 效果预览 + +| 首页 | 设置图像内容顺时针旋转90度显示 | +|------------------------------------|---------------------------------| +| ![](screenshots/device/image1.png) |![](screenshots/device/result.png) | + +### 使用说明 + +1. 在主界面,可以点击“选择节点类型”,创建需要的组件。 + +2. 选择组件对应的“选择节点属性”菜单列。 + +3. 通过文本输入,设置属性值。 + +4. 点击“设置属性值”,查看效果。 + +5. 点击“获取属性值”,查看已设置的属性值。 + +6. 点击“重置”,清除设置的属性。 + +7. 点击“清理”,移除创建的组件节点。 + +### 工程目录 +``` +entry/src/main/cpp +|---CMakeLists.txt // 编译脚本 +|---napi_init.cpp // 实现创建、设置、获取、重置组件属性 +|---manager.cpp // 管理组件节点 +|---types + |---Index.d.ts // napi对外接口定义 +entry/src/main/ets/ +|---entryability +|---pages +| |---Index.ets // 应用主页面 +entry/src/ohosTest/ +|---ets +| |---index.test.ets // 示例代码测试代码 +``` + +### 具体实现 + +1. 在[Index.ets](entry%2Fsrc%2Fmain%2Fets%2Fpages%2FIndex.ets)文件中,通过点击按钮创建IMAGE组件节点,并通过文本输入框设置、获取、重置属性值。 +2. 在[Index.d.ts](entry%2Fsrc%2Fmain%2Fcpp%2Ftypes%2Flibentry%2FIndex.d.ts)文件中,定义napi对外接口。 +3. 在[napi_init.cpp](entry%2Fsrc%2Fmain%2Fcpp%2Fnapi_init.cpp)文件中,实现Index.d.ts中对外的接口。 +4. 在[manager.cpp](entry%2Fsrc%2Fmain%2Fcpp%2Fmanager.cpp)文件中,通过调用ArkUI的接口实现创建、设置、获取、重置组件属性。 + +### 相关权限 + +不涉及。 + +### 依赖 + +不涉及。 + +### 约束与限制 + +1.本示例支持标准系统上运行, 支持设备:RK3568等。 + +2.本示例为Stage模型,支持API20版本SDK,版本号:6.0.0.47,镜像版本号:OpenHarmony_5.0.2.57。 + +### 下载 + +如需单独下载本工程,执行如下命令: + +```` +git init +git config core.sparsecheckout true +echo code/DocsSample/ArkUIDocSample/NativeNodeSample > .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/ArkUIKit/NativeNodeUtilsSample/build-profile.json5 b/ArkUIKit/NativeNodeUtilsSample/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..9fd7e58490e8b4d53272f97f44975c7a3dfe8be7 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/build-profile.json5 @@ -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. + */ +{ + "app": { + "products": [ + { + "name": "default", + "signingConfig": "default", + "compileSdkVersion": 20, + "compatibleSdkVersion": 20, + "runtimeOS": "OpenHarmony", + "buildOption": { + "strictMode": { + "caseSensitiveCheck": true, + "useNormalizedOHMUrl": true + } + } + } + ], + "buildModeSet": [ + { + "name": "debug" + }, + { + "name": "release" + } + ], + "signingConfigs": [ + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/ArkUIKit/NativeNodeUtilsSample/code-linter.json5 b/ArkUIKit/NativeNodeUtilsSample/code-linter.json5 new file mode 100644 index 0000000000000000000000000000000000000000..5c4682f8164874ec7e9cb8f99ff8b3228ffbc126 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/code-linter.json5 @@ -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. + */ +{ + "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/ArkUIKit/NativeNodeUtilsSample/entry/.gitignore b/ArkUIKit/NativeNodeUtilsSample/entry/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/.gitignore @@ -0,0 +1,6 @@ +/node_modules +/oh_modules +/.preview +/build +/.cxx +/.test \ No newline at end of file diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/build-profile.json5 b/ArkUIKit/NativeNodeUtilsSample/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..1f28520fc48e32a1440b8c3ed958205edb0f123e --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/build-profile.json5 @@ -0,0 +1,54 @@ +/* + * 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/ArkUIKit/NativeNodeUtilsSample/entry/hvigorfile.ts b/ArkUIKit/NativeNodeUtilsSample/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..f8b117a17af3b2d7cb87a7680e29e2bb8ccd5b46 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/hvigorfile.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 { 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/ArkUIKit/NativeNodeUtilsSample/entry/obfuscation-rules.txt b/ArkUIKit/NativeNodeUtilsSample/entry/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/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/ArkUIKit/NativeNodeUtilsSample/entry/oh-package.json5 b/ArkUIKit/NativeNodeUtilsSample/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..75d2e499a804dc9c4875b133326ee877cc980c65 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/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. + */ +{ + "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/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUIBaseNode.h b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUIBaseNode.h new file mode 100644 index 0000000000000000000000000000000000000000..45c3d4e43ac4df0ab7765d62c031a76d60583544 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUIBaseNode.h @@ -0,0 +1,211 @@ +/* + * 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. + */ +// ArkUIBaseNode.h +// 提供组件树操作的基类。 +#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); + } + } + + void InsertChildBefore(const std::shared_ptr &child, + const std::shared_ptr &slibing) + { + auto it = std::find(children_.begin(), children_.end(), slibing); + if (it != children_.end()) { + children_.insert(it, child); + } + OnInsertChildBefore(child, slibing); + } + + void InsertChildAfter(const std::shared_ptr &child, + const std::shared_ptr &slibing) + { + auto it = std::find(children_.begin(), children_.end(), slibing); + if (it != children_.end()) { + children_.insert(std::next(it), child); + } + OnInsertChildAfter(child, slibing); + } + + void RemoveAllChild() + { + for (auto it = children_.begin(); it != children_.end();) { + RemoveChild(*it); + } + OnRemoveAllChild(); + } + ArkUI_NodeHandle (*getChildAt)(ArkUI_NodeHandle node, int32_t position); + ArkUI_NodeHandle (*getFirstChild)(ArkUI_NodeHandle node); + ArkUI_NodeHandle (*getLastChild)(ArkUI_NodeHandle node); + ArkUI_NodeHandle (*getPreviousSibling)(ArkUI_NodeHandle node); + ArkUI_NodeHandle (*getNextSibling)(ArkUI_NodeHandle node); + + // 以下方法不可跨过ContentSlot。获取nodeHandle后可根据nativeEntry保存的节点map,做对应查找。 + ArkUI_NodeHandle GetParent() const { return nativeModule_->getParent(handle_); } + ArkUI_NodeHandle GetChildAt(uint32_t index) const { return nativeModule_->getChildAt(handle_, index); } + ArkUI_NodeHandle GetFirstChild() const { return nativeModule_->getFirstChild(handle_); } + ArkUI_NodeHandle GetLastChild() const { return nativeModule_->getLastChild(handle_); } + ArkUI_NodeHandle GetPreviousSibling() const { return nativeModule_->getPreviousSibling(handle_); } + ArkUI_NodeHandle GetNextSibling() const { return nativeModule_->getNextSibling(handle_); } + + // 以下方法可以跨过ContentSlot。 + ArkUI_NodeHandle GetParentInPageTree() const { return OH_ArkUI_NodeUtils_GetParentInPageTree(handle_); } + + ArkUI_NodeHandle GetCurrentPageRootNode() const { return OH_ArkUI_NodeUtils_GetCurrentPageRootNode(handle_); } + + ArkUI_NodeHandle GetActiveChildrenByIndex(uint32_t index) const + { + ArkUI_ActiveChildrenInfo *childrenInfo; + OH_ArkUI_NodeUtils_GetActiveChildrenInfo(handle_, &childrenInfo); + auto count = OH_ArkUI_ActiveChildrenInfo_GetCount(childrenInfo); + ArkUI_NodeHandle child; + if (index < count) { + child = OH_ArkUI_ActiveChildrenInfo_GetNodeByIndex(childrenInfo, index); + } + OH_ArkUI_ActiveChildrenInfo_Destroy(childrenInfo); + return child; + } + + // 用于获取懒展开的第一个活跃子节点下标。 + uint32_t GetFirstChildIndexWithoutExpand() const + { + uint32_t index = -1; + OH_ArkUI_NodeUtils_GetFirstChildIndexWithoutExpand(handle_, &index); + return index; + } + + // 用于获取懒展开的最后一个活跃子节点下标。 + uint32_t GetLastChildIndexWithoutExpand() const + { + uint32_t index = -1; + OH_ArkUI_NodeUtils_GetLastChildIndexWithoutExpand(handle_, &index); + return index; + } + + // 根据前置接口获取的懒展开活跃节点范围,高效的获取子节点信息。 + ArkUI_NodeHandle GetChildWithExpandMode(uint32_t index) const + { + ArkUI_NodeHandle subNode; + auto result = OH_ArkUI_NodeUtils_GetChildWithExpandMode(handle_, index, &subNode, ARKUI_LAZY_EXPAND); + if (result == ARKUI_ERROR_CODE_NO_ERROR) { + return subNode; + } + return nullptr; + } + + // 通知节点从布局到绘制全部标脏,实际使用可根据业务需要选择其中具体需要执行的内容,提升性能。 + void MarkDirty() + { + nativeModule_->markDirty(handle_, NODE_NEED_MEASURE); + nativeModule_->markDirty(handle_, NODE_NEED_LAYOUT); + nativeModule_->markDirty(handle_, NODE_NEED_RENDER); + } + + // 对单一节点设置单位。 + void SetLengthMetricUnit(ArkUI_LengthMetricUnit unit) { nativeModule_->setLengthMetricUnit(handle_, unit); } + + // 设置及获取自定义属性。 + void AddCustomProperty(const char *name, const char *value) + { + OH_ArkUI_NodeUtils_AddCustomProperty(handle_, name, value); + } + + void RemoveCustomProperty(const char *name) { OH_ArkUI_NodeUtils_RemoveCustomProperty(handle_, name); } + + const char *GetCustomProperty(const char *name) + { + ArkUI_CustomProperty *property; + OH_ArkUI_NodeUtils_GetCustomProperty(handle_, name, &property); + auto value = OH_ArkUI_CustomProperty_GetStringValue(property); + OH_ArkUI_CustomProperty_Destroy(property); + return value; + } + + // 节点迁移,可跨实例转移节点。 + void MoveTo(const std::shared_ptr &anotherParent) + { + OH_ArkUI_NodeUtils_MoveTo(handle_, anotherParent->GetHandle(), -1); //-1代表放到最后一个位置 + } + + ArkUI_NodeHandle GetHandle() const { return handle_; } + + protected: + // 针对父容器子类需要重载下面的函数,实现组件挂载和卸载。 + virtual void OnAddChild(const std::shared_ptr &child) {} + virtual void OnRemoveChild(const std::shared_ptr &child) {} + virtual void OnRemoveAllChild() {} + virtual void OnInsertChild(const std::shared_ptr &child, int32_t index) {} + virtual void OnInsertChildBefore(const std::shared_ptr &child, + const std::shared_ptr &slibing) {} + virtual void OnInsertChildAfter(const std::shared_ptr &child, + const std::shared_ptr &slibing) {} + + ArkUI_NodeHandle handle_; + ArkUI_NativeNodeAPI_1 *nativeModule_ = nullptr; + + private: + std::list> children_; + }; +} // namespace NativeModule + +#endif // MYAPPLICATION_ARKUIBASENODE_H \ No newline at end of file diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUIColumnNode.h b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUIColumnNode.h new file mode 100644 index 0000000000000000000000000000000000000000..b83d518500f06b9208695055085d6386ddb77ebe --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUIColumnNode.h @@ -0,0 +1,36 @@ +/* + * 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. + */ +// ArkUIColumnNode.h +// 自定义绘制组件示例 +#ifndef MYAPPLICATION_ARKUICOLUMNNODE_H +#define MYAPPLICATION_ARKUICOLUMNNODE_H + + +#include "ArkUINode.h" + +namespace NativeModule { + + class ArkUIColumnNode : public ArkUINode { + public: + // 使用自定义组件类型ARKUI_NODE_CUSTOM创建组件。 + ArkUIColumnNode() + : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_COLUMN)) {} + + ~ArkUIColumnNode() override {} + }; + +} // namespace NativeModule + +#endif // MYAPPLICATION_ArkUIColumnNode_H \ No newline at end of file diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUICustomContainerNode.h b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUICustomContainerNode.h new file mode 100644 index 0000000000000000000000000000000000000000..a567805ce99b5a8db8606a46926c7fad6c515b02 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUICustomContainerNode.h @@ -0,0 +1,126 @@ +/* + * 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. + */ +// ArkUICustomContainerNode.h +// 自定义容器组件示例 +#ifndef MYAPPLICATION_ARKUICUSTOMCONTAINERNODE_H +#define MYAPPLICATION_ARKUICUSTOMCONTAINERNODE_H + +#include "ArkUINode.h" + +namespace NativeModule { + class ArkUICustomContainerNode : public ArkUINode { + public: + // 使用自定义组件类型ARKUI_NODE_CUSTOM创建组件。 + ArkUICustomContainerNode() + : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_CUSTOM)) + { + // 注册自定义事件监听器。 + nativeModule_->addNodeCustomEventReceiver(handle_, OnStaticCustomEvent); + // 声明自定义事件并传递自身作为自定义数据。 + nativeModule_->registerNodeCustomEvent(handle_, ARKUI_NODE_CUSTOM_EVENT_ON_MEASURE, 0, this); + nativeModule_->registerNodeCustomEvent(handle_, ARKUI_NODE_CUSTOM_EVENT_ON_LAYOUT, 0, this); + } + + ~ArkUICustomContainerNode() override + { + // 反注册自定义事件监听器。 + nativeModule_->removeNodeCustomEventReceiver(handle_, OnStaticCustomEvent); + // 取消声明自定义事件。 + nativeModule_->unregisterNodeCustomEvent(handle_, ARKUI_NODE_CUSTOM_EVENT_ON_MEASURE); + nativeModule_->unregisterNodeCustomEvent(handle_, ARKUI_NODE_CUSTOM_EVENT_ON_LAYOUT); + } + + void SetPadding(int32_t padding) + { + padding_ = padding; + // 自定义属性事件更新需要主动调用标记脏区接口。 + nativeModule_->markDirty(handle_, NODE_NEED_MEASURE); + } + + private: + static void OnStaticCustomEvent(ArkUI_NodeCustomEvent *event) + { + // 获取组件实例对象,调用相关实例方法。 + auto customNode = reinterpret_cast(OH_ArkUI_NodeCustomEvent_GetUserData(event)); + auto type = OH_ArkUI_NodeCustomEvent_GetEventType(event); + switch (type) { + case ARKUI_NODE_CUSTOM_EVENT_ON_MEASURE: + customNode->OnMeasure(event); + break; + case ARKUI_NODE_CUSTOM_EVENT_ON_LAYOUT: + customNode->OnLayout(event); + break; + default: + break; + } + } + + // 自定义测算逻辑。 + void OnMeasure(ArkUI_NodeCustomEvent *event) + { + auto layoutConstrain = OH_ArkUI_NodeCustomEvent_GetLayoutConstraintInMeasure(event); + // 创建子节点布局限制,复用父组件布局中的百分比参考值。 + auto childLayoutConstrain = OH_ArkUI_LayoutConstraint_Copy(layoutConstrain); + int32_t maxConstrain = 1000; + OH_ArkUI_LayoutConstraint_SetMaxHeight(childLayoutConstrain, maxConstrain); + OH_ArkUI_LayoutConstraint_SetMaxWidth(childLayoutConstrain, maxConstrain); + OH_ArkUI_LayoutConstraint_SetMinHeight(childLayoutConstrain, 0); + OH_ArkUI_LayoutConstraint_SetMinWidth(childLayoutConstrain, 0); + + // 测算子节点获取子节点最大值。 + auto totalSize = nativeModule_->getTotalChildCount(handle_); + int32_t maxWidth = 0; + int32_t maxHeight = 0; + for (uint32_t i = 0; i < totalSize; i++) { + auto child = nativeModule_->getChildAt(handle_, i); + // 调用测算接口测算Native组件。 + nativeModule_->measureNode(child, childLayoutConstrain); + auto size = nativeModule_->getMeasuredSize(child); + if (size.width > maxWidth) { + maxWidth = size.width; + } + if (size.height > maxHeight) { + maxHeight = size.height; + } + } + // 自定义测算为所有子节点大小加固定边距。该自定义节点最终的尺寸以此处设置的值为准。 + nativeModule_->setMeasuredSize(handle_, maxWidth + 2 * padding_, maxHeight + 2 * padding_); // padding需要乘以2。 + } + + void OnLayout(ArkUI_NodeCustomEvent *event) + { + // 获取父组件期望位置并设置。 + auto position = OH_ArkUI_NodeCustomEvent_GetPositionInLayout(event); + nativeModule_->setLayoutPosition(handle_, position.x, position.y); + + // 设置子组件居中对齐。 + auto totalSize = nativeModule_->getTotalChildCount(handle_); + auto selfSize = nativeModule_->getMeasuredSize(handle_); + for (uint32_t i = 0; i < totalSize; i++) { + auto child = nativeModule_->getChildAt(handle_, i); + // 获取子组件大小。 + auto childSize = nativeModule_->getMeasuredSize(child); + // 布局子组件位置。 + nativeModule_->layoutNode(child, (selfSize.width - childSize.width) / 2, + (selfSize.height - childSize.height) / 2); // 除以2作居中。 + } + } + + int32_t padding_ = 100; + }; + +} // namespace NativeModule + +#endif // MYAPPLICATION_ARKUICUSTOMCONTAINERNODE_H \ No newline at end of file diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUICustomNode.h b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUICustomNode.h new file mode 100644 index 0000000000000000000000000000000000000000..33e82871e7b4c102c12c82fbdc6c922d40da3a82 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUICustomNode.h @@ -0,0 +1,214 @@ +/* + * 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. + */ +// ArkUICustomNode.h +// 自定义绘制组件示例 +#ifndef MYAPPLICATION_ARKUICUSTOMNODE_H +#define MYAPPLICATION_ARKUICUSTOMNODE_H + +#include +#include +#include + +#include "ArkUINode.h" + +namespace NativeModule { + +class ArkUICustomNode : public ArkUINode { +public: + // 使用自定义组件类型ARKUI_NODE_CUSTOM创建组件。 + ArkUICustomNode() + : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_CUSTOM)) + { + // 注册自定义事件监听器。 + nativeModule_->addNodeCustomEventReceiver(handle_, OnStaticCustomEvent); + // 声明自定义事件并转递自身作为自定义数据。 + nativeModule_->registerNodeCustomEvent(handle_, ARKUI_NODE_CUSTOM_EVENT_ON_DRAW_FRONT, 0, this); + nativeModule_->registerNodeCustomEvent(handle_, ARKUI_NODE_CUSTOM_EVENT_ON_DRAW, 0, this); + nativeModule_->registerNodeCustomEvent(handle_, ARKUI_NODE_CUSTOM_EVENT_ON_DRAW_BEHIND, 0, this); + // 绘制完成事件通知。 + OH_ArkUI_RegisterDrawCallbackOnNodeHandle(handle_, nullptr, [](void* userData) {}); + } + + ~ArkUICustomNode() override + { + // 反注册自定义事件监听器。 + nativeModule_->removeNodeCustomEventReceiver(handle_, OnStaticCustomEvent); + // 取消声明自定义事件。 + nativeModule_->unregisterNodeCustomEvent(handle_, ARKUI_NODE_CUSTOM_EVENT_ON_DRAW_FRONT); + nativeModule_->unregisterNodeCustomEvent(handle_, ARKUI_NODE_CUSTOM_EVENT_ON_DRAW); + nativeModule_->unregisterNodeCustomEvent(handle_, ARKUI_NODE_CUSTOM_EVENT_ON_DRAW_BEHIND); + OH_ArkUI_UnregisterDrawCallbackOnNodeHandle(handle_); + } + +private: + int32_t NUM_2 = 2; + int32_t NUM_3 = 3; + int32_t NUM_4 = 4; + int32_t NUM_5 = 5; + + static void OnStaticCustomEvent(ArkUI_NodeCustomEvent *event) + { + // 获取组件实例对象,调用相关实例方法。 + auto targetId = OH_ArkUI_NodeCustomEvent_GetEventTargetId(event); + auto handle = OH_ArkUI_NodeCustomEvent_GetNodeHandle(event); + auto customNode = reinterpret_cast(OH_ArkUI_NodeCustomEvent_GetUserData(event)); + auto type = OH_ArkUI_NodeCustomEvent_GetEventType(event); + switch (type) { + //绘制层级由低到高。 + case ARKUI_NODE_CUSTOM_EVENT_ON_DRAW_BEHIND: + customNode->OnDrawBehind(event); + break; + case ARKUI_NODE_CUSTOM_EVENT_ON_DRAW: + customNode->OnDraw(event); + break; + case ARKUI_NODE_CUSTOM_EVENT_ON_DRAW_FRONT: + customNode->OnDrawFront(event); + break; + case ARKUI_NODE_CUSTOM_EVENT_ON_FOREGROUND_DRAW: + customNode->OnDrawForeGround(event); + break; + case ARKUI_NODE_CUSTOM_EVENT_ON_OVERLAY_DRAW: + customNode->OnDrawOverLay(event); + break; + default: + break; + } + } + + // 自定义绘制逻辑。 + void OnDrawBehind(ArkUI_NodeCustomEvent *event) + { + auto drawContext = OH_ArkUI_NodeCustomEvent_GetDrawContextInDraw(event); + // 获取图形绘制对象。 + auto drawCanvas = reinterpret_cast(OH_ArkUI_DrawContext_GetCanvas(drawContext)); + // 获取组件大小。 + auto size = OH_ArkUI_DrawContext_GetSize(drawContext); + // 绘制自定义内容。 + auto path = OH_Drawing_PathCreate(); + OH_Drawing_PathMoveTo(path, size.width / NUM_5, size.height / NUM_5); + OH_Drawing_PathLineTo(path, size.width * NUM_4 / NUM_5, size.height / NUM_5); + OH_Drawing_PathLineTo(path, size.width * NUM_4 / NUM_5, size.height * NUM_4 / NUM_5); + OH_Drawing_PathLineTo(path, size.width / NUM_5, size.height * NUM_4 / NUM_5); + OH_Drawing_PathLineTo(path, size.width / NUM_5, size.height / NUM_5); + OH_Drawing_PathClose(path); + auto brush = OH_Drawing_BrushCreate(); + OH_Drawing_BrushSetColor(brush, 0xFFF0FAFF); // 蓝白色 + OH_Drawing_CanvasAttachBrush(drawCanvas, brush); + OH_Drawing_CanvasDrawPath(drawCanvas, path); + // 释放资源 + OH_Drawing_BrushDestroy(brush); + OH_Drawing_PathDestroy(path); + } + + void OnDraw(ArkUI_NodeCustomEvent *event) + { + auto drawContext = OH_ArkUI_NodeCustomEvent_GetDrawContextInDraw(event); + // 获取图形绘制对象。 + auto drawCanvas = reinterpret_cast(OH_ArkUI_DrawContext_GetCanvas(drawContext)); + // 获取组件大小。 + auto size = OH_ArkUI_DrawContext_GetSize(drawContext); + // 绘制自定义内容。 + auto path = OH_Drawing_PathCreate(); + OH_Drawing_PathMoveTo(path, size.width / NUM_4, size.height / NUM_4); + OH_Drawing_PathLineTo(path, size.width * NUM_3 / NUM_4, size.height / NUM_4); + OH_Drawing_PathLineTo(path, size.width * NUM_3 / NUM_4, size.height * NUM_3 / NUM_4); + OH_Drawing_PathLineTo(path, size.width / NUM_4, size.height * NUM_3 / NUM_4); + OH_Drawing_PathLineTo(path, size.width / NUM_4, size.height / NUM_4); + OH_Drawing_PathClose(path); + auto brush = OH_Drawing_BrushCreate(); + OH_Drawing_BrushSetColor(brush, 0xff2787D9); // 浅蓝色 + OH_Drawing_CanvasAttachBrush(drawCanvas, brush); + OH_Drawing_CanvasDrawPath(drawCanvas, path); + // 释放资源 + OH_Drawing_BrushDestroy(brush); + OH_Drawing_PathDestroy(path); + } + + void OnDrawFront(ArkUI_NodeCustomEvent *event) + { + auto drawContext = OH_ArkUI_NodeCustomEvent_GetDrawContextInDraw(event); + // 获取图形绘制对象。 + auto drawCanvas = reinterpret_cast(OH_ArkUI_DrawContext_GetCanvas(drawContext)); + // 获取组件大小。 + auto size = OH_ArkUI_DrawContext_GetSize(drawContext); + // 绘制自定义内容。 + auto path = OH_Drawing_PathCreate(); + OH_Drawing_PathMoveTo(path, size.width / NUM_3, size.height / NUM_3); + OH_Drawing_PathLineTo(path, size.width * NUM_2 / NUM_3, size.height / NUM_3); + OH_Drawing_PathLineTo(path, size.width * NUM_2 / NUM_3, size.height * NUM_2 / NUM_3); + OH_Drawing_PathLineTo(path, size.width / NUM_3, size.height * NUM_2 / NUM_3); + OH_Drawing_PathLineTo(path, size.width / NUM_3, size.height / NUM_3); + OH_Drawing_PathClose(path); + auto brush = OH_Drawing_BrushCreate(); + OH_Drawing_BrushSetColor(brush, 0xFF00NUM_4AAF); // 深蓝色 + OH_Drawing_CanvasAttachBrush(drawCanvas, brush); + OH_Drawing_CanvasDrawPath(drawCanvas, path); + // 释放资源 + OH_Drawing_BrushDestroy(brush); + OH_Drawing_PathDestroy(path); + } + + void OnDrawForeGround(ArkUI_NodeCustomEvent *event) + { + auto drawContext = OH_ArkUI_NodeCustomEvent_GetDrawContextInDraw(event); + // 获取图形绘制对象。 + auto drawCanvas = reinterpret_cast(OH_ArkUI_DrawContext_GetCanvas(drawContext)); + // 获取组件大小。 + auto size = OH_ArkUI_DrawContext_GetSize(drawContext); + // 绘制自定义内容。 + auto path = OH_Drawing_PathCreate(); + OH_Drawing_PathMoveTo(path, size.width / NUM_2, size.height / NUM_2); + OH_Drawing_PathLineTo(path, size.width * NUM_2 / NUM_2, size.height / NUM_2); + OH_Drawing_PathLineTo(path, size.width * NUM_2 / NUM_2, size.height * NUM_2 / NUM_2); + OH_Drawing_PathLineTo(path, size.width / NUM_2, size.height * NUM_2 / NUM_2); + OH_Drawing_PathLineTo(path, size.width / NUM_2, size.height / NUM_2); + OH_Drawing_PathClose(path); + auto brush = OH_Drawing_BrushCreate(); + OH_Drawing_BrushSetColor(brush, 0xFFFF0000); // 红色 + OH_Drawing_CanvasAttachBrush(drawCanvas, brush); + OH_Drawing_CanvasDrawPath(drawCanvas, path); + // 释放资源 + OH_Drawing_BrushDestroy(brush); + OH_Drawing_PathDestroy(path); + } + + void OnDrawOverLay(ArkUI_NodeCustomEvent *event) + { + auto drawContext = OH_ArkUI_NodeCustomEvent_GetDrawContextInDraw(event); + // 获取图形绘制对象。 + auto drawCanvas = reinterpret_cast(OH_ArkUI_DrawContext_GetCanvas(drawContext)); + // 获取组件大小。 + auto size = OH_ArkUI_DrawContext_GetSize(drawContext); + // 绘制自定义内容。 + auto path = OH_Drawing_PathCreate(); + OH_Drawing_PathMoveTo(path, size.width, size.height); + OH_Drawing_PathLineTo(path, size.width, size.height); + OH_Drawing_PathLineTo(path, size.width * NUM_2, size.height * NUM_2); + OH_Drawing_PathLineTo(path, size.width, size.height * NUM_2); + OH_Drawing_PathLineTo(path, size.width, size.height / NUM_2); + OH_Drawing_PathClose(path); + auto brush = OH_Drawing_BrushCreate(); + OH_Drawing_BrushSetColor(brush, 0xFF00FF00); // 绿色 + OH_Drawing_CanvasAttachBrush(drawCanvas, brush); + OH_Drawing_CanvasDrawPath(drawCanvas, path); + // 释放资源 + OH_Drawing_BrushDestroy(brush); + OH_Drawing_PathDestroy(path); + } +}; + +} // namespace NativeModule + +#endif // MYAPPLICATION_ARKUICUSTOMNODE_H \ No newline at end of file diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUIListItemAdapter.h b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUIListItemAdapter.h new file mode 100644 index 0000000000000000000000000000000000000000..a76e275a032c417a884ede5fefd742594ab5e487 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUIListItemAdapter.h @@ -0,0 +1,210 @@ +/* + * 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. + */ +// ArkUIListItemAdapter +// 用于文本列表懒加载功能代码。 +#ifndef MYAPPLICATION_ARKUILISTITEMADAPTER_H +#define MYAPPLICATION_ARKUILISTITEMADAPTER_H + +#include +#include +#include +#include + +#include "ArkUIListItemNode.h" +#include "ArkUITextNode.h" +#include "NativeModule.h" +#include + +namespace NativeModule { + + class ArkUIListItemAdapter { + public: + ArkUIListItemAdapter() + : module_(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()), + handle_(OH_ArkUI_NodeAdapter_Create()) // 使用NodeAdapter创建函数。 + { + // 初始化懒加载数据。 + for (int32_t i = 0; i < 1000; i++) { //模拟1000组数据。 + data_.emplace_back(std::to_string(i)); + } + // 设置懒加载数据。 + OH_ArkUI_NodeAdapter_SetTotalNodeCount(handle_, data_.size()); + // 设置懒加载回调事件。 + OH_ArkUI_NodeAdapter_RegisterEventReceiver(handle_, this, OnStaticAdapterEvent); + } + + ~ArkUIListItemAdapter() + { + // 释放创建的组件。 + while (!cachedItems_.empty()) { + cachedItems_.pop(); + } + items_.clear(); + // 释放Adapter相关资源。 + OH_ArkUI_NodeAdapter_UnregisterEventReceiver(handle_); + OH_ArkUI_NodeAdapter_Dispose(handle_); + } + + ArkUI_NodeAdapterHandle GetHandle() const { return handle_; } + + void RemoveItem(int32_t index) + { + // 删除第index个数据。 + data_.erase(data_.begin() + index); + // 如果index会导致可视区域元素发生可见性变化,则会回调NODE_ADAPTER_EVENT_ON_REMOVE_NODE_FROM_ADAPTER事件删除元素, + // 根据是否有新增元素回调NODE_ADAPTER_EVENT_ON_GET_NODE_ID和NODE_ADAPTER_EVENT_ON_ADD_NODE_TO_ADAPTER事件。 + OH_ArkUI_NodeAdapter_RemoveItem(handle_, index, 1); + // 更新新的数量。 + OH_ArkUI_NodeAdapter_SetTotalNodeCount(handle_, data_.size()); + } + + void InsertItem(int32_t index, const std::string &value) + { + data_.insert(data_.begin() + index, value); + // 如果index会导致可视区域元素发生可见性变化,则会回调NODE_ADAPTER_EVENT_ON_GET_NODE_ID + // 和NODE_ADAPTER_EVENT_ON_ADD_NODE_TO_ADAPTER事件 + // 根据是否有删除元素回调NODE_ADAPTER_EVENT_ON_REMOVE_NODE_FROM_ADAPTER事件。 + OH_ArkUI_NodeAdapter_InsertItem(handle_, index, 1); + // 更新新的数量。 + OH_ArkUI_NodeAdapter_SetTotalNodeCount(handle_, data_.size()); + } + + void MoveItem(int32_t oldIndex, int32_t newIndex) + { + auto temp = data_[oldIndex]; + data_.insert(data_.begin() + newIndex, temp); + data_.erase(data_.begin() + oldIndex); + // 移到位置如果未发生可视区域内元素的可见性变化,则不回调事件,反之根据新增和删除场景回调对应的事件。 + OH_ArkUI_NodeAdapter_MoveItem(handle_, oldIndex, newIndex); + } + + void ReloadItem(int32_t index, const std::string &value) + { + data_[index] = value; + // 如果index位于可视区域内,先回调NODE_ADAPTER_EVENT_ON_REMOVE_NODE_FROM_ADAPTER删除老元素, + // 再回调NODE_ADAPTER_EVENT_ON_GET_NODE_ID和NODE_ADAPTER_EVENT_ON_ADD_NODE_TO_ADAPTER事件。 + OH_ArkUI_NodeAdapter_ReloadItem(handle_, index, 1); + } + + void ReloadAllItem() + { + std::reverse(data_.begin(), data_.end()); + // 全部重新加载场景下,会回调NODE_ADAPTER_EVENT_ON_GET_NODE_ID接口获取新的组件ID, + // 根据新的组件ID进行对比,ID不发生变化的进行复用, + // 针对新增ID的元素,调用NODE_ADAPTER_EVENT_ON_ADD_NODE_TO_ADAPTER事件创建新的组件, + // 然后判断老数据中遗留的未使用ID,调用NODE_ADAPTER_EVENT_ON_REMOVE_NODE_FROM_ADAPTER删除老元素。 + OH_ArkUI_NodeAdapter_ReloadAllItems(handle_); + } + + private: + static void OnStaticAdapterEvent(ArkUI_NodeAdapterEvent *event) + { + // 获取实例对象,回调实例事件。 + auto itemAdapter = reinterpret_cast(OH_ArkUI_NodeAdapterEvent_GetUserData(event)); + itemAdapter->OnAdapterEvent(event); + } + + void OnAdapterEvent(ArkUI_NodeAdapterEvent *event) + { + auto type = OH_ArkUI_NodeAdapterEvent_GetType(event); + switch (type) { + case NODE_ADAPTER_EVENT_ON_GET_NODE_ID: + OnNewItemIdCreated(event); + break; + case NODE_ADAPTER_EVENT_ON_ADD_NODE_TO_ADAPTER: + OnNewItemAttached(event); + break; + case NODE_ADAPTER_EVENT_ON_REMOVE_NODE_FROM_ADAPTER: + OnItemDetached(event); + break; + default: + break; + } + } + + // 分配ID给需要显示的Item,用于ReloadAllItems场景的元素diff。 + void OnNewItemIdCreated(ArkUI_NodeAdapterEvent *event) + { + auto index = OH_ArkUI_NodeAdapterEvent_GetItemIndex(event); + static std::hash hashId = std::hash(); + auto id = hashId(data_[index]); + OH_ArkUI_NodeAdapterEvent_SetNodeId(event, id); + } + + // 需要新的Item显示在可见区域。 + void OnNewItemAttached(ArkUI_NodeAdapterEvent *event) + { + auto index = OH_ArkUI_NodeAdapterEvent_GetItemIndex(event); + ArkUI_NodeHandle handle = nullptr; + int32_t textHeight = 100; + int32_t textFontSize = 16; + if (!cachedItems_.empty()) { + // 使用并更新回收复用的缓存。 + auto recycledItem = cachedItems_.top(); + auto textItem = std::dynamic_pointer_cast(recycledItem->GetChildren().back()); + textItem->SetTextContent(data_[index]); + handle = recycledItem->GetHandle(); + // 释放缓存池的引用。 + cachedItems_.pop(); + } else { + // 创建新的元素。 + auto listItem = std::make_shared(); + auto textNode = std::make_shared(); + textNode->SetTextContent(data_[index]); + textNode->SetFontSize(textFontSize); + textNode->SetPercentWidth(1); + textNode->SetHeight(textHeight); + textNode->SetBackgroundColor(0xFFfffacd); + textNode->SetTextAlign(ARKUI_TEXT_ALIGNMENT_CENTER); + listItem->AddChild(textNode); + auto swipeNode = std::make_shared(); + swipeNode->RegisterOnClick([this, data = data_[index]](ArkUI_NodeEvent *event) { + auto it = std::find(data_.begin(), data_.end(), data); + if (it != data_.end()) { + auto index = std::distance(data_.begin(), it); + RemoveItem(index); + } + }); + listItem->SetSwiperAction(swipeNode); + handle = listItem->GetHandle(); + // 保持文本列表项的引用。 + items_.emplace(handle, listItem); + } + // 设置需要展示的元素。 + OH_ArkUI_NodeAdapterEvent_SetItem(event, handle); + } + + // Item从可见区域移除。 + void OnItemDetached(ArkUI_NodeAdapterEvent *event) + { + auto item = OH_ArkUI_NodeAdapterEvent_GetRemovedNode(event); + // 放置到缓存池中进行回收复用。 + cachedItems_.emplace(items_[item]); + } + + std::vector data_; + ArkUI_NativeNodeAPI_1 *module_ = nullptr; + ArkUI_NodeAdapterHandle handle_ = nullptr; + + // 管理NodeAdapter生成的元素。 + std::unordered_map> items_; + + // 管理回收复用组件池。 + std::stack> cachedItems_; + }; + +} // namespace NativeModule + +#endif // MYAPPLICATION_ARKUILISTITEMADAPTER_H \ No newline at end of file diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUIListItemNode.h b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUIListItemNode.h new file mode 100644 index 0000000000000000000000000000000000000000..d8cfc7d19be4d0a887e7e53db0f1660ec2a62ade --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUIListItemNode.h @@ -0,0 +1,54 @@ +/* + * 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. + */ +// ArkUIListItemNode.h +// 提供列表项的封装类。 +#ifndef MYAPPLICATION_ARKUILISTITEMNODE_H +#define MYAPPLICATION_ARKUILISTITEMNODE_H +#include "ArkUINode.h" +namespace NativeModule { + class ArkUIListItemNode : public ArkUINode { + public: + ArkUIListItemNode() + : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_LIST_ITEM)) {} + ~ArkUIListItemNode() override + { + if (swipeAction_) { + OH_ArkUI_ListItemSwipeActionOption_Dispose(swipeAction_); + } + if (swipeItem_) { + OH_ArkUI_ListItemSwipeActionItem_Dispose(swipeItem_); + } + } + void SetSwiperAction(std::shared_ptr node) + { + swipeContent_ = node; + swipeItem_ = OH_ArkUI_ListItemSwipeActionItem_Create(); + OH_ArkUI_ListItemSwipeActionItem_SetContent(swipeItem_, node->GetHandle()); + swipeAction_ = OH_ArkUI_ListItemSwipeActionOption_Create(); + OH_ArkUI_ListItemSwipeActionOption_SetEnd(swipeAction_, swipeItem_); + ArkUI_AttributeItem Item = {.object = swipeAction_}; + nativeModule_->setAttribute(handle_, NODE_LIST_ITEM_SWIPE_ACTION, &Item); + } + std::shared_ptr GetSwipeContent() const { return swipeContent_; } + std::list> &GetChildren() { return children_; } + + private: + ArkUI_ListItemSwipeActionOption *swipeAction_ = nullptr; + ArkUI_ListItemSwipeActionItem *swipeItem_ = nullptr; + std::shared_ptr swipeContent_ = nullptr; + std::list> children_; + }; +} // namespace NativeModule +#endif // MYAPPLICATION_ARKUILISTITEMNODE_H \ No newline at end of file diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUIListNode.h b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUIListNode.h new file mode 100644 index 0000000000000000000000000000000000000000..34361b1723e4decae0d444395b46f41aa82b602b --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUIListNode.h @@ -0,0 +1,41 @@ +/* + * 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. + */ +// ArkUIListNode.h +// 提供列表组件的封装。 +#ifndef MYAPPLICATION_ARKUILISTNODE_H +#define MYAPPLICATION_ARKUILISTNODE_H + +#include "ArkUINode.h" + +namespace NativeModule { + class ArkUIListNode : public ArkUINode { + public: + ArkUIListNode() // 创建ArkUI的列表组件。 + : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_LIST)) {} + + ~ArkUIListNode() override {} + // List组件的属性接口封装。 + void SetScrollBarState(bool isShow) + { + ArkUI_ScrollBarDisplayMode displayMode = + isShow ? ARKUI_SCROLL_BAR_DISPLAY_MODE_ON : ARKUI_SCROLL_BAR_DISPLAY_MODE_OFF; + ArkUI_NumberValue value[] = {{.i32 = displayMode}}; + ArkUI_AttributeItem item = {value, 1}; + nativeModule_->setAttribute(handle_, NODE_SCROLL_BAR_DISPLAY_MODE, &item); + } + }; +} // namespace NativeModule + +#endif // MYAPPLICATION_ARKUILISTNODE_H \ No newline at end of file diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUINode.h b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUINode.h new file mode 100644 index 0000000000000000000000000000000000000000..58f975b314868175159a49d25c833a026620c4b6 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUINode.h @@ -0,0 +1,299 @@ +/* + * 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. + */ +// ArkUINode.h +// 提供通用属性和事件的封装。 +#ifndef MYAPPLICATION_ARKUINODE_H +#define MYAPPLICATION_ARKUINODE_H + +#include "ArkUIBaseNode.h" +#include "NativeModule.h" +#include +#include +#include +#include +#include + +namespace NativeModule { + +void CallBack(uint64_t nanoTimeLeft, uint32_t frameCount, void *userData) +{ + OH_LOG_Print(LOG_APP, LOG_INFO, 0xFF00, "PostCallback", + "***StartCallBack*** nanoTimeLeft = %{public}lu , frameCount = %{public}d", + nanoTimeLeft, frameCount); + if (userData) { + int *myData = (int *)userData; + } + // 执行业务相关逻辑。 +} + +class ArkUINode : public ArkUIBaseNode { +public: + explicit ArkUINode(ArkUI_NodeHandle handle) : ArkUIBaseNode(handle) + { + nativeModule_ = NativeModuleInstance::GetInstance()->GetNativeNodeAPI(); + // 事件触发时需要通过函数获取对应的事件对象,这边通过设置节点自定义数据将封装类指针保持在组件上,方便后续事件分发。 + nativeModule_->setUserData(handle_, this); + // 注册节点监听事件接受器。 + nativeModule_->addNodeEventReceiver(handle_, ArkUINode::NodeEventReceiver); + } + + ~ArkUINode() override + { + if (onClick_) { + nativeModule_->unregisterNodeEvent(handle_, NODE_ON_CLICK_EVENT); + } + if (onTouch_) { + nativeModule_->unregisterNodeEvent(handle_, NODE_TOUCH_EVENT); + } + if (onDisappear_) { + nativeModule_->unregisterNodeEvent(handle_, NODE_EVENT_ON_DISAPPEAR); + } + if (onAppear_) { + nativeModule_->unregisterNodeEvent(handle_, NODE_EVENT_ON_APPEAR); + } + nativeModule_->removeNodeEventReceiver(handle_, ArkUINode::NodeEventReceiver); + } + + // 通用属性调用封装 + void SetWidth(float width) + { + ArkUI_NumberValue value[] = {{.f32 = width}}; + ArkUI_AttributeItem item = {value, 1}; + auto result = nativeModule_->setAttribute(handle_, NODE_WIDTH, &item); + CheckErrorCode(result); + } + void SetPercentWidth(float percent) + { + ArkUI_NumberValue value[] = {{.f32 = percent}}; + ArkUI_AttributeItem item = {value, 1}; + auto result = nativeModule_->setAttribute(handle_, NODE_WIDTH_PERCENT, &item); + CheckErrorCode(result); + } + void SetHeight(float height) + { + ArkUI_NumberValue value[] = {{.f32 = height}}; + ArkUI_AttributeItem item = {value, 1}; + auto result = nativeModule_->setAttribute(handle_, NODE_HEIGHT, &item); + CheckErrorCode(result); + } + void SetPercentHeight(float percent) + { + ArkUI_NumberValue value[] = {{.f32 = percent}}; + ArkUI_AttributeItem item = {value, 1}; + auto result = nativeModule_->setAttribute(handle_, NODE_HEIGHT_PERCENT, &item); + CheckErrorCode(result); + } + void SetBackgroundColor(uint32_t color) + { + ArkUI_NumberValue value[] = {{.u32 = color}}; + ArkUI_AttributeItem item = {value, 1}; + auto result = nativeModule_->setAttribute(handle_, NODE_BACKGROUND_COLOR, &item); + CheckErrorCode(result); + } + void SetId(const std::string &id) + { + ArkUI_AttributeItem item = {.string = id.c_str() }; + auto result = nativeModule_->setAttribute(handle_, NODE_ID, &item); + CheckErrorCode(result); + } + void CheckErrorCode(int32_t errorCode) + { + if (errorCode == ARKUI_ERROR_CODE_NO_ERROR) { + return; + } + int32_t uniqueId = -1; + OH_ArkUI_NodeUtils_GetNodeUniqueId(handle_, &uniqueId); + auto nodeType = OH_ArkUI_NodeUtils_GetNodeType(handle_); + auto isNDKNode = OH_ArkUI_NodeUtils_IsCreatedByNDK(handle_); + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "Manager", + "ErrorCode:%{public}d, uniqueId:%{public}d, nodeType:%{public}d, isCreateByNdk:%{public}d", + errorCode, uniqueId, nodeType, isNDKNode); + } + + void SetCrossLanguage(bool isCross) + { + auto option = OH_ArkUI_CrossLanguageOption_Create(); + OH_ArkUI_CrossLanguageOption_SetAttributeSettingStatus(option, isCross); + OH_ArkUI_NodeUtils_SetCrossLanguageOption(handle_, option); + OH_ArkUI_CrossLanguageOption_Destroy(option); + } + + bool GetCrossLanguage() + { + auto option = OH_ArkUI_CrossLanguageOption_Create(); + OH_ArkUI_NodeUtils_GetCrossLanguageOption(handle_, option); + bool isCross = OH_ArkUI_CrossLanguageOption_GetAttributeSettingStatus(option); + int32_t uniqueId = -1; + OH_ArkUI_NodeUtils_GetNodeUniqueId(handle_, &uniqueId); + OH_LOG_Print(LOG_APP, LOG_ERROR, 0xFF00, "Manager", + "uniqueId:%{public}d, isCrossLanguage:%{public}d", uniqueId, isCross); + OH_ArkUI_CrossLanguageOption_Destroy(option); + } + + ArkUI_IntOffset GetLayoutPositionInWindow() + { + ArkUI_IntOffset globalOffset; + auto result = OH_ArkUI_NodeUtils_GetLayoutPositionInWindow(handle_, &globalOffset); + if (result == ARKUI_ERROR_CODE_NO_ERROR) { + return globalOffset; + } else { + return {0, 0}; + } + } + + ArkUI_IntOffset GetPositionWithTranslateInWindow() + { + ArkUI_IntOffset translateOffset; + auto result = OH_ArkUI_NodeUtils_GetPositionWithTranslateInWindow(handle_, &translateOffset); + if (result == ARKUI_ERROR_CODE_NO_ERROR) { + return translateOffset; + } else { + return {0, 0}; + } + } + + // 处理通用事件。 + void RegisterOnClick(const std::function &onClick) + { + onClick_ = onClick; + // 注册点击事件。 + nativeModule_->registerNodeEvent(handle_, NODE_ON_CLICK_EVENT, 0, nullptr); + } + + void RegisterOnTouch(const std::function &onTouch) + { + onTouch_ = onTouch; + // 注册触碰事件。 + nativeModule_->registerNodeEvent(handle_, NODE_TOUCH_EVENT, 0, nullptr); + } + + void RegisterOnDisappear(const std::function &onDisappear) + { + onDisappear_ = onDisappear; + // 注册卸载事件。 + nativeModule_->registerNodeEvent(handle_, NODE_EVENT_ON_DISAPPEAR, 0, nullptr); + } + + void RegisterOnAppear(const std::function &onAppear) + { + onAppear_ = onAppear; + // 注册挂载事件。 + nativeModule_->registerNodeEvent(handle_, NODE_EVENT_ON_APPEAR, 0, nullptr); + } + + // 抛出任务在下一帧渲染时执行,用于执行一些需等待其他任务完成时的业务逻辑。 + void PostFrameCallback(void *data) + { + auto context = OH_ArkUI_GetContextByNode(handle_); + OH_ArkUI_PostFrameCallback(context, &data, CallBack); + } + + // 抛出任务在下一帧渲染结束后且vsync信号来临还有大于1ms时执行,若剩余时间小于1ms,则顺延至下一帧并自动请求vysnc。 + void PostIdleCallback(void *data) + { + auto context = OH_ArkUI_GetContextByNode(handle_); + OH_ArkUI_PostIdleCallback(context, &data, CallBack); + } + +protected: + // 组件树操作的实现类对接。 + void OnAddChild(const std::shared_ptr &child) override + { + nativeModule_->addChild(handle_, child->GetHandle()); + } + void OnRemoveChild(const std::shared_ptr &child) override + { + nativeModule_->removeChild(handle_, child->GetHandle()); + } + void OnRemoveAllChild() override + { + nativeModule_->removeAllChildren(handle_); + } + void OnInsertChild(const std::shared_ptr &child, int32_t index) override + { + nativeModule_->insertChildAt(handle_, child->GetHandle(), index); + } + void OnInsertChildBefore(const std::shared_ptr &child, + const std::shared_ptr &slibing) override + { + nativeModule_->insertChildBefore(handle_, child->GetHandle(), slibing->GetHandle()); + } + void OnInsertChildAfter(const std::shared_ptr &child, + const std::shared_ptr &slibing) override + { + nativeModule_->insertChildAfter(handle_, child->GetHandle(), slibing->GetHandle()); + } + + // 事件监听器函数指针。 + static void NodeEventReceiver(ArkUI_NodeEvent *event) + { + // 获取事件发生的UI组件对象。 + auto nodeHandle = OH_ArkUI_NodeEvent_GetNodeHandle(event); + // 获取保持在UI组件对象中的自定义数据,返回封装类指针。 + auto *node = reinterpret_cast( + NativeModuleInstance::GetInstance()->GetNativeNodeAPI()->getUserData(nodeHandle)); + // 基于封装类实例对象处理事件。 + node->ProcessNodeEvent(event); + } + void ProcessNodeEvent(ArkUI_NodeEvent *event) + { + auto eventType = OH_ArkUI_NodeEvent_GetEventType(event); + switch (eventType) { + case NODE_ON_CLICK_EVENT: { + if (onClick_) { + onClick_(event); + } + break; + } + case NODE_TOUCH_EVENT: { + if (onTouch_) { + auto *uiInputEvent = OH_ArkUI_NodeEvent_GetInputEvent(event); + float x = OH_ArkUI_PointerEvent_GetX(uiInputEvent); + float y = OH_ArkUI_PointerEvent_GetY(uiInputEvent); + auto type = OH_ArkUI_UIInputEvent_GetAction(uiInputEvent); + onTouch_(type, x, y); + } + } + case NODE_EVENT_ON_DISAPPEAR: { + if (onDisappear_) { + onDisappear_(); + } + break; + } + case NODE_EVENT_ON_APPEAR: { + if (onAppear_) { + onAppear_(); + } + break; + } + default: { + // 组件特有事件交给子类处理 + OnNodeEvent(event); + } + } + } + + virtual void OnNodeEvent(ArkUI_NodeEvent *event) {} + +private: + std::function onClick_; + std::function onDisappear_; + std::function onAppear_; + std::function onTouch_; +}; + +} // namespace NativeModule + +#endif // MYAPPLICATION_ARKUINODE_H \ No newline at end of file diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUITextNode.h b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUITextNode.h new file mode 100644 index 0000000000000000000000000000000000000000..72079bdc707e1b962a2405d3780e6c9675afcb69 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/ArkUITextNode.h @@ -0,0 +1,77 @@ +/* + * 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. + */ +// ArkUITextNode.h +// 实现文本组件的封装类。 +#ifndef MYAPPLICATION_ARKUITEXTNODE_H +#define MYAPPLICATION_ARKUITEXTNODE_H + +#include "ArkUINode.h" + +#include + +namespace NativeModule { + + void ColorChangeCallback(ArkUI_SystemColorMode colorMode, void *userData) + { + if (userData) { + auto handle = (ArkUI_NodeHandle)userData; + // 执行业务相关逻辑,如更换字体颜色,实际所需内容可以根据userData自行修改。 + bool isDark = (colorMode == ARKUI_SYSTEM_COLOR_MODE_DARK); + ArkUI_NumberValue value[] = { + {.u32 = isDark ? 0xFFFFFFFF : 0xFF000000}}; // 深色模式字体白色,浅色模式字体黑色。 + ArkUI_AttributeItem item = {value, 1}; + NativeModuleInstance::GetInstance()->GetNativeNodeAPI()->setAttribute(handle, NODE_FONT_COLOR, &item); + } + } + + class ArkUITextNode : public ArkUINode { + public: + ArkUITextNode() + : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_TEXT)) {} + // 文本属性接口封装。 + void SetFontSize(float fontSize) + { + ArkUI_NumberValue value[] = {{.f32 = fontSize}}; + ArkUI_AttributeItem item = {value, 1}; + nativeModule_->setAttribute(handle_, NODE_FONT_SIZE, &item); + } + void SetFontColor(uint32_t color) + { + ArkUI_NumberValue value[] = {{.u32 = color}}; + ArkUI_AttributeItem item = {value, 1}; + nativeModule_->setAttribute(handle_, NODE_FONT_COLOR, &item); + } + void SetTextContent(const std::string &content) + { + ArkUI_AttributeItem item = {nullptr, 0, content.c_str()}; + nativeModule_->setAttribute(handle_, NODE_TEXT_CONTENT, &item); + } + void SetTextAlign(ArkUI_TextAlignment align) + { + ArkUI_NumberValue value[] = {{.i32 = align}}; + ArkUI_AttributeItem item = {value, 1}; + nativeModule_->setAttribute(handle_, NODE_TEXT_ALIGN, &item); + } + + void RegistSystemColorModeChange() + { + OH_ArkUI_RegisterSystemColorModeChangeEvent(handle_, handle_, ColorChangeCallback); + } + + void UnregistSystemColorModeChange() { OH_ArkUI_UnregisterSystemColorModeChangeEvent(handle_); } + }; +} // namespace NativeModule + +#endif // MYAPPLICATION_ARKUITEXTNODE_H \ No newline at end of file diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/CMakeLists.txt b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..e90fa73eafa611ef05834c10f4b4c41a7f76fd30 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/CMakeLists.txt @@ -0,0 +1,17 @@ +# the minimum version of CMake. +cmake_minimum_required(VERSION 3.4.1) +project(MyApplication17) + +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 NativeEntry.cpp) + +target_link_libraries(entry PUBLIC libace_napi.z.so libace_ndk.z.so hilog_ndk.z.so) +target_link_libraries(entry PUBLIC libnative_drawing.so) diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/CreateNode.h b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/CreateNode.h new file mode 100644 index 0000000000000000000000000000000000000000..ebb2a0aed51a09c28c7f9929f3326ef68f713028 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/CreateNode.h @@ -0,0 +1,65 @@ +/* + * 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. + */ +// CreateNode.h +#ifndef MYAPPLICATION_CREATENODE_H +#define MYAPPLICATION_CREATENODE_H + +#include "ArkUINode.h" +#include + +namespace NativeModule { + // 封装Button组件。 + class ArkUIButtonNode : public ArkUINode { + public: + ArkUIButtonNode() + : ArkUINode(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()->createNode(ARKUI_NODE_BUTTON)) {} + int32_t SetLabel(ArkUI_AttributeItem &label_item) + { + return nativeModule_->setAttribute(handle_, NODE_BUTTON_LABEL, &label_item); + } + int32_t SetMargin(ArkUI_AttributeItem &item) + { + return nativeModule_->setAttribute(handle_, NODE_MARGIN, &item); + } + }; + + // 封装Row组件。 + class ArkUIRowNode : public ArkUINode { + public: + ArkUIRowNode() + : ArkUINode(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()->createNode(ARKUI_NODE_ROW)) {} + }; + + // 封装Scroll组件。 + class ArkUIScrollNode : public ArkUINode { + public: + ArkUIScrollNode() + : ArkUINode(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()->createNode(ARKUI_NODE_SCROLL)) {} + }; + + // 封装Column组件。 + class ArkUIColumnNode : public ArkUINode { + public: + ArkUIColumnNode() + : ArkUINode(NativeModuleInstance::GetInstance()->GetNativeNodeAPI()->createNode(ARKUI_NODE_COLUMN)) {} + }; + + // 多线程创建组件。 + napi_value CreateNodeTreeOnMultiThread(napi_env env, napi_callback_info info); + // 释放多线程创建的组件。 + napi_value DisposeNodeTreeOnMultiThread(napi_env env, napi_callback_info info); +} // namespace NativeModule + +#endif // MYAPPLICATION_CREATENODE_H \ No newline at end of file diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/NativeEntry.cpp b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/NativeEntry.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9a49043225bf993650db188558be8f3b8fcf53a4 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/NativeEntry.cpp @@ -0,0 +1,420 @@ +/* + * 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. + */ +// NativeEntry.cpp +#include +#include +#include +#include +#include +#include +#include +#include +#include "NativeEntry.h" +#include +#include + +namespace NativeModule { + +#define FRAMEWORK_NODE_TREE_NUMBER 4 // 在框架线程创建组件树的数量。 +#define USER_NODE_TREE_NUMBER 3 // 在开发者线程创建组件树的数量。 +struct AsyncData { + napi_env env; + std::shared_ptr parent = nullptr; + std::shared_ptr child = nullptr; + std::string label = ""; +}; + +// 保存ArkTs侧NodeContent指针与Native侧节点树根节点的对应关系。 +std::map> g_nodeMap; +ArkUI_ContextHandle g_contextHandle = nullptr; + +// 创建组件树。 +void CreateNodeTree(void *asyncUITaskData) +{ + auto asyncData = static_cast(asyncUITaskData); + if (!asyncData) { + return; + } + // 创建组件树根节点。 + auto rowNode = std::make_shared(); + asyncData->child = rowNode; + + // 创建button组件。 + auto buttonNode1 = std::make_shared(); + ArkUI_AttributeItem label_item = {.string = asyncData->label.c_str()}; + // 设置button组件的label属性。 + int32_t result = buttonNode1->SetLabel(label_item); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "Button SetLabel Failed %{public}d", result); + } + ArkUI_NumberValue value[] = {{.f32 = 5}, {.f32 = 5}, {.f32 = 5}, {.f32 = 5}}; + ArkUI_AttributeItem item = {value, 4}; + // 设置button组件的margin属性。 + result = buttonNode1->SetMargin(item); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "Button SetMargin Failed %{public}d", result); + } + int32_t size = 150; + // 设置button组件的width属性。 + buttonNode1->SetWidth(size); + + // 创建button组件。 + auto buttonNode2 = std::make_shared(); + ArkUI_AttributeItem label_item2 = {.string = asyncData->label.c_str()}; + // 设置button组件的label属性。 + result = buttonNode2->SetLabel(label_item2); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "Button SetLabel Failed %{public}d", result); + } + ArkUI_NumberValue value2[] = {{.f32 = 5}, {.f32 = 5}, {.f32 = 5}, {.f32 = 5}}; + ArkUI_AttributeItem item2 = {value2, 4}; + // 设置button组件的margin属性。 + result = buttonNode1->SetMargin(item2); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "Button SetMargin Failed %{public}d", result); + } + // 设置button组件的width属性。 + buttonNode2->SetWidth(size); + + // 把组件挂载到组件树上。 + rowNode->AddChild(buttonNode1); + rowNode->AddChild(buttonNode2); +} + +// 把组件树挂载到UI组件主树上。 +void MountNodeTree(void *asyncUITaskData) +{ + auto asyncData = static_cast(asyncUITaskData); + if (!asyncData) { + return; + } + auto parent = asyncData->parent; + auto child = asyncData->child; + // 把组件树挂载到UI组件主树上。 + parent->AddChild(child); + delete asyncData; +} + +void CreateNodeOnFrameworkThread(ArkUI_ContextHandle contextHandle, std::shared_ptr parent) +{ + for (int i = 0; i < FRAMEWORK_NODE_TREE_NUMBER; i++) { + // UI线程创建子树根节点,保证scroll的子节点顺序。 + auto columnItem = std::make_shared(); + parent->AddChild(columnItem); + AsyncData *asyncData = new AsyncData(); + asyncData->parent = columnItem; + asyncData->label = "OnFwkThread"; + // 使用框架提供的非UI线程创建组件树,创建完成后回到UI线程挂载到主树上。 + int32_t result = OH_ArkUI_PostAsyncUITask(contextHandle, asyncData, CreateNodeTree, MountNodeTree); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "OH_ArkUI_PostAsyncUITask Failed %{public}d", result); + delete asyncData; + } + } +} + +void CreateNodeOnUserThread(ArkUI_ContextHandle contextHandle, std::shared_ptr parent) +{ + auto columnItem = std::make_shared(); + parent->AddChild(columnItem); + // 在开发者创建的非UI线程上创建组件树。 + std::thread userThread([columnItem, contextHandle]() { + for (int i = 0; i < USER_NODE_TREE_NUMBER; i++) { + AsyncData *asyncData = new AsyncData(); + asyncData->parent = columnItem; + asyncData->label = "OnUserThread1"; + CreateNodeTree(asyncData); + // 组件树创建完成后回到UI线程挂载到主树上。 + int32_t result = OH_ArkUI_PostUITask(contextHandle, asyncData, MountNodeTree); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "OH_ArkUI_PostUITask Failed %{public}d", result); + delete asyncData; + } + } + }); + userThread.detach(); +} + +void CreateNodeOnUserThreadAndWait(ArkUI_ContextHandle contextHandle, std::shared_ptr parent) +{ + auto columnItem = std::make_shared(); + parent->AddChild(columnItem); + // 在开发者创建的非UI线程上创建组件树。 + std::thread userThread([columnItem, contextHandle]() { + for (int i = 0; i < USER_NODE_TREE_NUMBER; i++) { + AsyncData *asyncData = new AsyncData(); + asyncData->parent = columnItem; + asyncData->label = "OnUserThread2"; + CreateNodeTree(asyncData); + // 组件树创建完成后回到UI线程挂载到主树上,等待挂载完成后继续创建剩余组件。 + int32_t result = OH_ArkUI_PostUITaskAndWait(contextHandle, asyncData, MountNodeTree); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "OH_ArkUI_PostUITask Failed %{public}d", result); + delete asyncData; + } + } + }); + userThread.detach(); +} + +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); + OH_LOG_ERROR(LOG_APP, "kkk OH_ArkUI_GetNodeContentFromNapiValue Failed %{public}d"); + // 获取ArkTs侧组件挂载点。 + 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; + } + + // 获取上下文对象指针。 + if (!g_contextHandle) { + result = OH_ArkUI_GetContextFromNapiValue(env, args[1], &g_contextHandle); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + OH_LOG_ERROR(LOG_APP, "OH_ArkUI_GetContextFromNapiValue Failed %{public}d", result); + delete g_contextHandle; + g_contextHandle = nullptr; + return nullptr; + } + } + + // 创建Native侧组件树根节点。 + auto scrollNode = std::make_shared(); + // 将Native侧组件树根节点挂载到UI主树上。 + 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; + } + // 保存Native侧组件树。 + g_nodeMap[contentHandle] = scrollNode; + + auto columnNode = std::make_shared(); + scrollNode->AddChild(columnNode); + // 在框架提供的线程池中创建组件。 + CreateNodeOnFrameworkThread(g_contextHandle, columnNode); + // 在开发者创建的非UI线程中创建组件。 + CreateNodeOnUserThread(g_contextHandle, columnNode); + CreateNodeOnUserThreadAndWait(g_contextHandle, columnNode); + return nullptr; +} + + +napi_value DisposeNodeTreeOnMultiThread(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); + + // 获取ArkTs侧组件挂载点。 + 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; + // 将Native侧组件树根节点从UI主树上卸载。 + 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; + } + // 释放Native侧组件树。 + g_nodeMap.erase(contentHandle); + return nullptr; +} + +std::shared_ptr CreateTextListExample() +{ + // 创建组件并挂载 + // 1:使用智能指针创建List组件。 + auto list = std::make_shared(); + list->SetPercentWidth(1); + list->SetPercentHeight(1); + list->SetScrollBarState(true); + // 2:创建ListItem子组件并挂载到List上。 + for (int32_t i = 0; i < 30; ++i) { // 创建30个子项目。 + auto listItem = std::make_shared(); + auto textNode = std::make_shared(); + textNode->SetTextContent(std::to_string(i)); + int32_t fontSize = 16; + textNode->SetFontSize(fontSize); + textNode->SetFontColor(0xFFff00ff); + textNode->SetPercentWidth(1); + int32_t width = 300; + int32_t height = 100; + textNode->SetWidth(width); + textNode->SetHeight(height); + textNode->SetBackgroundColor(0xFFfffacd); + textNode->SetTextAlign(ARKUI_TEXT_ALIGNMENT_CENTER); + listItem->InsertChild(textNode, i); + list->AddChild(listItem); + } + return list; +} + +napi_value CreateNativeRoot(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); + + // 获取NodeContent + ArkUI_NodeContentHandle contentHandle; + OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &contentHandle); + NativeEntry::GetInstance()->SetContentHandle(contentHandle); + + //创建文本列表 + auto list = CreateTextListExample(); + + //保持Native侧对象到管理类中,维护生命周期。 + NativeEntry::GetInstance()->SetRootNode(list); + return nullptr; +} + +napi_value DestroyNativeRoot(napi_env env, napi_callback_info info) +{ + // 从管理类中释放Native侧对象。 + NativeEntry::GetInstance()->DisposeRootNode(); + NativeEntry::GetInstance()->ClearNode(); + return nullptr; +} + +napi_value GetContext(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_ContextHandle context = nullptr; + // result 判断是否获取成功 + auto result = OH_ArkUI_GetContextFromNapiValue(env, args[0], &context); + if (result == ARKUI_ERROR_CODE_NO_ERROR) { + NativeEntry::GetInstance()->SetContextHandle(context); + } + return nullptr; +} + +napi_value GetNodeHandle(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_NodeHandle handle = nullptr; + // result 判断是否获取成功 + auto result = OH_ArkUI_GetNodeHandleFromNapiValue(env, args[0], &handle); + if (result == ARKUI_ERROR_CODE_NO_ERROR) { + NativeEntry::GetInstance()->SetNodeHandle(handle); + } + return nullptr; +} + +napi_value GetNodeHandleById(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); + + size_t maxValueLen = 1024; + char ids[maxValueLen]; + size_t length = 0; + napi_get_value_string_utf8(env, args[0], ids, maxValueLen, &length); + ArkUI_NodeHandle handle = nullptr; + // result 判断是否获取成功 + auto result = OH_ArkUI_NodeUtils_GetAttachedNodeHandleById(ids, &handle); + // 节点获取成功,实现业务功能。 + if (result == ARKUI_ERROR_CODE_NO_ERROR) {} + return nullptr; +} + +napi_value GetNodeHandleByUniqueId(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); + + int32_t id = 0; + napi_get_value_int32(env, args[0], &id); + ArkUI_NodeHandle handle = nullptr; + // result 判断是否获取成功 + auto result = OH_ArkUI_NodeUtils_GetNodeHandleByUniqueId(id, &handle); + if (result == ARKUI_ERROR_CODE_NO_ERROR) { + // 节点获取成功,实现业务功能。 + } +} + +void NativeEntry::SetWindowName() +{ + ArkUI_HostWindowInfo* windowInfo; + auto result = OH_ArkUI_NodeUtils_GetWindowInfo(nodeHandle_, &windowInfo); + if (result != ARKUI_ERROR_CODE_NO_ERROR) { + return; + } + // 保存窗口名称到全局参数。 + windowName_ = OH_ArkUI_HostWindowInfo_GetName(windowInfo); + // 结构体使用完成后,释放对应内存。 + OH_ArkUI_HostWindowInfo_Destroy(windowInfo); +} + +void NativeEntry::RegisterNodeEventReceiver() +{ + NativeModuleInstance::GetInstance()->GetNativeNodeAPI()->registerNodeEventReceiver([](ArkUI_NodeEvent *event) { + // 从组件事件中获取基础事件对象 + auto *inputEvent = OH_ArkUI_NodeEvent_GetInputEvent(event); + // 从组件事件获取事件类型 + auto eventType = OH_ArkUI_NodeEvent_GetEventType(event); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "eventInfo", "inputEvent = %{public}p", inputEvent); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "eventInfo", "eventType = %{public}d", eventType); + auto componentEvent = OH_ArkUI_NodeEvent_GetNodeComponentEvent(event); + // 获取组件事件中的数字类型数据 + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "eventInfo", "componentEvent = %{public}p", componentEvent); + // 获取触发该事件的组件对象 + auto nodeHandle = OH_ArkUI_NodeEvent_GetNodeHandle(event); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "eventInfo", "nodeHandle = %{public}p", nodeHandle); + // 根据eventType来区分事件类型,进行差异化处理,其他获取事件信息的接口也可类似方式来进行差异化的处理 + switch (eventType) { + case NODE_ON_CLICK_EVENT: { + //实现具体业务 + break; + } + default: { + break; + } + } + }); +} + +void NativeEntry::UnregisterNodeEventReceiver() +{ + NativeModuleInstance::GetInstance()->GetNativeNodeAPI()->unregisterNodeEventReceiver(); +} + +} // namespace NativeModule \ No newline at end of file diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/NativeEntry.h b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/NativeEntry.h new file mode 100644 index 0000000000000000000000000000000000000000..90f293a16de59ae18d963463a6ce6a4fce674ced --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/NativeEntry.h @@ -0,0 +1,90 @@ +/* + * 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. + */ +// NativeEntry.h +#ifndef MYAPPLICATION_NATIVEENTRY_H +#define MYAPPLICATION_NATIVEENTRY_H + +#include +#include +#include + +namespace NativeModule { + + napi_value CreateNativeRoot(napi_env env, napi_callback_info info); + napi_value CreateNodeTreeOnMultiThread(napi_env env, napi_callback_info info); + napi_value DisposeNodeTreeOnMultiThread(napi_env env, napi_callback_info info); + + napi_value DestroyNativeRoot(napi_env env, napi_callback_info info); + + napi_value GetContext(napi_env env, napi_callback_info info); + + napi_value GetNodeHandle(napi_env env, napi_callback_info info); + napi_value GetNodeHandleById(napi_env env, napi_callback_info info); + napi_value GetNodeHandleByUniqueId(napi_env env, napi_callback_info info); + const unsigned int LOG_PRINT_DOMAIN = 0xFF00; + // 管理Native组件的生命周期和内存。 + class NativeEntry { + public: + static NativeEntry *GetInstance() + { + static NativeEntry nativeEntry; + return &nativeEntry; + } + + void SetContentHandle(ArkUI_NodeContentHandle handle) { handle_ = handle; } + + void SetContextHandle(ArkUI_ContextHandle handle) { context_ = handle; } + + void SetNodeHandle(ArkUI_NodeHandle handle) { nodeHandle_ = handle; } + + void SetWindowName(); + + void SetRootNode(const std::shared_ptr &baseNode) + { + root_ = baseNode; + // 添加Native组件到NodeContent上用于挂载显示。 + OH_ArkUI_NodeContent_AddNode(handle_, root_->GetHandle()); + } + void DisposeRootNode() + { + // 从NodeContent上卸载组件并销毁Native组件。 + OH_ArkUI_NodeContent_RemoveNode(handle_, root_->GetHandle()); + root_.reset(); + } + + void RegisterNodeEventReceiver(); + void UnregisterNodeEventReceiver(); + + void AddNode(std::shared_ptr node) { nodes_.emplace(node->GetHandle(), node); } + std::shared_ptr FindNodeByHandle(ArkUI_NodeHandle nodeHandle) + { + return nodes_.find(nodeHandle)->second; + } + void ClearNode() { nodes_.clear(); } + + private: + std::shared_ptr root_; + ArkUI_NodeContentHandle handle_; + ArkUI_ContextHandle context_; + ArkUI_NodeHandle nodeHandle_; + const char *windowName_ = nullptr; + + // 管理生成的元素,通过map来查找nodeHandle和对应的BaseNode。 + std::unordered_map> nodes_; + }; + +} // namespace NativeModule + +#endif // MYAPPLICATION_NATIVEENTRY_H \ No newline at end of file diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/NativeModule.h b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/NativeModule.h new file mode 100644 index 0000000000000000000000000000000000000000..9f7121f8ee12c4e4cc4b916e450a7fef6ed257dc --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/NativeModule.h @@ -0,0 +1,53 @@ +/* + * 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. + */ +// NativeModule.h +// 提供获取ArkUI在Native侧模块的封装接口 +#ifndef MYAPPLICATION_NATIVEMODULE_H +#define MYAPPLICATION_NATIVEMODULE_H + +#include "napi/native_api.h" +#include +#include + +#include + +namespace NativeModule { + + class NativeModuleInstance { + public: + static NativeModuleInstance *GetInstance() + { + static NativeModuleInstance instance; + return &instance; + } + + NativeModuleInstance() + { + // 获取接口的函数指针结构体对象,用于后续接口调用。 + OH_ArkUI_GetModuleInterface(ARKUI_NATIVE_NODE, ArkUI_NativeNodeAPI_1, arkUINativeNodeApi_); + // 上下两种获取方式相同,均为获取接口的函数指针结构体对象,用于后续接口调用。 + arkUINativeNodeApi_ = reinterpret_cast( + OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1")); + } + // 暴露给其他模块使用。 + ArkUI_NativeNodeAPI_1 *GetNativeNodeAPI() { return arkUINativeNodeApi_; } + + private: + ArkUI_NativeNodeAPI_1 *arkUINativeNodeApi_ = nullptr; + }; + +} // namespace NativeModule + +#endif // MYAPPLICATION_NATIVEMODULE_H \ No newline at end of file diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/napi_init.cpp b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/napi_init.cpp new file mode 100644 index 0000000000000000000000000000000000000000..af39116fac01408ce1b33ab69260f95097ed6b63 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/napi_init.cpp @@ -0,0 +1,38 @@ +// entry/src/main/cpp/napi_init.cpp +#include "napi/native_api.h" +#include "NativeEntry.h" + +EXTERN_C_START +static napi_value Init(napi_env env, napi_value exports) { + // 绑定Native侧的创建组件和销毁组件。 + napi_property_descriptor desc[] = { + {"createNativeRoot", nullptr, NativeModule::CreateNativeRoot, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"createNodeTreeOnMultiThread", nullptr, NativeModule::CreateNodeTreeOnMultiThread, nullptr, nullptr, nullptr, + napi_default, nullptr}, + {"disposeNodeTreeOnMultiThread", nullptr, NativeModule::DisposeNodeTreeOnMultiThread, nullptr, nullptr, nullptr, + napi_default, nullptr}, + {"destroyNativeRoot", nullptr, NativeModule::DestroyNativeRoot, nullptr, nullptr, nullptr, napi_default, + nullptr}, + {"getContext", nullptr, NativeModule::GetContext, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"getNodeHandle", nullptr, NativeModule::GetNodeHandle, nullptr, nullptr, nullptr, napi_default, nullptr}, + {"getNodeHandleById", nullptr, NativeModule::GetNodeHandleById, nullptr, nullptr, nullptr, napi_default, + nullptr}, + {"getNodeHandleByUniqueId", nullptr, NativeModule::GetNodeHandleByUniqueId, 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 demoModule = { + .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(&demoModule); } \ No newline at end of file diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/types/libentry/Index.d.ts b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/types/libentry/Index.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..aff09736a83f77dd9f8e2af3fd596d998d8d2597 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/types/libentry/Index.d.ts @@ -0,0 +1,8 @@ +export const createNativeRoot: (content: Object) => void; +export const createNodeTreeOnMultiThread: (content: Object, context: Object) => void; +export const disposeNodeTreeOnMultiThread: (content: Object) => void; +export const getContext: (context: Object) => void; +export const getNodeHandle: (node: Object) => void; +export const getNodeHandleById: (id: Object) => void; +export const getNodeHandleByUniqueId: (uniqueId: Object) => void; +export const destroyNativeRoot: () => void; diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/types/libentry/oh-package.json5 b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/types/libentry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c69ca2198f11d3288b2ac61227a583604b647c78 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/cpp/types/libentry/oh-package.json5 @@ -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. + */ +{ + "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/ArkUIKit/NativeNodeUtilsSample/entry/src/main/ets/entryability/EntryAbility.ets b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..3b968bc6fc6e355d8abe166771fe100fb0a9bd56 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/ets/entryability/EntryAbility.ets @@ -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. + */ +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/entry', (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/ArkUIKit/NativeNodeUtilsSample/entry/src/main/ets/pages/entry.ets b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/ets/pages/entry.ets new file mode 100644 index 0000000000000000000000000000000000000000..ffb677347d436745f435447679a750cbf2e97bf9 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/ets/pages/entry.ets @@ -0,0 +1,53 @@ +import { NodeContent } from '@kit.ArkUI'; +import entry from 'libentry.so'; + +@Component +struct CAPIComponent { + private rootSlot = new NodeContent(); + + aboutToAppear(): void { + // 页面显示前多线程创建Native组件。 + entry.createNodeTreeOnMultiThread(this.rootSlot, this.getUIContext()) + } + + aboutToDisappear(): void { + // 页面销毁前释放已创建的Native组件。 + entry.disposeNodeTreeOnMultiThread(this.rootSlot) + } + + build() { + Column() { + // Native组件挂载点。 + ContentSlot(this.rootSlot) + } + } +} + +@Entry +@Component +struct Index { + @State isShow: boolean = false; + @State message: string = 'CreateNodeTree'; + + build() { + Flex() { + Column() { + Text('CreateNodeTreeOnMultiThread') + .fontSize(18) + .fontWeight(FontWeight.Bold) + Button(this.message) + .onClick(() => { + this.isShow = !this.isShow; + if (this.isShow) { + this.message = 'DisposeNodeTree' + } else { + this.message = 'CreateNodeTree' + } + }) + if (this.isShow) { + CAPIComponent() + } + }.width('100%') + }.width('100%') + } +} diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/main/module.json5 b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..78a72362efdf4ef6d9c8400b25527133d926dd45 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/module.json5 @@ -0,0 +1,65 @@ +/* + * 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": [ + "default", + "tablet" + ], + "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/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/element/color.json b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..d66f9a7d4ac61fb8d215239ab3620b7bcd77bf33 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/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/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/element/float.json b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/element/float.json new file mode 100644 index 0000000000000000000000000000000000000000..a8a5d404dcd8b0466194afc3aa25d90a8a327470 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/element/float.json @@ -0,0 +1,8 @@ +{ + "float": [ + { + "name": "page_text_font_size", + "value": "50fp" + } + ] +} diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/element/string.json b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..f94595515a99e0c828807e243494f57f09251930 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/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/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/media/background.png b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f Binary files /dev/null and b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/media/background.png differ diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/media/foreground.png b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..97014d3e10e5ff511409c378cd4255713aecd85f Binary files /dev/null and b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/media/foreground.png differ diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/media/layered_image.json b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/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/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/media/startIcon.png b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..be4105a540f934fd33ca9d03a5a33407f40eca5d Binary files /dev/null and b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/media/startIcon.png differ diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/media/startIcon2.png b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/media/startIcon2.png new file mode 100644 index 0000000000000000000000000000000000000000..24bd43eb05e4e5a8b35a3bc9651ec1abbef1ba68 Binary files /dev/null and b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/media/startIcon2.png differ diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/profile/backup_config.json b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000000000000000000000000000000000000..d742c2f96e7dd0f406f499941f3147345e998f95 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/profile/main_pages.json b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..676ebd21c666b6b9f69d210728def4cff68191ce --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,5 @@ +{ + "src": [ + "pages/entry" + ] +} diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/dark/element/color.json b/ArkUIKit/NativeNodeUtilsSample/entry/src/main/resources/dark/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..438d5bc43bb23c59c210d586b96635a72da5b64a --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/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/ArkUIKit/NativeNodeUtilsSample/entry/src/mock/Libentry.mock.ets b/ArkUIKit/NativeNodeUtilsSample/entry/src/mock/Libentry.mock.ets new file mode 100644 index 0000000000000000000000000000000000000000..82fa70b5693ddab96d237d2d17d943d866b61465 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/mock/Libentry.mock.ets @@ -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. + */ +const NativeMock: Record = { + 'add': (a: number, b: number) => { + return a + b; + }, +}; + +export default NativeMock; \ No newline at end of file diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/mock/mock-config.json5 b/ArkUIKit/NativeNodeUtilsSample/entry/src/mock/mock-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..98b0ae79f0090e1fc381d54c959fb32c9f7563f4 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/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/ArkUIKit/NativeNodeUtilsSample/entry/src/ohosTest/ets/test/Ability.test.ets b/ArkUIKit/NativeNodeUtilsSample/entry/src/ohosTest/ets/test/Ability.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..7f30942b81554a399e89aa253c7089eca4f8d8d1 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/ohosTest/ets/test/Ability.test.ets @@ -0,0 +1,49 @@ +/* + * 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 { 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/ArkUIKit/NativeNodeUtilsSample/entry/src/ohosTest/ets/test/List.test.ets b/ArkUIKit/NativeNodeUtilsSample/entry/src/ohosTest/ets/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..c64e0b06938d246ce044186d4b2d02b500a89e14 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/ohosTest/ets/test/List.test.ets @@ -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. + */ +import abilityTest from './Ability.test'; + +export default function testsuite() { + abilityTest(); +} \ No newline at end of file diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/ohosTest/module.json5 b/ArkUIKit/NativeNodeUtilsSample/entry/src/ohosTest/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..15985f07ded51de709b7c68483df86e9071ade0b --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/ohosTest/module.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. + */ +{ + "module": { + "name": "entry_test", + "type": "feature", + "deviceTypes": [ + "default", + "tablet" + ], + "deliveryWithInstall": true, + "installationFree": false + } +} diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/test/List.test.ets b/ArkUIKit/NativeNodeUtilsSample/entry/src/test/List.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..a60c87c5cbb0badf7c3fd8975034590e6fafa992 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/test/List.test.ets @@ -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. + */ +import localUnitTest from './LocalUnit.test'; + +export default function testsuite() { + localUnitTest(); +} \ No newline at end of file diff --git a/ArkUIKit/NativeNodeUtilsSample/entry/src/test/LocalUnit.test.ets b/ArkUIKit/NativeNodeUtilsSample/entry/src/test/LocalUnit.test.ets new file mode 100644 index 0000000000000000000000000000000000000000..841bfd77e56060e50ec0924302a5ae624e76e3aa --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/entry/src/test/LocalUnit.test.ets @@ -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. + */ +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/ArkUIKit/NativeNodeUtilsSample/hvigor/hvigor-config.json5 b/ArkUIKit/NativeNodeUtilsSample/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..70879912169503ff02665211233887556b8f4ae8 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/hvigor/hvigor-config.json5 @@ -0,0 +1,36 @@ +/* + * 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/ArkUIKit/NativeNodeUtilsSample/hvigorfile.ts b/ArkUIKit/NativeNodeUtilsSample/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..ae9086af35844176c08f1be3772d081d95d267c6 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/hvigorfile.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 { 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/ArkUIKit/NativeNodeUtilsSample/oh-package.json5 b/ArkUIKit/NativeNodeUtilsSample/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..463ba600e57f685bdc2b1d5a759cd939fe9f1762 --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/oh-package.json5 @@ -0,0 +1,24 @@ +/* + * 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" + } +} diff --git a/ArkUIKit/NativeNodeUtilsSample/ohosTest.md b/ArkUIKit/NativeNodeUtilsSample/ohosTest.md new file mode 100644 index 0000000000000000000000000000000000000000..94ba776ab3b8074712192f808f480ef035fa0ebd --- /dev/null +++ b/ArkUIKit/NativeNodeUtilsSample/ohosTest.md @@ -0,0 +1,7 @@ +# NativeNodeSample 测试用例归档 + +## 用例表 + +| 测试功能 | 预置条件 | 输入 | 预期输出 | 是否自动 | 测试结果 | +| ------------------- | -------------- | ----------------------- | ------------------------------------------------------------ | :------- | -------- | +| 示例代码验证 | 设备正常运行 | 输入a、b的值 | 符合预期 | 是 | Pass |