首页 » 网站推广 » phpjsiframe技巧_鸿蒙跨端实践ArkTS和CAPI的混淆开拓实现

phpjsiframe技巧_鸿蒙跨端实践ArkTS和CAPI的混淆开拓实现

访客 2024-12-13 0

扫一扫用手机浏览

文章目录 [+]



2. 通讯流程长

在实现鸿蒙跨端方案中,JS虚拟机(V8)运行JS代码,通过JSI打通C++,再通过华为NAPI从C++打通ArkTS,跨措辞通讯本钱高。

phpjsiframe技巧_鸿蒙跨端实践ArkTS和CAPI的混淆开拓实现



phpjsiframe技巧_鸿蒙跨端实践ArkTS和CAPI的混淆开拓实现
(图片来自网络侵删)
3. 列表渲染性能差

长列表渲染性能是iOS、Android、Harmony系统非常主要的指标,华为也一贯在推出多种方案以提升列表渲染性能。
但在业界所有三方框架渲染长列表繁芜业务场景(例如社区频道页面)时,在ArkUI层因设计事理导致性能问题一贯无法完美办理。



4、二次布局

在对接到鸿蒙系统组件后,由于设置了干系布局属性后,系统会进行二次布局。

二、新方案实践1.问题阐发

UI层级过多:缘故原由在于在鸿蒙系统利用系统组件进行递归渲染的时候,须要借助自定义组件进行实现,然而和iOS和Android真个命令式组件渲染不同,比如RomaDiv对应iOS便是直接翻译为UIView即可,在鸿蒙必须增加一个包裹的容器才是一个合法的自定义组件,比如Stack容器,这样每个组件的层级就多了一层。

