diff --git a/NativeAPI/NativeTemplateDemo/README.md b/NativeAPI/NativeTemplateDemo/README.md index bfb012bf57cd83ce103cc9f01362c824bec31499..4ebfb5dea1e280dad836e455f45a1dd25a29ebab 100644 --- a/NativeAPI/NativeTemplateDemo/README.md +++ b/NativeAPI/NativeTemplateDemo/README.md @@ -2,13 +2,13 @@ ## 介绍 -本篇Codelab主要介绍如何使用DevEco Studio创建一个Native C++应用。应用采用Native C++模板,实现使用Native API调用C标准库的功能。使用C标准库hypot接口计算两个给定数平方和的平方根。在输入框中输入两个数字,点击计算结果按钮显示计算后的数值。 +本篇Codelab主要介绍如何使用DevEco Studio创建一个Native C++应用。应用采用Native C++模板,实现使用NAPI调用C标准库的功能。使用C标准库hypot接口计算两个给定数平方和的平方根。在输入框中输入两个数字,点击计算结果按钮显示计算后的数值。 ![](./figures/zh-cn_image_0000001570142635.gif) ### 相关概念 -- [Native API](https://gitee.com/openharmony/docs/blob/OpenHarmony-3.2-Release/zh-cn/application-dev/napi/napi-guidelines.md):Native API提供的接口名与三方Node.js一致,目前支持部分接口。 +- [Native API](https://gitee.com/openharmony/docs/blob/OpenHarmony-3.2-Release/zh-cn/application-dev/napi/napi-guidelines.md):NAPI提供的接口名与三方Node.js一致,目前支持部分接口。 - [Native API中支持的标准库](https://gitee.com/openharmony/docs/blob/OpenHarmony-3.2-Release/zh-cn/application-dev/reference/native-lib/third_party_libc/musl.md):目前支持标准C库、C++库、OpenSL ES、zlib。 ## 环境搭建 @@ -46,6 +46,8 @@ 本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 +使用Native C++模板创建项目会自动生成cpp文件夹、types文件夹、CMakeList.txt文件,开发者可以根据实际情况自行添加修改其他文件及文件夹。 + ``` ├──entry/src/main │ ├──common @@ -75,9 +77,9 @@ - ArkTS:包含界面UI、自身方法、调用引用包的方法等。 - 工具链:包含CMake编译工具在内的系列工具。 -使用ArkTS调用C++方法的过程中,需要使用到Native API、CMake等工具来做中间转换,整个架构及其关联关系参考示意图。 +使用ArkTS调用C++方法的过程中,需要使用到NAPI、CMake等工具来做中间转换,整个架构及其关联关系参考示意图。 -示意图中,hello.cpp文件实现C++方法,并通过Native API将C++方法与ArkTS方法关联。 +示意图中,hello.cpp文件实现C++方法,并通过NAPI将C++方法与ArkTS方法关联。 C++代码通过CMake编译工具编译成动态链接库so文件,使用index.d.ts文件对外提供接口。ArkTS引入so文件后调用其中的接口。 @@ -93,124 +95,157 @@ ArkTS与C++方法的调用、编译流程参考示意图。图中C++代码通过 ### Native侧操作详解 -1. 配置模块描述信息,设置Init方法为napi\_module的入口方法。\_\_attribute\_\_\(\(constructor\)\)修饰的方法由系统自动调用,使用Native API接口napi\_module\_register\(\)传入模块描述信息进行模块注册。 - - ``` cpp - // hello.cpp - static napi_module demoModule = { - nm_version = 1, - nm_flags = 0, - nm_filename = nullptr, - nm_register_func = Init, // napi_module入口方法 - nm_modname = "hello", // napi_module模块名 - nm_priv = ((void *)0), - reserved = { 0 } - }; - - extern "C" __attribute__((constructor)) void RegisterModule(void) { - napi_module_register(&demoModule); - } - ``` - -2. 关联C++方法至ArkTS。在napi\_property\_descriptor desc\[\]中,我们需要将编写的MyHypot方法与对外提供的接口myHypot接口进行关联,其他参数使用示例默认值填写。使用Native API接口napi\_define\_properties构建包含方法对应列表的返回值。 - - ``` cpp - // hello.cpp - EXTERN_C_START - static napi_value Init(napi_env env, napi_value exports) { - napi_property_descriptor desc[] = { - { "myHypot", nullptr, MyHypot, nullptr, nullptr, nullptr, napi_default, nullptr } - }; - napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); - return exports; - } - EXTERN_C_END - ``` - -3. 实现C++方法。本例中使用C标准库的hypot方法进行计算。引入C标准库头文件math.h,使用double类型解析传入的参数后,调用C标准库方法hypot计算两数平方的和后计算平方根。使用Native API接口napi\_create\_double将结果转化为napi\_value类型的变量并返回。 - - ``` cpp - // hello.cpp - #include "napi/native_api.h" - #include "math.h" - static napi_value MyHypot(napi_env env, napi_callback_info info) { - // 参数数量 - size_t argc = 2; - - // 声明参数数组 - napi_value args[2] = {nullptr}; - - // 获取传入的参数并依次放入参数数组中 - napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); - - // 将第一个传入参数转化为double类型 - double value0; - napi_get_value_double(env, args[0], &value0); - - // 将第二个传入参数转化为double类型 - double value1; - napi_get_value_double(env, args[1], &value1); - - // 调用C标准库的hypot接口进行计算 - double result = hypot(value0, value1); - napi_value sum; - napi_create_double(env, result, &sum); - return sum; - } - ``` - -4. 添加接口文件以及接口配置文件。接口文件index.d.ts用于对外提供方法说明。接口配置文件oh-package.json5文件中将index.d.ts与CMake编译的so文件关联起来。模块级目录下oh-package.json5文件添加so文件依赖。 - - ```typescript - // index.d.ts - export const myHypot: (a: number, b: number) => number; - ``` - ```json - // oh-package.json5 - { - "name": "libhello.so", - "types": "./index.d.ts" - } - - // entry/oh-package.json5 - { - "devDependencies": { - "@types/libhello.so": "file:./src/main/cpp/types/libhello" - } - } - ``` - -5. 在CMakeLists.txt文件中配置CMake编译参数。配置需要添加的hello.cpp文件,编译后的so文件名为libhello.so。CMakeLists.txt是CMake编译的配置文件,里面的大部分内容无需修改,project、add\_library方法中的内容可以根据实际情况修改。 - - ```cmake - # CMakeLists.txt - # 声明使用 CMAKE 的最小版本号 - cmake_minimum_required(VERSION 3.4.1) - - # 配置项目信息 - project(NativeTemplateDemo) - - # set命令,格式为set(key value),表示设置key的值为value - set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) - - # 设置头文件的搜索目录 - include_directories( - ${NATIVERENDER_ROOT_PATH} - ${NATIVERENDER_ROOT_PATH}/include - ) - - # 添加名为hello的库,库文件名为libhello.so - add_library(hello SHARED hello.cpp) - - # 添加构建需要链接的库 - target_link_libraries(hello PUBLIC libace_napi.z.so libc++.a) - ``` - - >![](public_sys-resources/icon-note.gif) **说明:** - > - >- CMAKE\_CURRENT\_SOURCE\_DIR:CMakeList.txt文件所在的目录。 - >- add\_library:添加本地的cpp文件,多cpp文件使用空格或换行间隔。 - >- target\_link\_libraries:添加需要链接的库,本篇Codelab使用C标准库hypot方法,此处链接libc++.a库文件。 +1. 配置模块描述信息,设置Init方法为napi\_module的入口方法。\_\_attribute\_\_\(\(constructor\)\)修饰的方法由系统自动调用,使用NAPI接口napi\_module\_register\(\)传入模块描述信息进行模块注册。Native C++模板创建项目会自动生成此结代码,开发者可根据实际情况修改其中内容。 + + ```cpp + // hello.cpp + static napi_module demoModule = { + nm_version = 1, + nm_flags = 0, + nm_filename = nullptr, + nm_register_func = Init, // napi_module入口方法 + nm_modname = "hello", // napi_module模块名 + nm_priv = ((void *)0), + reserved = { 0 } + }; + + extern "C" __attribute__((constructor)) void RegisterModule(void) { + napi_module_register(&demoModule); + } + ``` + +2. Init方法为Native C++模板生成的结构,开发者可根据实际情况修改其中内容。在napi\_property\_descriptor desc\[\]中,我们需要将编写的MyHypot方法与对外提供的接口myHypot接口进行关联,其他参数使用示例默认值填写。使用NAPI接口napi\_define\_properties构建包含方法对应列表的返回值。 + + ```cpp + // hello.cpp + static napi_value Init(napi_env env, napi_value exports) + { + if ((nullptr == env) || (nullptr == exports)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Init", "env or exports is null"); + return exports; + } + + napi_property_descriptor desc[] = { + { "myHypot", nullptr, MyHypot, nullptr, nullptr, nullptr, napi_default, nullptr } + }; + if (napi_ok != napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Init", "napi_define_properties failed"); + return nullptr; + } + return exports; + } + ``` + +3. 本例中使用C标准库的hypot方法进行计算。引入C标准库头文件math.h,使用double类型解析传入的参数后,调用C标准库方法hypot计算两数平方的和后计算平方根。使用NAPI接口napi\_create\_double将结果转化为napi\_value类型的变量并返回。 + + ```cpp + // hello.cpp + #include + #include "napi/native_api.h" + #include "math.h" + + static napi_value MyHypot(napi_env env, napi_callback_info info) + { + if ((nullptr == env) || (nullptr == info)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "MyHypot", "env or exports is null"); + return nullptr; + } + + // 参数数量 + size_t argc = PARAMETER_COUNT; + + // 定义参数数组 + napi_value args[PARAMETER_COUNT] = { nullptr }; + + // 获取传入的参数并放入参数数组中 + if (napi_ok != napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "MyHypot", "api_get_cb_info failed"); + return nullptr; + } + + // 将传入的参数转化为double类型 + double valueX = 0.0; + double valueY = 0.0; + if (napi_ok != napi_get_value_double(env, args[0], &valueX) || + napi_ok != napi_get_value_double(env, args[1], &valueY)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "MyHypot", "napi_get_value_double failed"); + return nullptr; + } + + // 调用C标准库的hypot接口进行计算 + double result = hypot(valueX, valueY); + + // 创建返回结果并返回 + napi_value napiResult; + if (napi_ok != napi_create_double(env, result, &napiResult)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "MyHypot", "napi_create_double failed"); + return nullptr; + } + return napiResult; + } + ``` + +4. 添加接口文件以及接口配置文件。接口文件index.d.ts用于对外提供方法说明。接口配置文件oh-package.json5文件中将index.d.ts与CMake编译的so文件关联起来。模块级目录下oh-package.json5文件添加so文件依赖。 + + ```typescript + // index.d.ts + export const myHypot: (a: number, b: number) => number; + ``` + ```json + // oh-package.json5 + { + "name": "libhello.so", + "types": "./index.d.ts" + } + + // entry/oh-package.json5 + { + "devDependencies": { + "@types/libhello.so": "file:./src/main/cpp/types/libhello" + } + } + ``` + +5. 在CMakeLists.txt文件中配置CMake编译参数。配置需要添加的hello.cpp文件,编译后的so文件名为libhello.so。CMakeLists.txt是CMake编译的配置文件,里面的大部分内容无需修改,project、add\_library方法中的内容可以根据实际情况修改。 + + ```cmake + # CMakeLists.txt + # 声明使用 CMAKE 的最小版本号 + cmake_minimum_required(VERSION 3.4.1) + + # 配置项目信息 + project(NativeTemplateDemo) + + # set命令,格式为set(key value),表示设置key的值为value + set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) + + # 设置头文件的搜索目录 + include_directories( + ${NATIVERENDER_ROOT_PATH} + ${NATIVERENDER_ROOT_PATH}/include + ) + + # 添加日志库 + find_library( + # Sets the name of the path variable. + hilog-lib + # Specifies the name of the NDK library that + # you want CMake to locate. + hilog_ndk.z + ) + + # 添加名为hello的库,库文件名为libhello.so + add_library(hello SHARED hello.cpp) + + # 添加构建需要链接的库 + target_link_libraries(hello PUBLIC ${hilog-lib} libace_napi.z.so libc++.a) + ``` + + >![](public_sys-resources/icon-note.gif) **说明:** + >- CMAKE\_CURRENT\_SOURCE\_DIR:CMakeList.txt文件所在的目录。 + >- add\_library:添加本地的cpp文件,多cpp文件使用空格或换行间隔。 + >- target\_link\_libraries:添加需要链接的库,本篇Codelab使用C标准库hypot方法,此处链接libc++.a库文件。 + ### ArkTS调用C++方法 diff --git a/NativeAPI/NativeTemplateDemo/entry/src/main/cpp/CMakeLists.txt b/NativeAPI/NativeTemplateDemo/entry/src/main/cpp/CMakeLists.txt index 7b2d83d1f39ebe747230dc256625f40995241963..ff9417c2570699ef6436320027c0a5471fc6b0bc 100644 --- a/NativeAPI/NativeTemplateDemo/entry/src/main/cpp/CMakeLists.txt +++ b/NativeAPI/NativeTemplateDemo/entry/src/main/cpp/CMakeLists.txt @@ -9,5 +9,13 @@ include_directories( ${NATIVERENDER_ROOT_PATH}/include ) +find_library( + # Sets the name of the path variable. + hilog-lib + # Specifies the name of the NDK library that + # you want CMake to locate. + hilog_ndk.z +) + add_library(hello SHARED hello.cpp) -target_link_libraries(hello PUBLIC libace_napi.z.so libc++.a) \ No newline at end of file +target_link_libraries(hello PUBLIC ${hilog-lib} libace_napi.z.so libc++.a) \ No newline at end of file diff --git a/NativeAPI/NativeTemplateDemo/entry/src/main/cpp/common/common.h b/NativeAPI/NativeTemplateDemo/entry/src/main/cpp/common/common.h new file mode 100644 index 0000000000000000000000000000000000000000..a389f5ae1213e90780254fec575ae07d4b0d37bf --- /dev/null +++ b/NativeAPI/NativeTemplateDemo/entry/src/main/cpp/common/common.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NativeTemplateDemo_common_H +#define NativeTemplateDemo_common_H + +// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found, +// please include "napi/native_api.h". +#include + +/** + * Parameter count. + */ +const int PARAMETER_COUNT = 2; + +/** + * Log print domain. + */ +const unsigned int LOG_PRINT_DOMAIN = 0xFF00; + + +#endif // NativeTemplateDemo_common_H diff --git a/NativeAPI/NativeTemplateDemo/entry/src/main/cpp/hello.cpp b/NativeAPI/NativeTemplateDemo/entry/src/main/cpp/hello.cpp index 02bf028b42076bf51753db16ccc4c2ba3c449034..7efdbc9783c03e0184ca6d562b90356e0deabe5d 100644 --- a/NativeAPI/NativeTemplateDemo/entry/src/main/cpp/hello.cpp +++ b/NativeAPI/NativeTemplateDemo/entry/src/main/cpp/hello.cpp @@ -12,41 +12,65 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include #include "napi/native_api.h" #include "math.h" +#include "./common/common.h" + +static napi_value MyHypot(napi_env env, napi_callback_info info) +{ + if ((nullptr == env) || (nullptr == info)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "MyHypot", "env or exports is null"); + return nullptr; + } -static napi_value MyHypot(napi_env env, napi_callback_info info) { // Number of parameters. - size_t argc = 2; + size_t argc = PARAMETER_COUNT; // Declare parameter array. - napi_value args[2] = {nullptr}; + napi_value args[PARAMETER_COUNT] = { nullptr }; // Gets the arguments passed in and puts them in the argument array. - napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); - - // Converts the first argument passed in to type double. - double value0; - napi_get_value_double(env, args[0], &value0); + if (napi_ok != napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "MyHypot", "api_get_cb_info failed"); + return nullptr; + } - // Converts the second argument passed in to type double. - double value1; - napi_get_value_double(env, args[1], &value1); + // Converts arguments passed in to type double. + double valueX = 0.0; + double valueY = 0.0; + if (napi_ok != napi_get_value_double(env, args[0], &valueX) || + napi_ok != napi_get_value_double(env, args[1], &valueY)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "MyHypot", "napi_get_value_double failed"); + return nullptr; + } // The hypot method of the C standard library is called to perform the calculation. - double result = hypot(value0, value1); + double result = hypot(valueX, valueY); - napi_value sum; - napi_create_double(env, result, &sum); - return sum; + napi_value napiResult; + if (napi_ok != napi_create_double(env, result, &napiResult)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "MyHypot", "napi_create_double failed"); + return nullptr; + } + return napiResult; } EXTERN_C_START -static napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) +{ + if ((nullptr == env) || (nullptr == exports)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Init", "env or exports is null"); + return exports; + } + napi_property_descriptor desc[] = { - {"myHypot", nullptr, MyHypot, nullptr, nullptr, nullptr, napi_default, nullptr} + { "myHypot", nullptr, MyHypot, nullptr, nullptr, nullptr, napi_default, nullptr } }; - napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + if (napi_ok != napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Init", "napi_define_properties failed"); + return nullptr; + } return exports; } EXTERN_C_END @@ -58,9 +82,10 @@ static napi_module demoModule = { .nm_register_func = Init, .nm_modname = "hello", .nm_priv = ((void *)0), - .reserved = {0} + .reserved = { 0 } }; -extern "C" __attribute__((constructor)) void RegisterModule(void) { +extern "C" __attribute__((constructor)) void RegisterModule(void) +{ napi_module_register(&demoModule); -} +} \ No newline at end of file diff --git a/NativeAPI/NativeTemplateDemo/entry/src/main/ets/pages/Index.ets b/NativeAPI/NativeTemplateDemo/entry/src/main/ets/pages/Index.ets index d366f87e879fea24da4733f9064b137adae012c9..4100b0184983791819c430c9f2b9aedcaefb4cfb 100644 --- a/NativeAPI/NativeTemplateDemo/entry/src/main/ets/pages/Index.ets +++ b/NativeAPI/NativeTemplateDemo/entry/src/main/ets/pages/Index.ets @@ -43,7 +43,6 @@ struct NativeTemplate { right: $r('app.float.text_padding_left'), top: $r('app.float.text_padding_top') }) - Row() { Text($r('app.string.message')) .fontSize($r('app.float.message_font_size')) @@ -60,7 +59,6 @@ struct NativeTemplate { .padding({ left: $r('app.float.text_padding_left'), right: $r('app.float.text_padding_left') }) .justifyContent(FlexAlign.Start) .alignItems(VerticalAlign.Bottom) - Column() { Row() { Text($r('app.string.result_tip')) @@ -76,7 +74,6 @@ struct NativeTemplate { bottom: $r('app.float.tips_result_padding_bottom'), right: $r('app.float.tips_result_padding_right') }) - Row() { Text(this.result) .textAlign(TextAlign.End) @@ -90,7 +87,6 @@ struct NativeTemplate { .padding({ right: $r('app.float.result_padding_right') }) .width(CommonContants.FULL_PARENT) .justifyContent(FlexAlign.End) - Row() { Text($r('app.string.input_x_value')) .fontColor(Color.Black) @@ -110,7 +106,6 @@ struct NativeTemplate { .padding({ left: $r('app.float.text_input_padding'), right: $r('app.float.text_input_padding') }) .width(CommonContants.FULL_PARENT) .justifyContent(FlexAlign.Start) - Row() { Text($r('app.string.input_y_value')) .fontColor(Color.Black) @@ -130,13 +125,11 @@ struct NativeTemplate { .padding({ left: $r('app.float.text_input_padding'), right: $r('app.float.text_input_padding') }) .width(CommonContants.FULL_PARENT) .justifyContent(FlexAlign.Start) - } .margin($r('app.float.function_area_margin')) .borderRadius($r('app.float.function_area_border_radius')) .height($r('app.float.function_area_height')) .backgroundColor(Color.White) - Row() { Button($r('app.string.submit_button')) .fontSize($r('app.float.submit_button_font_size')) @@ -145,10 +138,9 @@ struct NativeTemplate { .width($r('app.float.button_width')) .onClick(() => { let resultTemp = libHello.myHypot(this.numX, this.numY); - if (resultTemp > CommonContants.MAX_RESULT){ + if (resultTemp > CommonContants.MAX_RESULT) { this.result = resultTemp.toExponential(CommonContants.EXPONENTIAL_COUNT); - } - else { + } else { this.result = resultTemp.toFixed(CommonContants.FIXED_COUNT); } }) diff --git a/NativeAPI/XComponent/README.md b/NativeAPI/XComponent/README.md index 1644cbb0a31f1e14f8881fc8ad493d17ca4d902a..c14fb4cd7ca5cfdc0896bd8653b21fa669c5e69b 100644 --- a/NativeAPI/XComponent/README.md +++ b/NativeAPI/XComponent/README.md @@ -2,7 +2,9 @@ ## 介绍 -本篇Codelab主要介绍如何使用XComponent组件调用Native API来创建EGL/GLES环境,从而使用标准OpenGL ES进行图形渲染。使用OpenGL ES实现在主页面绘制一个正方形,并可以改变正方形的颜色。如图所示,点击绘制矩形按钮,XComponent组件绘制区域中渲染出一个正方形,点击绘制区域,正方形显示另一种颜色,点击绘制矩形按钮正方形还原至初始绘制的颜色。 +本篇Codelab主要介绍如何使用XComponent组件调用NAPI来创建EGL/GLES环境,实现在主页面绘制一个正方形,并可以改变正方形的颜色。本篇CodeLab使用Native C++模板创建。 + +如图所示,点击绘制矩形按钮,XComponent组件绘制区域中渲染出一个正方形,点击绘制区域,正方形显示另一种颜色,点击绘制矩形按钮正方形还原至初始绘制的颜色。 ![](figures/zh-cn_image_0000001569305413.gif) @@ -48,6 +50,8 @@ 本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。 +使用Native C++模板创建项目会自动生成cpp文件夹、types文件夹、CMakeList.txt文件,开发者可以根据实际情况自行添加修改其他文件及文件夹。 + ``` ├──entry/src/main │ ├──cpp // C++代码区 @@ -126,7 +130,12 @@ struct Index { ## ArkTS侧方法调用 -在ArkTS侧导入编译生成的动态链接库文件。增加XComponent组件,设置XComponent组件的唯一标识id,指定XComponent组件类型及需要链接的动态库名称。组件链接动态库加载完成后回调onLoad()方法指定上下文环境,上下文环境包含来自C++挂载的方法。新增Button组件,绑定由Native API注册的drawRectangle()方法,点击后绘制正方形。 +ArkTS侧方法调用步骤如下: + +- 使用import语句导入编译生成的动态链接库文件。 +- 增加XComponent组件,设置XComponent组件的唯一标识id,指定XComponent组件类型及需要链接的动态库名称。 +- 组件链接动态库加载完成后回调onLoad()方法,指定XComponent组件的上下文环境,上下文环境包含来自C++挂载的方法。 +- 新增Button组件,绑定由NAPI注册的drawRectangle()方法,实现绘制正方形的功能。 ```typescript // Index.ets @@ -172,11 +181,17 @@ struct Index { ``` c++ // egl_core.cpp - void EGLCore::EglContextInit(void *window, int width, int height) + bool EGLCore::EglContextInit(void *window, int width, int height) { + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "EGLCore", "EglContextInit execute"); + if ((nullptr == window) || (0 >= width) || (0 >= height)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "EglContextInit: param error"); + return false; + } + m_width = width; m_height = height; - if (m_width > 0) { + if (0 < m_width) { // 计算绘制矩形宽度百分比 m_widthPercent = FIFTY_PERCENT * m_height / m_width; } @@ -185,41 +200,59 @@ struct Index { // 初始化display m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (EGL_NO_DISPLAY == m_eglDisplay) { - return; + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglGetDisplay: unable to get EGL display"); + return false; } EGLint majorVersion; EGLint minorVersion; if (!eglInitialize(m_eglDisplay, &majorVersion, &minorVersion)) { - return; + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", + "eglInitialize: unable to get initialize EGL display"); + return false; } // 选择配置 const EGLint maxConfigSize = 1; EGLint numConfigs; if (!eglChooseConfig(m_eglDisplay, ATTRIB_LIST, &m_eglConfig, maxConfigSize, &numConfigs)) { - return; + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglChooseConfig: unable to choose configs"); + return false; } + // 创建环境 + return CreateEnvironment(); + } + + bool EGLCore::CreateEnvironment() + { // 创建surface - if (nullptr != m_eglWindow) { - m_eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig, m_eglWindow, NULL); - if (m_eglSurface == nullptr) { - return; - } + if (nullptr == m_eglWindow) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "m_eglWindow is null"); + return false; + } + m_eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig, m_eglWindow, NULL); + + if (nullptr == m_eglSurface) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", + "eglCreateWindowSurface: unable to create surface"); + return false; } // 创建context m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, CONTEXT_ATTRIBS); if (!eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext)) { - return; + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglMakeCurrent failed"); + return false; } // 创建program - m_programHandle = CreateProgram(VERTEX_SHADER, FRAGMENT_SHADER); - if (!m_programHandle) { - return; + m_program = CreateProgram(VERTEX_SHADER, FRAGMENT_SHADER); + if (PROGRAM_ERROR == m_program) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "CreateProgram: unable to create program"); + return false; } + return true; } ``` @@ -250,11 +283,22 @@ struct Index { // egl_core.cpp void EGLCore::Draw() { + m_flag = false; + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "EGLCore", "Draw"); + // 绘制准备工作 - GLint positionHandle = PrepareDraw(); + GLint position = PrepareDraw(); + if (POSITION_ERROR == position) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw get position failed"); + return; + } // 绘制背景 - ExecuteDraw(positionHandle, BACKGROUND_COLOR, BACKGROUND_RECTANGLE_VERTICES); + if (!ExecuteDraw(position, BACKGROUND_COLOR, BACKGROUND_RECTANGLE_VERTICES, + sizeof(BACKGROUND_RECTANGLE_VERTICES))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw execute draw background failed"); + return; + } // 确定绘制矩形的顶点,使用绘制区域的百分比表示 const GLfloat rectangleVertices[] = { @@ -265,50 +309,67 @@ struct Index { }; // 绘制矩形 - ExecuteDraw(positionHandle, DRAW_COLOR, rectangleVertices); + if (!ExecuteDraw(position, DRAW_COLOR, rectangleVertices, sizeof(rectangleVertices))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw execute draw rectangle failed"); + return; + } // 绘制后操作 - FinishDraw(); + if (!FinishDraw()) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw FinishDraw failed"); + return; + } // 标记已绘制 m_flag = true; } - // 绘制前准备,获取positionHandle + // 绘制前准备,获取position,创建成功时position值从0开始 GLint EGLCore::PrepareDraw() { - if (!eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext)) { - return -1; + if ((nullptr == m_eglDisplay) || (nullptr == m_eglSurface) || (nullptr == m_eglContext) || + (!eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "PrepareDraw: param error"); + return POSITION_ERROR; } + // 下列方法无返回值 glViewport(DEFAULT_X_POSITION, DEFAULT_X_POSITION, m_width, m_height); glClearColor(GL_RED_DEFAULT, GL_GREEN_DEFAULT, GL_BLUE_DEFAULT, GL_ALPHA_DEFAULT); glClear(GL_COLOR_BUFFER_BIT); - glUseProgram(m_programHandle); + glUseProgram(m_program); - GLint positionHandle = glGetAttribLocation(m_programHandle, POSITION_HANDLE_NAME); - return positionHandle; + return glGetAttribLocation(m_program, POSITION_NAME); } // 依据传入参数在指定区域绘制指定颜色 - void EGLCore::ExecuteDraw(GLint positionHandle, const GLfloat *color, const GLfloat rectangleVertices[]) + bool EGLCore::ExecuteDraw(GLint position, const GLfloat *color, const GLfloat rectangleVertices[], + unsigned long vertSize) { - glVertexAttribPointer(positionHandle, POINTER_SIZE, GL_FLOAT, GL_FALSE, 0, rectangleVertices); - glEnableVertexAttribArray(positionHandle); + if ((0 > position) || (nullptr == color) || (RECTANGLE_VERTICES_SIZE != vertSize / sizeof(rectangleVertices[0]))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "ExecuteDraw: param error"); + return false; + } + + // 下列方法无返回值 + glVertexAttribPointer(position, POINTER_SIZE, GL_FLOAT, GL_FALSE, 0, rectangleVertices); + glEnableVertexAttribArray(position); glVertexAttrib4fv(1, color); glDrawArrays(GL_TRIANGLE_FAN, 0, TRIANGLE_FAN_SIZE); - glDisableVertexAttribArray(positionHandle); + glDisableVertexAttribArray(position); + + return true; } // 结束绘制操作 - void EGLCore::FinishDraw() + bool EGLCore::FinishDraw() { // 强制刷新缓冲 glFlush(); glFinish(); // 交换前后缓存 - eglSwapBuffers(m_eglDisplay, m_eglSurface); + return eglSwapBuffers(m_eglDisplay, m_eglSurface); } ``` @@ -330,10 +391,18 @@ struct Index { } // 绘制准备工作 - GLint positionHandle = PrepareDraw(); + GLint position = PrepareDraw(); + if (POSITION_ERROR == position) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "ChangeColor get position failed"); + return; + } // 绘制背景 - ExecuteDraw(positionHandle, BACKGROUND_COLOR, BACKGROUND_RECTANGLE_VERTICES); + if (!ExecuteDraw(position, BACKGROUND_COLOR, BACKGROUND_RECTANGLE_VERTICES, + sizeof(BACKGROUND_RECTANGLE_VERTICES))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "ChangeColor execute draw background failed"); + return; + } // 确定绘制矩形的顶点,使用绘制区域的百分比表示 const GLfloat rectangleVertices[] = { @@ -344,87 +413,126 @@ struct Index { }; // 使用新的颜色绘制矩形 - ExecuteDraw(positionHandle, CHANGE_COLOR, rectangleVertices); + if (!ExecuteDraw(position, CHANGE_COLOR, rectangleVertices, sizeof(rectangleVertices))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "ChangeColor execute draw rectangle failed"); + return; + } // 结束绘制 - FinishDraw(); + if (!FinishDraw()) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "ChangeColor FinishDraw failed"); + } } ``` -### 使用Native API将C++方法传递给ArkTS +### 使用NAPI将C++方法传递给ArkTS -- 创建NAPI接口函数NapiDrawRectangle\(\),封装对应C++渲染方法。根据XComponent组件信息,获取对应的渲染模块render,调用绘制矩形的方法。 +- 创建接口函数NapiDrawRectangle\(\),封装对应C++渲染方法。根据XComponent组件信息,获取对应的渲染模块render,调用绘制矩形的方法。 - ```c++ - // plugin_render.cpp - napi_value PluginRender::NapiDrawRectangle(napi_env env, napi_callback_info info) - { - // 获取环境变量参数 - napi_value thisArg; - if (napi_ok != napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr)) { - return nullptr; - } - - // 获取环境变量中XComponent实例 - napi_value exportInstance; - if (napi_ok != napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance)) { - return nullptr; - } - - OH_NativeXComponent *nativeXComponent = nullptr; - if (napi_ok != napi_unwrap(env, exportInstance, reinterpret_cast(&nativeXComponent))) { - return nullptr; - } - - // 获取XComponent实例的id - char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; - uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; - if (OH_NATIVEXCOMPONENT_RESULT_SUCCESS != OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize)) { - return nullptr; - } - - std::string id(idStr); - PluginRender *render = PluginRender::GetInstance(id); - if (render) { - // 该接口函数封装的是上文实现的渲染方法 - render->m_eglCore->Draw(); - } - return nullptr; - } - ``` + 注册为ArkTS侧接口的方法,固定为napi\_value \(\*napi\_callback\)\(napi\_env env, napi\_callback\_info info\)类型,不可更改。napi\_value为NAPI定义的指针,无返回值时返回 nullptr。 -- 使用Native API中的napi\_define\_properties方法,将接口函数NapiDrawRectangle\(\)注册为ArkTS侧接口drawRectangle\(\),在ArkTS侧调用drawRectangle\(\)方法,完成正方形的绘制。 + ```c++ + // plugin_render.cpp + // NAPI注册方法固定参数及返回值类型,无返回值时返回nullptr + napi_value PluginRender::NapiDrawRectangle(napi_env env, napi_callback_info info) + { + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "PluginRender", "NapiDrawRectangle"); + if ((nullptr == env) || (nullptr == info)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender", "NapiDrawRectangle: env or info is null"); + return nullptr; + } + + // 获取环境变量参数 + napi_value thisArg; + if (napi_ok != napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender", "NapiDrawRectangle: napi_get_cb_info fail"); + return nullptr; + } + + // 获取环境变量中XComponent实例 + napi_value exportInstance; + if (napi_ok != napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender", + "NapiDrawRectangle: napi_get_named_property fail"); + return nullptr; + } + + OH_NativeXComponent *nativeXComponent = nullptr; + if (napi_ok != napi_unwrap(env, exportInstance, reinterpret_cast(&nativeXComponent))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender", "NapiDrawRectangle: napi_unwrap fail"); + return nullptr; + } + + // 获取XComponent实例的id + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' }; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NATIVEXCOMPONENT_RESULT_SUCCESS != OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender", + "NapiDrawRectangle: Unable to get XComponent id"); + return nullptr; + } + + std::string id(idStr); + PluginRender *render = PluginRender::GetInstance(id); + if (render) { + // 调用绘制矩形的方法 + render->m_eglCore->Draw(); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "PluginRender", "render->m_eglCore->Draw() executed"); + } + return nullptr; + } + ``` - ```C++ - // plugin_render.cpp - napi_value PluginRender::Export(napi_env env, napi_value exports) - { - // 将接口函数注册为ArkTS侧接口drawRectangle - napi_property_descriptor desc[] = { - { "drawRectangle", nullptr, PluginRender::NapiDrawRectangle, nullptr, nullptr, nullptr, napi_default, nullptr } - }; - napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); - return exports; - } - ``` +- 使用NAPI中的napi\_define\_properties方法,将接口函数NapiDrawRectangle\(\)注册为ArkTS侧接口drawRectangle\(\),在ArkTS侧调用drawRectangle\(\)方法,完成正方形的绘制。 -### 使用Native API实现触摸事件回调函数 + ```c++ + // plugin_render.cpp + void PluginRender::Export(napi_env env, napi_value exports) + { + if ((nullptr == env) || (nullptr == exports)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender", "Export: env or exports is null"); + return; + } + + // 将接口函数注册为ArkTS侧接口drawRectangle + napi_property_descriptor desc[] = { + { "drawRectangle", nullptr, PluginRender::NapiDrawRectangle, nullptr, nullptr, nullptr, napi_default, nullptr } + }; + if (napi_ok != napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender", "Export: napi_define_properties failed"); + } + } + ``` + +### 使用NAPI实现触摸事件回调函数 -通过将上文实现的改变颜色函数ChangeColor\(\)封装为触摸事件回调函数的方式,实现在触摸时改变正方形的颜色。创建一个新函数DispatchTouchEventCB\(\),将C++对应方法封装于其中。将新函数绑定为组件触摸事件的回调函数,组件绘制区域产生触摸事件时触发,改变正方形展示的颜色。 +通过将C++方法封装至触摸事件回调函数的方式,实现触摸绘制区域时改变正方形的颜色的功能。 + +- 创建一个新函数DispatchTouchEventCB(),将改变颜色的C++方法ChangeColor()封装于其中。 +- 将新函数绑定为组件触摸事件的回调函数,组件绘制区域产生触摸事件时触发,改变正方形展示的颜色。 ```c++ // plugin_render.cpp void DispatchTouchEventCB(OH_NativeXComponent *component, void *window) { - char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "DispatchTouchEventCB"); + if ((nullptr == component) || (nullptr == window)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", + "DispatchTouchEventCB: component or window is null"); + return; + } + + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' }; uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; if (OH_NATIVEXCOMPONENT_RESULT_SUCCESS != OH_NativeXComponent_GetXComponentId(component, idStr, &idSize)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", + "DispatchTouchEventCB: Unable to get XComponent id"); return; } std::string id(idStr); - auto render = PluginRender::GetInstance(id); + PluginRender *render = PluginRender::GetInstance(id); if (nullptr != render) { // 封装改变颜色的函数 render->m_eglCore->ChangeColor(); @@ -434,36 +542,121 @@ void DispatchTouchEventCB(OH_NativeXComponent *component, void *window) PluginRender::PluginRender(std::string &id) { this->m_id = id; - this->m_eglCore = new EGLCore(id); + this->m_eglCore = new EGLCore(); auto renderCallback = &PluginRender::m_callback; renderCallback->OnSurfaceCreated = OnSurfaceCreatedCB; renderCallback->OnSurfaceChanged = OnSurfaceChangedCB; renderCallback->OnSurfaceDestroyed = OnSurfaceDestroyedCB; - // 这一步修改了触摸事件的回调函数,在触摸事件触发时调用NAPI接口函数,从而调用原C++方法 + // 设置触摸事件的回调函数,在触摸事件触发时调用NAPI接口函数,从而调用原C++方法 renderCallback->DispatchTouchEvent = DispatchTouchEventCB; } ``` -## 注册与编译 +### 释放相关资源 -在napi\_init.cpp文件中,Init方法注册上文实现的接口函数,从而将封装的C++方法传递出来,供ArkTS侧调用。编写接口的描述信息,根据实际需要可以修改对应参数。 +释放申请资源的步骤如下: + +- EGLCore类下创建Release\(\)方法,释放初始化环境时申请的资源,包含窗口display、渲染区域surface、环境上下文context等。 +- PluginRender类添加Release\(\)方法,释放EGLCore实例及PluginRender实例。 +- 创建一个新方法OnSurfaceDestroyedCB\(\),将PluginRender类内释放资源的方法Release\(\)封装于其中。 +- 将新方法绑定为组件销毁事件的回调方法,组件销毁时触发,释放相关资源。 + +```c++ +// egl_core.cpp +void EGLCore::Release() +{ + if ((nullptr == m_eglDisplay) || (nullptr == m_eglSurface) || (!eglDestroySurface(m_eglDisplay, m_eglSurface))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Release eglDestroySurface failed"); + } + + if ((nullptr == m_eglDisplay) || (nullptr == m_eglContext) || (!eglDestroyContext(m_eglDisplay, m_eglContext))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Release eglDestroyContext failed"); + } + + if ((nullptr == m_eglDisplay) || (!eglTerminate(m_eglDisplay))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Release eglTerminate failed"); + } +} + +// plugin_render.cpp +void PluginRender::Release(std::string &id) +{ + PluginRender *render = PluginRender::GetInstance(id); + if (nullptr != render) { + render->m_eglCore->Release(); + delete render->m_eglCore; + render->m_eglCore = nullptr; + delete render; + render = nullptr; + m_instance.erase(m_instance.find(id)); + } +} + +void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window) +{ + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "OnSurfaceDestroyedCB"); + if ((nullptr == component) || (nullptr == window)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", + "OnSurfaceDestroyedCB: component or window is null"); + return; + } + + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' }; + uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; + if (OH_NATIVEXCOMPONENT_RESULT_SUCCESS != OH_NativeXComponent_GetXComponentId(component, idStr, &idSize)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", + "OnSurfaceDestroyedCB: Unable to get XComponent id"); + return; + } + + // 释放申请的资源 + std::string id(idStr); + PluginRender::Release(id); +} + +PluginRender::PluginRender(std::string &id) +{ + this->m_id = id; + this->m_eglCore = new EGLCore(); + OH_NativeXComponent_Callback *renderCallback = &PluginRender::m_callback; + renderCallback->OnSurfaceCreated = OnSurfaceCreatedCB; + renderCallback->OnSurfaceChanged = OnSurfaceChangedCB; + + // 设置组件销毁事件的回调函数,组件销毁时触发相关操作,释放申请的资源 + renderCallback->OnSurfaceDestroyed = OnSurfaceDestroyedCB; + renderCallback->DispatchTouchEvent = DispatchTouchEventCB; +} +``` + + + +### 注册与编译 + +在napi\_init.cpp文件中,Init方法注册上文实现的接口函数,从而将封装的C++方法传递出来,供ArkTS侧调用。编写接口的描述信息,根据实际需要可以修改对应参数。\_\_attribute\_\_\(\(constructor\)\)修饰的方法由系统自动调用,使用NAPI接口napi\_module\_register\(\)传入模块描述信息进行模块注册。Native C++模板创建项目会自动生成此结构代码,开发者可根据实际情况修改其中内容。 ```c++ // napi_init.cpp static napi_value Init(napi_env env, napi_value exports) { + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Init", "Init begins"); + if ((nullptr == env) || (nullptr == exports)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Init", "env or exports is null"); + return nullptr; + } + napi_property_descriptor desc[] = { { "getContext", nullptr, PluginManager::GetContext, nullptr, nullptr, nullptr, napi_default, nullptr } }; + // 将接口函数注册为ArkTS侧接口getContext() - napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); + if (napi_ok != napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Init", "napi_define_properties failed"); + return nullptr; + } // 方法内检查环境变量是否包含XComponent组件实例,若实例存在注册绘制相关接口 - bool ret = PluginManager::GetInstance()->Export(env, exports); - if (!ret) { - OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Init", "Init failed"); - } + PluginManager::GetInstance()->Export(env, exports); return exports; } @@ -476,6 +669,11 @@ static napi_module nativerenderModule = { .nm_priv = ((void *)0), .reserved = { 0 } }; + +extern "C" __attribute__((constructor)) void RegisterModule(void) +{ + napi_module_register(&nativerenderModule); +} ``` 使用CMake工具链将C++源代码编译成动态链接库文件。本篇Codelab中会链接两次动态库,第一次为import语句,第二次为XComponent组件链接动态库。 @@ -513,7 +711,7 @@ target_link_libraries(nativerender PUBLIC ${EGL-lib} ${GLES-lib} ${hilog-lib} ${ 您已经完成了本次Codelab的学习,并了解到以下知识点: -1. 使用XComponent组件调用Native API创建EGL/GLES环境。 +1. 使用XComponent组件调用NAPI创建EGL/GLES环境。 2. 使用OpenGL ES进行开发渲染。 3. 使用回调函数响应触摸事件。 diff --git a/NativeAPI/XComponent/entry/src/main/cpp/common/common.h b/NativeAPI/XComponent/entry/src/main/cpp/common/common.h index ebaf02bb8ba0e35b3bfe18d99b230532d4ca6ed7..c813b4501f37966ff68ef519a85af87d82fc7fe5 100644 --- a/NativeAPI/XComponent/entry/src/main/cpp/common/common.h +++ b/NativeAPI/XComponent/entry/src/main/cpp/common/common.h @@ -152,12 +152,27 @@ const GLfloat GL_ALPHA_DEFAULT = 1.0; */ const GLuint PROGRAM_ERROR = 0; +/** + * Rectangle vertices size. + */ +const int RECTANGLE_VERTICES_SIZE = 8; + +/** + * Position handle name. + */ +const char POSITION_NAME[] = "a_position"; + +/** + * Position error. + */ +const GLint POSITION_ERROR = -1; + /** * Context type. */ enum ContextType { APP_LIFECYCLE, - JS_PAGE_LIFECYCLE, + PAGE_LIFECYCLE, }; /** diff --git a/NativeAPI/XComponent/entry/src/main/cpp/manager/plugin_manager.cpp b/NativeAPI/XComponent/entry/src/main/cpp/manager/plugin_manager.cpp index cf0babc9ac5ea8c1a80c30a9189e707816841437..635189729553a59b1a25181b0cea66565bdc02e8 100644 --- a/NativeAPI/XComponent/entry/src/main/cpp/manager/plugin_manager.cpp +++ b/NativeAPI/XComponent/entry/src/main/cpp/manager/plugin_manager.cpp @@ -25,11 +25,38 @@ PluginManager PluginManager::m_pluginManager; +PluginManager::~PluginManager() +{ + for (auto iter = m_nativeXComponentMap.begin(); iter != m_nativeXComponentMap.end(); ++iter) { + if (nullptr != iter->second) { + delete iter->second; + iter->second = nullptr; + } + } + m_nativeXComponentMap.clear(); + + for (auto iter = m_pluginRenderMap.begin(); iter != m_pluginRenderMap.end(); ++iter) { + if (nullptr != iter->second) { + delete iter->second; + iter->second = nullptr; + } + } + m_pluginRenderMap.clear(); +} + napi_value PluginManager::GetContext(napi_env env, napi_callback_info info) { + if ((nullptr == env) || (nullptr == info)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginManager", "GetContext env or info is null"); + return nullptr; + } + size_t argCnt = GET_CONTEXT_PARAM_CNT; - napi_value args[GET_CONTEXT_PARAM_CNT] = {nullptr}; - napi_get_cb_info(env, info, &argCnt, args, nullptr, nullptr); + napi_value args[GET_CONTEXT_PARAM_CNT] = { nullptr }; + if (napi_ok != napi_get_cb_info(env, info, &argCnt, args, nullptr, nullptr)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginManager", "GetContext napi_get_cb_info failed"); + } + if (GET_CONTEXT_PARAM_CNT != argCnt) { napi_throw_type_error(env, NULL, "Wrong number of arguments"); return nullptr; @@ -37,6 +64,7 @@ napi_value PluginManager::GetContext(napi_env env, napi_callback_info info) napi_valuetype valuetype; if (napi_ok != napi_typeof(env, args[0], &valuetype)) { + napi_throw_type_error(env, NULL, "napi_typeof failed"); return nullptr; } @@ -47,17 +75,32 @@ napi_value PluginManager::GetContext(napi_env env, napi_callback_info info) int64_t value; if (napi_ok != napi_get_value_int64(env, args[0], &value)) { + napi_throw_type_error(env, NULL, "napi_get_value_int64 failed"); return nullptr; } napi_value exports; if (napi_ok != napi_create_object(env, &exports)) { + napi_throw_type_error(env, NULL, "napi_create_object failed"); return nullptr; } + RegisterLifecycle(env, exports, value); + + return exports; +} + +void PluginManager::RegisterLifecycle(napi_env env, napi_value exports, int64_t value) +{ + if ((nullptr == env) || (nullptr == exports)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginManager", + "RegisterLifecycle: env or exports is null"); + return; + } + switch (value) { case APP_LIFECYCLE: { - OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "PluginManager", "getContext: APP_LIFECYCLE"); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "PluginManager", "RegisterLifecycle: APP_LIFECYCLE"); /* **** Register App Lifecycle **** */ napi_property_descriptor desc[] = { {"onCreate", nullptr, PluginManager::NapiOnCreate, nullptr, nullptr, nullptr, napi_default, nullptr}, @@ -66,10 +109,11 @@ napi_value PluginManager::GetContext(napi_env env, napi_callback_info info) {"onDestroy", nullptr, PluginManager::NapiOnDestroy, nullptr, nullptr, nullptr, napi_default, nullptr} }; napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); - } break; - case JS_PAGE_LIFECYCLE: { - OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "PluginManager", "getContext: JS_PAGE_LIFECYCLE"); - /* **** Register JS Page Lifecycle **** */ + break; + } + case PAGE_LIFECYCLE: { + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "PluginManager", "RegisterLifecycle: PAGE_LIFECYCLE"); + /* **** Register Page Lifecycle **** */ napi_property_descriptor desc[] = { {"aboutToAppear", nullptr, PluginManager::NapiToAppear, nullptr, nullptr, nullptr, napi_default, nullptr}, {"aboutToDisappear", nullptr, PluginManager::NapiToDisappear, nullptr, nullptr, nullptr, napi_default, nullptr}, @@ -77,57 +121,71 @@ napi_value PluginManager::GetContext(napi_env env, napi_callback_info info) {"onPageHide", nullptr, PluginManager::NapiOnPageHide, nullptr, nullptr, nullptr, napi_default, nullptr} }; napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); - } break; - default: - OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, "PluginManager", "getContext: wrong type of arguments"); + break; + } + default: { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginManager", + "RegisterLifecycle: wrong type of value"); + break; + } } - return exports; } -bool PluginManager::Export(napi_env env, napi_value exports) +void PluginManager::Export(napi_env env, napi_value exports) { + if ((nullptr == env) || (nullptr == exports)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginManager", "Export: env or exports is null"); + return; + } + napi_value exportInstance = nullptr; if (napi_ok != napi_get_named_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance)) { OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginManager", "Export: napi_get_named_property fail"); - return false; + return; } OH_NativeXComponent *nativeXComponent = nullptr; if (napi_ok != napi_unwrap(env, exportInstance, reinterpret_cast(&nativeXComponent))) { OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginManager", "Export: napi_unwrap fail"); - return false; + return; } - char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' }; uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; if (OH_NATIVEXCOMPONENT_RESULT_SUCCESS != OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize)) { OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginManager", "Export: OH_NativeXComponent_GetXComponentId fail"); - return false; + return; } std::string id(idStr); auto context = PluginManager::GetInstance(); - if (nullptr != context) { + if ((nullptr != context) && (nullptr != nativeXComponent)) { context->SetNativeXComponent(id, nativeXComponent); auto render = context->GetRender(id); OH_NativeXComponent_RegisterCallback(nativeXComponent, &PluginRender::m_callback); if (nullptr != render) { render->Export(env, exports); } - return true; } - return false; } void PluginManager::SetNativeXComponent(std::string &id, OH_NativeXComponent *nativeXComponent) { + if (nullptr == nativeXComponent) { + return; + } + if (m_nativeXComponentMap.find(id) == m_nativeXComponentMap.end()) { m_nativeXComponentMap[id] = nativeXComponent; - } else { - if (m_nativeXComponentMap[id] != nativeXComponent) { - m_nativeXComponentMap[id] = nativeXComponent; - } + return; + } + + if (m_nativeXComponentMap[id] != nativeXComponent) { + OH_NativeXComponent *tmp = m_nativeXComponentMap[id]; + delete tmp; + tmp = nullptr; + m_nativeXComponentMap[id] = nativeXComponent; } } @@ -137,64 +195,55 @@ PluginRender *PluginManager::GetRender(std::string &id) PluginRender *instance = PluginRender::GetInstance(id); m_pluginRenderMap[id] = instance; return instance; - } else { - return m_pluginRenderMap[id]; } + + return m_pluginRenderMap[id]; } napi_value PluginManager::NapiOnCreate(napi_env env, napi_callback_info info) { OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "PluginManager", "NapiOnCreate"); - // do something return nullptr; } napi_value PluginManager::NapiOnShow(napi_env env, napi_callback_info info) { OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "PluginManager", "NapiOnShow"); - // do something return nullptr; } napi_value PluginManager::NapiOnHide(napi_env env, napi_callback_info info) { OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "PluginManager", "NapiOnHide"); - // do something return nullptr; } napi_value PluginManager::NapiOnDestroy(napi_env env, napi_callback_info info) { OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "PluginManager", "NapiOnDestroy"); - PluginRender::ReleaseEgl(); - // do something return nullptr; } napi_value PluginManager::NapiToAppear(napi_env env, napi_callback_info info) { OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "PluginManager", "NapiToAppear"); - // do something return nullptr; } napi_value PluginManager::NapiToDisappear(napi_env env, napi_callback_info info) { OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "PluginManager", "NapiToDisappear"); - // do something return nullptr; } napi_value PluginManager::NapiOnPageShow(napi_env env, napi_callback_info info) { OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "PluginManager", "NapiOnPageShow"); - // do something return nullptr; } napi_value PluginManager::NapiOnPageHide(napi_env env, napi_callback_info info) { OH_LOG_Print(LOG_APP, LOG_INFO, LOG_DOMAIN, "PluginManager", "NapiOnPageHide"); - // do something return nullptr; -} +} \ No newline at end of file diff --git a/NativeAPI/XComponent/entry/src/main/cpp/manager/plugin_manager.h b/NativeAPI/XComponent/entry/src/main/cpp/manager/plugin_manager.h index 14cfd9564d7ca323d1e7c5988cfd25d871e3aa9b..52ab66437b6656a452c2ac769b5150908c0ef08c 100644 --- a/NativeAPI/XComponent/entry/src/main/cpp/manager/plugin_manager.h +++ b/NativeAPI/XComponent/entry/src/main/cpp/manager/plugin_manager.h @@ -27,7 +27,7 @@ class PluginManager { public: - ~PluginManager() {} + ~PluginManager(); static PluginManager *GetInstance() { @@ -52,7 +52,10 @@ public: void SetNativeXComponent(std::string &id, OH_NativeXComponent *nativeXComponent); PluginRender *GetRender(std::string &id); - bool Export(napi_env env, napi_value exports); + void Export(napi_env env, napi_value exports); + +private: + static void RegisterLifecycle(napi_env env, napi_value exports, int64_t value); private: static PluginManager m_pluginManager; diff --git a/NativeAPI/XComponent/entry/src/main/cpp/napi_init.cpp b/NativeAPI/XComponent/entry/src/main/cpp/napi_init.cpp index f040f3a7f6990fd74df4aaa9081a786e5bcb68db..10e4233baa2450b1515e5d0ecd0a3e7fa47e18ab 100644 --- a/NativeAPI/XComponent/entry/src/main/cpp/napi_init.cpp +++ b/NativeAPI/XComponent/entry/src/main/cpp/napi_init.cpp @@ -17,20 +17,27 @@ #include "manager/plugin_manager.h" #include "common/common.h" +EXTERN_C_START static napi_value Init(napi_env env, napi_value exports) { OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Init", "Init begins"); + if ((nullptr == env) || (nullptr == exports)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Init", "env or exports is null"); + return nullptr; + } + napi_property_descriptor desc[] = { { "getContext", nullptr, PluginManager::GetContext, nullptr, nullptr, nullptr, napi_default, nullptr } }; - napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); - - bool ret = PluginManager::GetInstance()->Export(env, exports); - if (!ret) { - OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Init", "Init failed"); + if (napi_ok != napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Init", "napi_define_properties failed"); + return nullptr; } + + PluginManager::GetInstance()->Export(env, exports); return exports; } +EXTERN_C_END static napi_module nativerenderModule = { .nm_version = 1, diff --git a/NativeAPI/XComponent/entry/src/main/cpp/render/egl_core.cpp b/NativeAPI/XComponent/entry/src/main/cpp/render/egl_core.cpp index 991cdc0e9e5038dcc50df530e5ad258a5e3dcae6..f94f2872dff6baa4a529c78da8a14a862f39e44e 100644 --- a/NativeAPI/XComponent/entry/src/main/cpp/render/egl_core.cpp +++ b/NativeAPI/XComponent/entry/src/main/cpp/render/egl_core.cpp @@ -24,13 +24,17 @@ #include "plugin_render.h" #include "../common/common.h" -void EGLCore::EglContextInit(void *window, int width, int height) +bool EGLCore::EglContextInit(void *window, int width, int height) { - OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "EGLCore", - "EglContextInit ===> window = %{public}p, w = %{public}d, h = %{public}d", window, width, height); + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "EGLCore", "EglContextInit execute"); + if ((nullptr == window) || (0 >= width) || (0 >= height)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "EglContextInit: param error"); + return false; + } + m_width = width; m_height = height; - if (m_width > 0) { + if (0 < m_width) { m_widthPercent = FIFTY_PERCENT * m_height / m_width; } m_eglWindow = static_cast(window); @@ -38,69 +42,95 @@ void EGLCore::EglContextInit(void *window, int width, int height) // Init display. m_eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (EGL_NO_DISPLAY == m_eglDisplay) { - OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglGetDisplay ===> unable to get EGL display"); - return; + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglGetDisplay: unable to get EGL display"); + return false; } EGLint majorVersion; EGLint minorVersion; if (!eglInitialize(m_eglDisplay, &majorVersion, &minorVersion)) { OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", - "eglInitialize ===> unable to get initialize EGL display"); - return; + "eglInitialize: unable to get initialize EGL display"); + return false; } // Select configuration. const EGLint maxConfigSize = 1; EGLint numConfigs; if (!eglChooseConfig(m_eglDisplay, ATTRIB_LIST, &m_eglConfig, maxConfigSize, &numConfigs)) { - OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglChooseConfig ===> unable to choose configs"); - return; + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglChooseConfig: unable to choose configs"); + return false; } + return CreateEnvironment(); +} + +bool EGLCore::CreateEnvironment() +{ // Create surface. - if (nullptr != m_eglWindow) { - m_eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig, m_eglWindow, NULL); - if (m_eglSurface == nullptr) { - OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", - "eglCreateWindowSurface ===> unable to create surface"); - return; - } + if (nullptr == m_eglWindow) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "m_eglWindow is null"); + return false; + } + m_eglSurface = eglCreateWindowSurface(m_eglDisplay, m_eglConfig, m_eglWindow, NULL); + + if (nullptr == m_eglSurface) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", + "eglCreateWindowSurface: unable to create surface"); + return false; } // Create context. m_eglContext = eglCreateContext(m_eglDisplay, m_eglConfig, EGL_NO_CONTEXT, CONTEXT_ATTRIBS); if (!eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext)) { - OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglMakeCurrent ===> error = %{public}d", - eglGetError()); - return; + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "eglMakeCurrent failed"); + return false; } // Create program. - m_programHandle = CreateProgram(VERTEX_SHADER, FRAGMENT_SHADER); - if (!m_programHandle) { - OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "CreateProgram ===> unable to create program"); - return; + m_program = CreateProgram(VERTEX_SHADER, FRAGMENT_SHADER); + if (PROGRAM_ERROR == m_program) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "CreateProgram: unable to create program"); + return false; } + return true; } void EGLCore::Background() { - GLint positionHandle = PrepareDraw(); - if (-1 == positionHandle) { + GLint position = PrepareDraw(); + if (POSITION_ERROR == position) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Background get position failed"); + return; + } + + if (!ExecuteDraw(position, BACKGROUND_COLOR, BACKGROUND_RECTANGLE_VERTICES, + sizeof(BACKGROUND_RECTANGLE_VERTICES))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Background execute draw failed"); + return; + } + + if (!FinishDraw()) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Background FinishDraw failed"); return; } - ExecuteDraw(positionHandle, BACKGROUND_COLOR, BACKGROUND_RECTANGLE_VERTICES); - FinishDraw(); } void EGLCore::Draw() { - GLint positionHandle = PrepareDraw(); - if (-1 == positionHandle) { + m_flag = false; + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "EGLCore", "Draw"); + GLint position = PrepareDraw(); + if (POSITION_ERROR == position) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw get position failed"); + return; + } + + if (!ExecuteDraw(position, BACKGROUND_COLOR, BACKGROUND_RECTANGLE_VERTICES, + sizeof(BACKGROUND_RECTANGLE_VERTICES))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw execute draw background failed"); return; } - ExecuteDraw(positionHandle, BACKGROUND_COLOR, BACKGROUND_RECTANGLE_VERTICES); const GLfloat rectangleVertices[] = { -m_widthPercent, FIFTY_PERCENT, @@ -108,9 +138,16 @@ void EGLCore::Draw() m_widthPercent, -FIFTY_PERCENT, -m_widthPercent, -FIFTY_PERCENT }; - ExecuteDraw(positionHandle, DRAW_COLOR, rectangleVertices); + if (!ExecuteDraw(position, DRAW_COLOR, rectangleVertices, sizeof(rectangleVertices))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw execute draw rectangle failed"); + return; + } + + if (!FinishDraw()) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Draw FinishDraw failed"); + return; + } - FinishDraw(); m_flag = true; } @@ -119,11 +156,18 @@ void EGLCore::ChangeColor() if (!m_flag) { return; } - GLint positionHandle = PrepareDraw(); - if (-1 == positionHandle) { + + GLint position = PrepareDraw(); + if (POSITION_ERROR == position) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "ChangeColor get position failed"); + return; + } + + if (!ExecuteDraw(position, BACKGROUND_COLOR, BACKGROUND_RECTANGLE_VERTICES, + sizeof(BACKGROUND_RECTANGLE_VERTICES))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "ChangeColor execute draw background failed"); return; } - ExecuteDraw(positionHandle, BACKGROUND_COLOR, BACKGROUND_RECTANGLE_VERTICES); const GLfloat rectangleVertices[] = { -m_widthPercent, FIFTY_PERCENT, @@ -131,130 +175,174 @@ void EGLCore::ChangeColor() m_widthPercent, -FIFTY_PERCENT, -m_widthPercent, -FIFTY_PERCENT }; - ExecuteDraw(positionHandle, CHANGE_COLOR, rectangleVertices); + if (!ExecuteDraw(position, CHANGE_COLOR, rectangleVertices, sizeof(rectangleVertices))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "ChangeColor execute draw rectangle failed"); + return; + } - FinishDraw(); + if (!FinishDraw()) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "ChangeColor FinishDraw failed"); + } } GLint EGLCore::PrepareDraw() { - if (!eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext)) { - OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "elgMakeCurrent ===> error = %{public}d", - eglGetError()); - return -1; + if ((nullptr == m_eglDisplay) || (nullptr == m_eglSurface) || (nullptr == m_eglContext) || + (!eglMakeCurrent(m_eglDisplay, m_eglSurface, m_eglSurface, m_eglContext))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "PrepareDraw: param error"); + return POSITION_ERROR; } + // The gl function has no return value. glViewport(DEFAULT_X_POSITION, DEFAULT_X_POSITION, m_width, m_height); glClearColor(GL_RED_DEFAULT, GL_GREEN_DEFAULT, GL_BLUE_DEFAULT, GL_ALPHA_DEFAULT); glClear(GL_COLOR_BUFFER_BIT); - glUseProgram(m_programHandle); + glUseProgram(m_program); - GLint positionHandle = glGetAttribLocation(m_programHandle, "a_position"); - return positionHandle; + return glGetAttribLocation(m_program, POSITION_NAME); } -void EGLCore::ExecuteDraw(GLint positionHandle, const GLfloat *color, const GLfloat rectangleVertices[]) +bool EGLCore::ExecuteDraw(GLint position, const GLfloat *color, const GLfloat rectangleVertices[], + unsigned long vertSize) { - glVertexAttribPointer(positionHandle, POINTER_SIZE, GL_FLOAT, GL_FALSE, 0, rectangleVertices); - glEnableVertexAttribArray(positionHandle); + if ((0 > position) || (nullptr == color) || (RECTANGLE_VERTICES_SIZE != vertSize / sizeof(rectangleVertices[0]))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "ExecuteDraw: param error"); + return false; + } + + // The gl function has no return value. + glVertexAttribPointer(position, POINTER_SIZE, GL_FLOAT, GL_FALSE, 0, rectangleVertices); + glEnableVertexAttribArray(position); glVertexAttrib4fv(1, color); glDrawArrays(GL_TRIANGLE_FAN, 0, TRIANGLE_FAN_SIZE); - glDisableVertexAttribArray(positionHandle); + glDisableVertexAttribArray(position); + + return true; } -void EGLCore::FinishDraw() +bool EGLCore::FinishDraw() { + // The gl function has no return value. glFlush(); glFinish(); - eglSwapBuffers(m_eglDisplay, m_eglSurface); + return eglSwapBuffers(m_eglDisplay, m_eglSurface); } GLuint EGLCore::LoadShader(GLenum type, const char *shaderSrc) { - GLuint shader; - GLint compiled; + if ((0 >= type) || (nullptr == shaderSrc)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "glCreateShader type or shaderSrc error"); + return PROGRAM_ERROR; + } + GLuint shader; shader = glCreateShader(type); if (0 == shader) { - OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "glCreateShader ===> unable to load shader"); - return 0; + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "glCreateShader unable to load shader"); + return PROGRAM_ERROR; } + // The gl function has no return value. glShaderSource(shader, 1, &shaderSrc, nullptr); glCompileShader(shader); + GLint compiled; glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); - if (!compiled) { - GLint infoLen = 0; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); - if (infoLen > 1) { - char *infoLog = (char *)malloc(sizeof(char) * infoLen); - glGetShaderInfoLog(shader, infoLen, nullptr, infoLog); - OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "glCompileShader ===> error = \n%s\n", - infoLog); - free(infoLog); - } + if (0 != compiled) { + return shader; + } + + GLint infoLen = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); + if (1 >= infoLen) { glDeleteShader(shader); - return 0; + return PROGRAM_ERROR; } - return shader; + + char *infoLog = (char *)malloc(sizeof(char) * (infoLen + 1)); + if (nullptr != infoLog) { + memset(infoLog, 0, infoLen + 1); + glGetShaderInfoLog(shader, infoLen, nullptr, infoLog); + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "glCompileShader error = %s", infoLog); + free(infoLog); + infoLog = nullptr; + } + glDeleteShader(shader); + return PROGRAM_ERROR; } GLuint EGLCore::CreateProgram(const char *vertexShader, const char *fragShader) { + if ((nullptr == vertexShader) || (nullptr == fragShader)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", + "createProgram: vertexShader or fragShader is null"); + return PROGRAM_ERROR; + } + GLuint vertex; vertex = LoadShader(GL_VERTEX_SHADER, vertexShader); - if (0 == vertex) { - OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "createProgram ===> vertex error"); + if (PROGRAM_ERROR == vertex) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "createProgram vertex error"); return PROGRAM_ERROR; } GLuint fragment; fragment = LoadShader(GL_FRAGMENT_SHADER, fragShader); - if (0 == fragment) { - OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "createProgram ===> fragment error"); - glDeleteShader(vertex); + if (PROGRAM_ERROR == fragment) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "createProgram fragment error"); return PROGRAM_ERROR; } GLuint program; program = glCreateProgram(); - if (0 == program) { - OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "createProgram ===> program error"); + if (PROGRAM_ERROR == program) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "createProgram program error"); glDeleteShader(vertex); glDeleteShader(fragment); return PROGRAM_ERROR; } + // The gl function has no return value. glAttachShader(program, vertex); glAttachShader(program, fragment); glLinkProgram(program); GLint linked; glGetProgramiv(program, GL_LINK_STATUS, &linked); - if (!linked) { - OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "createProgram ===> linked error"); - GLint infoLen = 0; - glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen); - if (infoLen > 1) { - char *infoLog = (char *)malloc(sizeof(char) * infoLen); - glGetProgramInfoLog(program, infoLen, nullptr, infoLog); - OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "glLinkProgram ===> error = \n%s\n", infoLog); - free(infoLog); - } + if (0 != linked) { glDeleteShader(vertex); glDeleteShader(fragment); - glDeleteProgram(program); - return PROGRAM_ERROR; + return program; + } + + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "createProgram linked error"); + GLint infoLen = 0; + glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen); + if (1 < infoLen) { + char *infoLog = (char *)malloc(sizeof(char) * (infoLen + 1)); + memset(infoLog, 0, infoLen + 1); + glGetProgramInfoLog(program, infoLen, nullptr, infoLog); + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "glLinkProgram error = %s", infoLog); + free(infoLog); + infoLog = nullptr; } glDeleteShader(vertex); glDeleteShader(fragment); - return program; + glDeleteProgram(program); + return PROGRAM_ERROR; } void EGLCore::Release() { - eglDestroySurface(m_eglDisplay, m_eglSurface); - eglDestroyContext(m_eglDisplay, m_eglContext); - eglTerminate(m_eglDisplay); + if ((nullptr == m_eglDisplay) || (nullptr == m_eglSurface) || (!eglDestroySurface(m_eglDisplay, m_eglSurface))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Release eglDestroySurface failed"); + } + + if ((nullptr == m_eglDisplay) || (nullptr == m_eglContext) || (!eglDestroyContext(m_eglDisplay, m_eglContext))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Release eglDestroyContext failed"); + } + + if ((nullptr == m_eglDisplay) || (!eglTerminate(m_eglDisplay))) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "EGLCore", "Release eglTerminate failed"); + } } \ No newline at end of file diff --git a/NativeAPI/XComponent/entry/src/main/cpp/render/egl_core.h b/NativeAPI/XComponent/entry/src/main/cpp/render/egl_core.h index 6a5c38717d3c3b793ab20fe36239a0bac6b6a2c1..912bf05f08c34fff38eebbfba0106ba6c4da4118 100644 --- a/NativeAPI/XComponent/entry/src/main/cpp/render/egl_core.h +++ b/NativeAPI/XComponent/entry/src/main/cpp/render/egl_core.h @@ -15,8 +15,6 @@ #ifndef EGL_CORE_H #define EGL_CORE_H -#include - #include #include #include @@ -25,7 +23,8 @@ class EGLCore { public: explicit EGLCore(){}; ~EGLCore() {} - void EglContextInit(void *window, int width, int height); + bool EglContextInit(void *window, int width, int height); + bool CreateEnvironment(); void Draw(); void Background(); void ChangeColor(); @@ -35,8 +34,8 @@ private: GLuint LoadShader(GLenum type, const char *shaderSrc); GLuint CreateProgram(const char *vertexShader, const char *fragShader); GLint PrepareDraw(); - void ExecuteDraw(GLint positionHandle, const GLfloat *color, const GLfloat rectangleVertices[]); - void FinishDraw(); + bool ExecuteDraw(GLint position, const GLfloat *color, const GLfloat rectangleVertices[], unsigned long vertSize); + bool FinishDraw(); private: EGLNativeWindowType m_eglWindow; @@ -44,7 +43,7 @@ private: EGLConfig m_eglConfig = EGL_NO_CONFIG_KHR; EGLSurface m_eglSurface = EGL_NO_SURFACE; EGLContext m_eglContext = EGL_NO_CONTEXT; - GLuint m_programHandle; + GLuint m_program; bool m_flag = false; int m_width; int m_height; diff --git a/NativeAPI/XComponent/entry/src/main/cpp/render/plugin_render.cpp b/NativeAPI/XComponent/entry/src/main/cpp/render/plugin_render.cpp index 8c7c4c73c6669cd313051156e24ba9df47aae84b..0a1c24771080e22b5bb05ed5d9361e316463af5e 100644 --- a/NativeAPI/XComponent/entry/src/main/cpp/render/plugin_render.cpp +++ b/NativeAPI/XComponent/entry/src/main/cpp/render/plugin_render.cpp @@ -29,8 +29,13 @@ OH_NativeXComponent_Callback PluginRender::m_callback; void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window) { OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "OnSurfaceCreatedCB"); + if ((nullptr == component) || (nullptr == window)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", + "OnSurfaceCreatedCB: component or window is null"); + return; + } - char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' }; uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; if (OH_NATIVEXCOMPONENT_RESULT_SUCCESS != OH_NativeXComponent_GetXComponentId(component, idStr, &idSize)) { OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", @@ -43,17 +48,23 @@ void OnSurfaceCreatedCB(OH_NativeXComponent *component, void *window) uint64_t width; uint64_t height; int32_t xSize = OH_NativeXComponent_GetXComponentSize(component, window, &width, &height); - if (OH_NATIVEXCOMPONENT_RESULT_SUCCESS == xSize && nullptr != render) { - render->m_eglCore->EglContextInit(window, width, height); - render->m_eglCore->Background(); + if ((OH_NATIVEXCOMPONENT_RESULT_SUCCESS == xSize) && (nullptr != render)) { + if (render->m_eglCore->EglContextInit(window, width, height)) { + render->m_eglCore->Background(); + } } } void OnSurfaceChangedCB(OH_NativeXComponent *component, void *window) { OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "OnSurfaceChangedCB"); + if ((nullptr == component) || (nullptr == window)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", + "OnSurfaceChangedCB: component or window is null"); + return; + } - char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' }; uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; if (OH_NATIVEXCOMPONENT_RESULT_SUCCESS != OH_NativeXComponent_GetXComponentId(component, idStr, &idSize)) { OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", @@ -64,15 +75,20 @@ void OnSurfaceChangedCB(OH_NativeXComponent *component, void *window) std::string id(idStr); auto render = PluginRender::GetInstance(id); if (nullptr != render) { - // do something + OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "surface changed"); } } void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window) { OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "OnSurfaceDestroyedCB"); + if ((nullptr == component) || (nullptr == window)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", + "OnSurfaceDestroyedCB: component or window is null"); + return; + } - char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' }; uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; if (OH_NATIVEXCOMPONENT_RESULT_SUCCESS != OH_NativeXComponent_GetXComponentId(component, idStr, &idSize)) { OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", @@ -81,18 +97,19 @@ void OnSurfaceDestroyedCB(OH_NativeXComponent *component, void *window) } std::string id(idStr); - auto render = PluginRender::GetInstance(id); - if (nullptr != render) { - // do something - render->ReleaseEgl(); - } + PluginRender::Release(id); } void DispatchTouchEventCB(OH_NativeXComponent *component, void *window) { OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "Callback", "DispatchTouchEventCB"); + if ((nullptr == component) || (nullptr == window)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", + "DispatchTouchEventCB: component or window is null"); + return; + } - char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' }; uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; if (OH_NATIVEXCOMPONENT_RESULT_SUCCESS != OH_NativeXComponent_GetXComponentId(component, idStr, &idSize)) { OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "Callback", @@ -101,7 +118,7 @@ void DispatchTouchEventCB(OH_NativeXComponent *component, void *window) } std::string id(idStr); - auto render = PluginRender::GetInstance(id); + PluginRender *render = PluginRender::GetInstance(id); if (nullptr != render) { render->m_eglCore->ChangeColor(); } @@ -111,7 +128,7 @@ PluginRender::PluginRender(std::string &id) { this->m_id = id; this->m_eglCore = new EGLCore(); - auto renderCallback = &PluginRender::m_callback; + OH_NativeXComponent_Callback *renderCallback = &PluginRender::m_callback; renderCallback->OnSurfaceCreated = OnSurfaceCreatedCB; renderCallback->OnSurfaceChanged = OnSurfaceChangedCB; renderCallback->OnSurfaceDestroyed = OnSurfaceDestroyedCB; @@ -129,18 +146,29 @@ PluginRender *PluginRender::GetInstance(std::string &id) } } -napi_value PluginRender::Export(napi_env env, napi_value exports) +void PluginRender::Export(napi_env env, napi_value exports) { + if ((nullptr == env) || (nullptr == exports)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender", "Export: env or exports is null"); + return; + } + napi_property_descriptor desc[] = { { "drawRectangle", nullptr, PluginRender::NapiDrawRectangle, nullptr, nullptr, nullptr, napi_default, nullptr } }; - napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); - return exports; + if (napi_ok != napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender", "Export: napi_define_properties failed"); + } } +// NAPI registration method type napi_callback. If no value is returned, nullptr is returned. napi_value PluginRender::NapiDrawRectangle(napi_env env, napi_callback_info info) { OH_LOG_Print(LOG_APP, LOG_INFO, LOG_PRINT_DOMAIN, "PluginRender", "NapiDrawRectangle"); + if ((nullptr == env) || (nullptr == info)) { + OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender", "NapiDrawRectangle: env or info is null"); + return nullptr; + } napi_value thisArg; if (napi_ok != napi_get_cb_info(env, info, nullptr, nullptr, &thisArg, nullptr)) { @@ -161,7 +189,7 @@ napi_value PluginRender::NapiDrawRectangle(napi_env env, napi_callback_info info return nullptr; } - char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; + char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { '\0' }; uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; if (OH_NATIVEXCOMPONENT_RESULT_SUCCESS != OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize)) { OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "PluginRender", @@ -178,13 +206,15 @@ napi_value PluginRender::NapiDrawRectangle(napi_env env, napi_callback_info info return nullptr; } -PluginRender *PluginRender::ReleaseEgl() +void PluginRender::Release(std::string &id) { - char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; - std::string id(idStr); PluginRender *render = PluginRender::GetInstance(id); if (nullptr != render) { render->m_eglCore->Release(); + delete render->m_eglCore; + render->m_eglCore = nullptr; + delete render; + render = nullptr; + m_instance.erase(m_instance.find(id)); } - return nullptr; -} +} \ No newline at end of file diff --git a/NativeAPI/XComponent/entry/src/main/cpp/render/plugin_render.h b/NativeAPI/XComponent/entry/src/main/cpp/render/plugin_render.h index 75ca811171b61cfef2f52dee37ea50ab5ad628f2..954f5caf99253dda6358ccbe8147cf984c9e457b 100644 --- a/NativeAPI/XComponent/entry/src/main/cpp/render/plugin_render.h +++ b/NativeAPI/XComponent/entry/src/main/cpp/render/plugin_render.h @@ -25,11 +25,18 @@ class PluginRender { public: explicit PluginRender(std::string &id); - ~PluginRender() {} + ~PluginRender() + { + if (nullptr != m_eglCore) { + m_eglCore->Release(); + delete m_eglCore; + m_eglCore = nullptr; + } + } static PluginRender *GetInstance(std::string &id); - static PluginRender *ReleaseEgl(); + static void Release(std::string &id); static napi_value NapiDrawRectangle(napi_env env, napi_callback_info info); - napi_value Export(napi_env env, napi_value exports); + void Export(napi_env env, napi_value exports); public: static std::unordered_map m_instance; diff --git a/NativeAPI/XComponent/entry/src/main/ets/entryability/EntryAbility.ts b/NativeAPI/XComponent/entry/src/main/ets/entryability/EntryAbility.ts index 2b5ac7953c661a2c9292e69b9b0eab7b18745662..d9a7365315aadb6973c64a8439d6d9af3db26e7e 100644 --- a/NativeAPI/XComponent/entry/src/main/ets/entryability/EntryAbility.ts +++ b/NativeAPI/XComponent/entry/src/main/ets/entryability/EntryAbility.ts @@ -20,7 +20,7 @@ import nativerender from 'libnativerender.so'; export enum ContextType { APP_LIFECYCLE, - JSPAGE_LIFECYCLE, + PAGE_LIFECYCLE, } const nativeAppLifecycle = nativerender.getContext(ContextType.APP_LIFECYCLE); diff --git a/NativeAPI/XComponent/entry/src/main/ets/pages/Index.ets b/NativeAPI/XComponent/entry/src/main/ets/pages/Index.ets index e98564859b8624c7dffd5c3d45da1fa853e7d9b9..a366a30c1368f4d3572e260645fa6bcea6d50f2c 100644 --- a/NativeAPI/XComponent/entry/src/main/ets/pages/Index.ets +++ b/NativeAPI/XComponent/entry/src/main/ets/pages/Index.ets @@ -17,7 +17,7 @@ import nativeRender from 'libnativerender.so'; import { ContextType } from '../entryability/EntryAbility'; import CommonConstants from '../common/CommonConstants'; -const nativePageLifecycle = nativeRender.getContext(ContextType.JSPAGE_LIFECYCLE); +const nativePageLifecycle = nativeRender.getContext(ContextType.PAGE_LIFECYCLE); @Entry @Component