• Lv0
    粉丝20

积分1156 / 贡献0

提问0答案被采纳63文章8

[经验分享] Native API应用开发 之 使用NDK接口构建UI 原创 精华

马迪 显示全部楼层 发表于 2024-7-30 19:58:30

背景

目前,OpenHarmony/HarmonyOS Next的主要UI开源三方库,如lottie,imageknife,pulltorefresh都是使用arkts自定义组件开发的。但越来越多应用除了功能对功能的要求外,现在也开始提出性能的要求。所以被迫得提前研究下使用NDK接口构建开源三方库。 ArkUI开发框架提供了一系列NDK接口,能够在应用中使用C和C++代码构建UI界面,这些接口包括UI组件创建、UI树操作、属性设置和事件监听等。在OpenHarmony 5.0文档中,我找到了如何使用NDK接入ArkTS页面,如何使用NDK构建自定义组件。 通过参考上述文档,我大概了解了如何在ArkTS页面嵌入一个NDK接口实现的自定义组件,并嵌入了一个系统Image组件。 具体效果如下,可以看到使用ndk可以实现与arkTS库一样的Image系统组件,加载网络图片:

200732lq85ssk7v8zkq8bb.png

代码实现

1.使用NDK自定义组件,内部嵌入一个Image组件,并提供设置url的方法:

#include "ArkUINode.h"

namespace NativeModule {

class CustomImageNode : public ArkUINode {
public:
    // 使用自定义组件类型ARKUI_NODE_IMAGE创建组件。
    CustomImageNode()
        : ArkUINode((NativeModuleInstance::GetInstance()->GetNativeNodeAPI())->createNode(ARKUI_NODE_IMAGE)) {
    }

    ~CustomImageNode() override {
    }

    // 设置图片地址
    void SetImageUrl(const char* url) {
        ArkUI_AttributeItem item = { .string = url};
       NativeModuleInstance::GetInstance()->GetNativeNodeAPI()->setAttribute(this->handle_, NODE_IMAGE_SRC , &item);
    }
};

} // namespace NativeModule

2.实现napi方法,对arkTS暴露创建ndk组件createNativeRoot和销毁ndk组件destroyNativeRoot的方法

namespace NativeModule {

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 customNode = std::make_shared<CustomImageNode>();
    customNode->SetImageUrl("http://h.hiphotos.baidu.com/image/pic/item/902397dda144ad340668b847d4a20cf430ad851e.jpg");
    customNode->SetWidth(200);
    customNode->SetHeight(200);

    // 保持Native侧对象到管理类中,维护生命周期。
    NativeEntry::GetInstance()->SetRootNode(customNode);
    return nullptr;
}

napi_value DestroyNativeRoot(napi_env env, napi_callback_info info) {
    // 从管理类中释放Native侧对象。
    NativeEntry::GetInstance()->DisposeRootNode();
    return nullptr;
}

} // namespace NativeModule


EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports) {
    napi_property_descriptor desc[] = {
        {"createNativeRoot", nullptr, NativeModule::CreateNativeRoot, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"destroyNativeRoot", nullptr, NativeModule::DestroyNativeRoot, nullptr, nullptr, nullptr, napi_default,
         nullptr}};
    napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
    return exports;
}
EXTERN_C_END

3.inded.d.ts声明createNativeRoot和destroyNativeRoot方法

export const createNativeRoot: (content: Object) => void;
export const destroyNativeRoot: () => void;

4.ArkTS嵌入组件,在aboutToAppear里加载,在aboutToDisappear里卸载

import nativeNode from 'libentry.so';
import { NodeContent } from '@ohos.arkui.node';

@Entry
@Component
struct Index {
  private rootSlot = new NodeContent();

  aboutToAppear(): void {
    // 传递NodeContent对象用于Native创建组件的挂载显示
    nativeNode.createNativeRoot(this.rootSlot)
  }

  aboutToDisappear(): void {
    // 销毁NativeModule组件
    nativeNode.destroyNativeRoot()
  }

  build() {
    Column() {
      Text("ArkTs组件").fontSize(30)
      Image("http://h.hiphotos.baidu.com/image/pic/item/902397dda144ad340668b847d4a20cf430ad851e.jpg").width(200).height(200)

      Blank().height(100)
      Text("NDK组件").fontSize(300)
      // 将NodeContent和ContentSlot占位组件绑定。
      ContentSlot(this.rootSlot)

    }
    .width('100%')
    .height('100%')
  }
}

5.CMakeLists增加对libace_ndk.z.so的链接

target_link_libraries(entry PUBLIC libace_napi.z.so libace_ndk.z.so)

【完整demo参考】 https://gitee.com/MaDiXin/ndksample 欢迎交流与探讨

©著作权归作者所有,转载或内容合作请联系作者

您尚未登录,无法参与评论,登录后可以:
参与开源共建问题交流
认同或收藏高质量问答
获取积分成为开源共建先驱

Copyright   ©2023  OpenHarmony开发者论坛  京ICP备2020036654号-3 |技术支持 Discuz!

返回顶部