@Componentexport struct RomaDiv { build(){ Stack(){ //借助wrapBuilder实现递归 ForEach(this.childrenTags, (childrenTag) => { RomaComponentFactory.builder()//RomaComponentFactory便是对应鸿蒙系统供应的WrappedBuilder }) } }}

通讯流程长:js代码运行在系统内置的V8虚拟机中,ArkTS代码运行在华为的方舟虚拟机中,再加上V8运行js的线程,C++解析js指令的线程以及ArkTS的主线程,跨线程开销耗时增加,以及各个措辞间的数据类型转换,通讯本钱一定会非常高。

列表渲染性能差:鸿蒙的相应式编程,底层类似于vue做了依赖网络,虽然长列表场景下华为供应了cacheCount机制以提升列表渲染性能,但当数据发生变革的时候,数据的递归剖析以及不在屏幕的的节点属性设置直接导致了列表性能的大幅低落。

二次布局:动态化在鸿蒙系统的跨端已经集成了其余两端共同利用的Yoga布局库,其实在给华为系统组件设置属性和坐标之前已经做好告终构打算,但是华为系统并未感知和处理这个过程,以是会存在二次布局的问题。

2.新方案简介

针对以上问题,通过和华为沟通,鸿蒙系统供应了C措辞的命令式接口。
C组件接口是介于UI组件的Native实现和ArkTS对接层之间的一层C接口封装,它绕过了状态管理对组件变革、刷新的自动化管理,同时避免了JS引擎和C++之间类型转换和跨措辞调用的开销,因此具有较好的性能。

通过C接口的对接,UI层级能直接和其余两端基本同等,通讯过程直接从JS到C++,C++可以直接调用C接口,流程大大缩短,数据类型转换变少了,列表渲染过程也由接入方自主掌握,并且可以做预渲染等优化方案,同时避免了系统的二次布局。



3.如何利用

在实际的动态化鸿蒙跨端中,会存在ArkTS组件和C组件嵌套的场景(对付一些对性能影响较小的组件许可利用ArkTS),下面我们实现一个比较繁芜的嵌套Demo,以展示全体嵌套实现过程。
包含了ArkTS组件插入C组件、ArkTS组件插入ArkTS组件、C组件插入C组件、C组件插入ArkTS组件等场景。



3.1、ArkTS插入C组件示例

ArkTS组件插入C组件的紧张过程分为三步:

1、NodeContent管理器创建

2、build函数中的ContentSlot占位组件

3、NodeContent节点创建(CAPI)

import entry from 'libentry.so'; import { NodeContent } from '@ohos.arkui.node'@Entry@Componentstruct CMixArkTS{ //1、NodeContent管理器创建 private divNodeContent: NodeContent = new NodeContent(); }build(){ //2、build函数中的ContentSlot占位组件 ContentSlot(this.divNodeContent);}aboutToAppear(): void { //3、NodeContent节点创建(CAPI) entry.CreateNativeDivNode(this.divNodeContent);}

CreateNativeDivNode在C++中的实现如下:

此处有个坑:ArkUI_NativeNodeAPI_1 nodeAPI 如果按照官方文档代码创建会失落败,精确的方法如下代码所示。
由于利用到ArkUI_NativeNodeAPI_1的地方比较多,以是我把ArkUI_NativeNodeAPI_1封装到CAPIManager::getNodeAPI()方法中了。

这个过程的核心API为OH_ArkUI_NodeContent_AddNode(nodeContentHandle_, DivComponent); 第一个参数指向ArkTS侧传入的nodeContent,第二个参数便是利用CAPI创建的Div节点。

// 1、C组件-绿色边框static napi_value CreateNativeDivNode(napi_env env, napi_callback_info info) { // napi干系处理空指针&数据越界等问题 if ((env == nullptr) || (info == nullptr)) { return nullptr; } napi_value returnVal = nullptr; size_t argc = 1; napi_value args[1] = {nullptr}; if (napi_get_cb_info(env, info, &argc, args, nullptr, nullptr) != napi_ok) { OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "napi_init", "CreateNativeNode napi_get_cb_info failed"); } if (argc != 1) { return nullptr; } // 将nodeContentHandle_指向ArkTS侧传入的nodeContent // 在Native侧获取ArkTS侧Content指针。
OH_ArkUI_GetNodeContentFromNapiValue(env, args[0], &nodeContentHandle_); // nodeAPI = reinterpret_cast<ArkUI_NativeNodeAPI_1 >(OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, // "ArkUI_NativeNode_API_1")); 上面写法弗成,必须如下写法...... // ArkUI_NativeNodeAPI_1 声明 ArkUI 供应的原生节点 API 凑集。
与原生节点干系的 API 必须在主线程中调用。
// 包括创建节点、添加、删除节点,给节点设置各种属性样式等 static ArkUI_NativeNodeAPI_1 nodeAPI = nullptr; if (nodeAPI == nullptr) { nodeAPI = reinterpret_cast<ArkUI_NativeNodeAPI_1 >( OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1")); } if (nodeAPI != nullptr) { if (nodeAPI->createNode != nullptr && nodeAPI->addChild != nullptr) { ArkUI_NodeHandle DivComponent; // 创建div节点 DivComponent = CreateDivNodeHandle(); // nodeContentHandle_指向ArkTS侧传入的nodeContent,nodeContent上div节点 OH_ArkUI_NodeContent_AddNode(nodeContentHandle_, DivComponent); } } return returnVal;}static ArkUI_NodeHandle CreateDivNodeHandle() { ArkUI_NodeHandle greenDivNodeHandle; // 创建div的node greenDivNodeHandle = CreateDivNodeHandleWithParam(200, 0xFF00FF00); CAPIManager::GetInstance()->greenDivNodeHandle = greenDivNodeHandle; return greenDivNodeHandle;}static napi_value Init(napi_env env, napi_value exports){ { "CreateNativeDivNode", nullptr, CreateNativeDivNode, nullptr, nullptr, nullptr, napi_default, nullptr},}

真正的C组件创建:

static ArkUI_NodeHandle CreateDivNodeHandleWithParam(float height, uint32_t borderColor) { ArkUI_NodeHandle divNode = CAPIManager::getNodeAPI()->createNode(ArkUI_NodeType::ARKUI_NODE_FLEX); // margin ArkUI_NumberValue number = {.f32 = 5}; ArkUI_AttributeItem marginValue = { .value = &number, // 初始化为NULL或者指向你的数字数组 .size = 1, // 初始化为你的数字数组的大小 .string = NULL, // 初始化为NULL或者指向你的字符串 .object = NULL // 初始化为NULL或者指向你的工具 }; // borderWidth ArkUI_NumberValue number2 = {.f32 = 2}; ArkUI_AttributeItem borderWValue = { .value = &number2, // 初始化为NULL或者指向你的数字数组 .size = 1, // 初始化为你的数字数组的大小 .string = NULL, // 初始化为NULL或者指向你的字符串 .object = NULL // 初始化为NULL或者指向你的工具 }; // 背景色 ArkUI_NumberValue number1 = {.u32 = borderColor}; ArkUI_AttributeItem borderColorItem = { .value = &number1, // 初始化为NULL或者指向你的数字数组 .size = 1, // 初始化为你的数字数组的大小 .string = NULL, // 初始化为NULL或者指向你的字符串 .object = NULL // 初始化为NULL或者指向你的工具 }; // 宽高 ArkUI_NumberValue number3 = {.f32 = height}; ArkUI_AttributeItem hValue = { .value = &number3, // 初始化为NULL或者指向你的数字数组 .size = 1, // 初始化为你的数字数组的大小 .string = NULL, // 初始化为NULL或者指向你的字符串 .object = NULL // 初始化为NULL或者指向你的工具 }; ArkUI_NumberValue number5 = {.f32 = 0.9}; ArkUI_AttributeItem wValue = { .value = &number5, // 初始化为NULL或者指向你的数字数组 .size = 1, // 初始化为你的数字数组的大小 .string = NULL, // 初始化为NULL或者指向你的字符串 .object = NULL // 初始化为NULL或者指向你的工具 }; ArkUI_NumberValue number4 = {.i32 = ARKUI_ITEM_ALIGNMENT_CENTER}; ArkUI_AttributeItem alignment = { .value = &number4, // 初始化为NULL或者指向你的数字数组 .size = 1, // 初始化为你的数字数组的大小 .string = NULL, // 初始化为NULL或者指向你的字符串 .object = NULL // 初始化为NULL或者指向你的工具 }; // 属性设置 CAPIManager::getNodeAPI()->setAttribute(divNode, NODE_MARGIN, &marginValue); CAPIManager::getNodeAPI()->setAttribute(divNode, NODE_BORDER_WIDTH, &borderWValue); CAPIManager::getNodeAPI()->setAttribute(divNode, NODE_BORDER_COLOR, &borderColorItem); CAPIManager::getNodeAPI()->setAttribute(divNode, NODE_WIDTH_PERCENT, &wValue); CAPIManager::getNodeAPI()->setAttribute(divNode, NODE_HEIGHT, &hValue); CAPIManager::getNodeAPI()->setAttribute(divNode, NODE_ALIGN_SELF, &alignment); return divNode;}

通过以长进程可以创造,通过CAPI创建一个节点并渲染的过程还是比较繁芜的,但只要捉住实现过程的核心步骤,剩下的便是按照文档开拓就行了。

大家感想熏染下iOS实现这个过程的仿照:

- (UIView ) CreateNativeDivNode{ UIView div = [UIView new]; div.backGroundColor = [UIColor greenColor]; div.frame = CGRectMake(0,0,width,height); return div;}

虽然过程有点繁芜,但是效果还是不错的,毕竟能办理文章开头提出的4个问题。
比如最直不雅观的UI层级,Text26(I am A ArkTS Node)的深度已经和其他两端能对齐了。



3.2、其他场景实现

从上面ArkTS组件插入C组件一个过程实现能看到,代码量还是比较惊人的,其他场景的实现读者可以参考官方文档进行考试测验。

标签:

相关文章