作者:王石
概述
在《[#跟着小白一起学鸿蒙# 七] 写个NAPI子系统》的文章里我们熟悉了如何用NAPI框架实现一个HAP应用的业务接口,但是这只是OpenHarmony提供的一种实现方式。在ETS的框架接口里OpenHarmony提供了一种更方便快捷的方式就是利用XComponent组件和NDK的方式快速进行业务层逻辑实现和动态库(so)的调用。
XComponent组件
参考文档链接:https://developer.harmonyos.com/cn/docs/documentation/doc-references/ts-basic-components-xcomponent-0000001333800561
-
接口
XComponent(value: {id: string, type: string, libraryname?: string, controller?: XComponentController})
参数:
参数名 参数类型 必填 描述 id string 是 组件的唯一标识,支持最大的字符串长度128。 type string 是 用于指定XComponent组件类型,可选值为: -surface:组件内容单独送显,直接合成到屏幕。 -component:组件内容与其他组件合成后统一送显。 libraryname string 否 应用Native层编译输出动态库名称。 controller XComponentcontroller 否 给组件绑定一个控制器,通过控制器调用组件方法。 -
事件
-
插件加载完毕后的回调事件(onLoad):onLoad(callback: (event?: object) => void )
参数:
参数名 参数类型 必填 描述 event object 否 获取XComponent实例对象的context,context上挂载的方法由开发者在c++层定义。 -
插件卸载完毕后的回调(onDestroy):onDestroy(event: () => void )
-
-
获取C++实例对象接口
getXComponentContext()
返回值:
类型 描述 Object 获取XComponent实例对象的context,context包含的具体接口方法由开发者自定义。
样例开发
-
应用层开发
和一般的HAP应用开发一样基于ets的页面开发,代码如下:
import nativerender from "libnativerender.so"; import { ContextType } from "../common/Constants" const nativePageLifecycle = nativerender.getContext(ContextType.JSPAGE_LIFECYCLE); @Entry @Component struct Index { private context = null; aboutToAppear() { console.log('[LIFECYCLE-Index] aboutToAppear'); nativePageLifecycle.aboutToAppear(); } aboutToDisappear() { console.log('[LIFECYCLE-Index] aboutToDisappear'); nativePageLifecycle.aboutToDisappear(); } onPageShow() { console.log('[LIFECYCLE-Page] onPageShow'); nativePageLifecycle.onPageShow(); } onPageHide() { console.log('[LIFECYCLE-Page] onPageHide'); nativePageLifecycle.onPageHide(); } build() { Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { Button('ChangeColor') .onClick(() => { if (this.context) { this.context.changeColor(); } }) .width(200) .height(80) Button('ChangeShape') .onClick(() => { if (this.context) { this.context.changeShape(); } }) .width(200) .height(80) XComponent({ id: 'xcomponentId', type: 'texture', libraryname: 'nativerender'}) .onLoad((context) => { this.context = context; }) .onDestroy(() => { }) } .width('100%') .height('100%') } }
- CPP层开发
-
编写CMakeList:
# the minimum version of CMake. cmake_minimum_required(VERSION 3.4.1) project(XComponent) set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR}) add_definitions(-DOHOS_PLATFORM) include_directories(${NATIVERENDER_ROOT_PATH} ${NATIVERENDER_ROOT_PATH}/common ${NATIVERENDER_ROOT_PATH}/napi ${NATIVERENDER_ROOT_PATH}/render ) add_library(nativerender SHARED render/egl_core.cpp render/plugin_render.cpp plugin_manager.cpp napi/napi_init.cpp ) find_library( # Sets the name of the path variable. EGL-lib # Specifies the name of the NDK library that # you want CMake to locate. EGL ) find_library( # Sets the name of the path variable. GLES-lib # Specifies the name of the NDK library that # you want CMake to locate. GLESv3 ) 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 ) find_library( # Sets the name of the path variable. libace-lib # Specifies the name of the NDK library that # you want CMake to locate. ace_ndk.z ) find_library( # Sets the name of the path variable. libnapi-lib # Specifies the name of the NDK library that # you want CMake to locate. ace_napi.z ) find_library( # Sets the name of the path variable. libuv-lib # Specifies the name of the NDK library that # you want CMake to locate. uv ) target_link_libraries(nativerender PUBLIC ${EGL-lib} ${GLES-lib} ${hilog-lib} ${libace-lib} ${libnapi-lib} ${libuv-lib} libc++.
-
NAPI接口:
#include "plugin_common.h" #include "plugin_manager.h" /* * function for module exports */ static napi_value Init(napi_env env, napi_value exports) { LOGE("Init"); napi_property_descriptor desc[] ={ DECLARE_NAPI_FUNCTION("getContext", PluginManager::GetContext), }; NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); bool ret = PluginManager::GetInstance()->Export(env, exports); if (!ret) { LOGE("Init failed"); } return exports; } /* * Napi Module define */ static napi_module nativerenderModule = { .nm_version = 1, .nm_flags = 0, .nm_filename = nullptr, .nm_register_func = Init, .nm_modname = "nativerender", .nm_priv = ((void*)0), .reserved = { 0 }, }; /* * Module register function */ extern "C" __attribute__((constructor)) void RegisterModule(void) { napi_module_register(&nativerenderModule); }
-
XComponent框架适配:
#include <stdint.h> #include <string> #include <stdio.h> #include <ace/xcomponent/native_interface_xcomponent.h> #include "plugin_manager.h" #include "plugin_common.h" enum ContextType { APP_LIFECYCLE = 0, JS_PAGE_LIFECYCLE, }; PluginManager PluginManager::manager_; napi_value PluginManager::GetContext(napi_env env, napi_callback_info info) { napi_status status; napi_value exports; size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)); if (argc != 1) { napi_throw_type_error(env, NULL, "Wrong number of arguments"); return nullptr; } napi_valuetype valuetype; status = napi_typeof(env, args[0], &valuetype); if (status != napi_ok) { return nullptr; } if (valuetype != napi_number) { napi_throw_type_error(env, NULL, "Wrong arguments"); return nullptr; } int64_t value; NAPI_CALL(env, napi_get_value_int64(env, args[0], &value)); NAPI_CALL(env, napi_create_object(env, &exports)); switch (value) { case APP_LIFECYCLE: { /**** AppInit 对应 app.ets中的应用生命周期 onCreate, onShow, onHide, onDestroy ******/ LOGD("GetContext APP_LIFECYCLE"); /**** Register App Lifecycle ******/ napi_property_descriptor desc[] = { DECLARE_NAPI_FUNCTION("onCreate", PluginManager::NapiOnCreate), DECLARE_NAPI_FUNCTION("onShow", PluginManager::NapiOnShow), DECLARE_NAPI_FUNCTION("onHide", PluginManager::NapiOnHide), DECLARE_NAPI_FUNCTION("onDestroy", PluginManager::NapiOnDestroy), }; NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); } break; case JS_PAGE_LIFECYCLE: { /**************** 声明式开发范式 JS Page 生命周期注册 ****************************/ LOGD("GetContext JS_PAGE_LIFECYCLE"); napi_property_descriptor desc[] = { DECLARE_NAPI_FUNCTION("onPageShow", PluginManager::NapiOnPageShow), DECLARE_NAPI_FUNCTION("onPageHide", PluginManager::NapiOnPageHide), }; NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); } break; default: LOGE("unknown type"); } return exports; } bool PluginManager::Export(napi_env env, napi_value exports) { napi_status status; napi_value exportInstance = nullptr; OH_NativeXComponent *nativeXComponent = nullptr; int32_t ret; char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = { }; uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; status = napi_get_named_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance); if (status != napi_ok) { return false; } status = napi_unwrap(env, exportInstance, reinterpret_cast<void**>(&nativeXComponent)); if (status != napi_ok) { return false; } ret = OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize); if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { return false; } std::string id(idStr); auto context = PluginManager::GetInstance(); if (context) { context->SetNativeXComponent(id, nativeXComponent); auto render = context->GetRender(id); render->SetNativeXComponent(nativeXComponent); render->Export(env, exports); return true; } return false; } void PluginManager::SetNativeXComponent(std::string& id, OH_NativeXComponent* nativeXComponent) { if (nativeXComponentMap_.find(id) == nativeXComponentMap_.end()) { nativeXComponentMap_[id] = nativeXComponent; } else { if (nativeXComponentMap_[id] != nativeXComponent) { nativeXComponentMap_[id] = nativeXComponent; } } } OH_NativeXComponent* PluginManager::GetNativeXComponent(std::string& id) { if (nativeXComponentMap_.find(id) == nativeXComponentMap_.end()) { return nullptr; } else { return nativeXComponentMap_[id]; } } PluginRender* PluginManager::GetRender(std::string& id) { if (pluginRenderMap_.find(id) == pluginRenderMap_.end()) { PluginRender* instance = PluginRender::GetInstance(id); pluginRenderMap_[id] = instance; return instance; } else { return pluginRenderMap_[id]; } } void PluginManager::MainOnMessage(const uv_async_t* req) { LOGD("MainOnMessage Triggered"); } napi_value PluginManager::NapiOnCreate(napi_env env, napi_callback_info info) { LOGD("PluginManager::NapiOnCreate"); uv_loop_t* loop = nullptr; uv_check_t* check = new uv_check_t; NAPI_CALL(env, napi_get_uv_event_loop(env, &loop)); PluginManager::GetInstance()->OnCreateNative(env, loop); return nullptr; } napi_value PluginManager::NapiOnShow(napi_env env, napi_callback_info info) { PluginManager::GetInstance()->OnShowNative(); return nullptr; } napi_value PluginManager::NapiOnHide(napi_env env, napi_callback_info info) { PluginManager::GetInstance()->OnHideNative(); return nullptr; } napi_value PluginManager::NapiOnDestroy(napi_env env, napi_callback_info info) { PluginManager::GetInstance()->OnDestroyNative(); return nullptr; } void PluginManager::OnCreateNative(napi_env env, uv_loop_t* loop) { mainEnv_ = env; mainLoop_ = loop; if (mainLoop_) { uv_async_init(mainLoop_, &mainOnMessageSignal_, reinterpret_cast<uv_async_cb>(PluginManager::MainOnMessage)); } } void PluginManager::OnShowNative() { LOGD("PluginManager::OnShowNative"); } void PluginManager::OnHideNative() { LOGD("PluginManager::OnHideNative"); } void PluginManager::OnDestroyNative() { LOGD("PluginManager::OnDestroyNative"); } napi_value PluginManager::NapiOnPageShow(napi_env env, napi_callback_info info) { LOGD("PluginManager::NapiOnPageShow"); return nullptr; } napi_value PluginManager::NapiOnPageHide(napi_env env, napi_callback_info info) { LOGD("PluginManager::NapiOnPageHide"); return nullptr; } void PluginManager::OnPageShowNative() { LOGD("PluginManager::OnPageShowNative"); } void PluginManager::OnPageHideNative() { LOGD("PluginManager::OnPageHideNative"); }
-
界面渲染适配
#include <stdint.h> #include "plugin_render.h" #include "plugin_common.h" #include "plugin_manager.h" #ifdef __cplusplus extern "C" { #endif std::unordered_map<std::string, PluginRender*> PluginRender::instance_; OH_NativeXComponent_Callback PluginRender::callback_; void OnSurfaceCreatedCB(OH_NativeXComponent* component, void* window) { LOGD("OnSurfaceCreatedCB"); int32_t ret; char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize); if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { return; } std::string id(idStr); auto render = PluginRender::GetInstance(id); render->OnSurfaceCreated(component, window); } void OnSurfaceChangedCB(OH_NativeXComponent* component, void* window) { int32_t ret; char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize); if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { return; } std::string id(idStr); auto render = PluginRender::GetInstance(id); render->OnSurfaceChanged(component, window); } void OnSurfaceDestroyedCB(OH_NativeXComponent* component, void* window) { int32_t ret; char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize); if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { return; } std::string id(idStr); auto render = PluginRender::GetInstance(id); render->OnSurfaceDestroyed(component, window); } void DispatchTouchEventCB(OH_NativeXComponent* component, void* window) { LOGD("DispatchTouchEventCB"); int32_t ret; char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; ret = OH_NativeXComponent_GetXComponentId(component, idStr, &idSize); if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { return; } std::string id(idStr); auto render = PluginRender::GetInstance(id); render->DispatchTouchEvent(component, window); } PluginRender::PluginRender(std::string& id) : id_(id), component_(nullptr) { eglCore_ = new EGLCore(id); auto renderCallback = PluginRender::GetNXComponentCallback(); renderCallback->OnSurfaceCreated = OnSurfaceCreatedCB; renderCallback->OnSurfaceChanged = OnSurfaceChangedCB; renderCallback->OnSurfaceDestroyed = OnSurfaceDestroyedCB; renderCallback->DispatchTouchEvent = DispatchTouchEventCB; } PluginRender* PluginRender::GetInstance(std::string& id) { if (instance_.find(id) == instance_.end()) { PluginRender* instance = new PluginRender(id); instance_[id] = instance; return instance; } else { return instance_[id]; } } OH_NativeXComponent_Callback* PluginRender::GetNXComponentCallback() { return &PluginRender::callback_; } void PluginRender::SetNativeXComponent(OH_NativeXComponent* component) { component_ = component; OH_NativeXComponent_RegisterCallback(component_, &PluginRender::callback_); } void PluginRender::OnSurfaceCreated(OH_NativeXComponent* component, void* window) { LOGD("PluginRender::OnSurfaceCreated"); int32_t ret=OH_NativeXComponent_GetXComponentSize(component, window, &width_, &height_); if (ret == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { eglCore_->GLContextInit(window, width_, height_); } } void PluginRender::OnSurfaceChanged(OH_NativeXComponent* component, void* window) { } void PluginRender::OnSurfaceDestroyed(OH_NativeXComponent* component, void* window) { } void PluginRender::DispatchTouchEvent(OH_NativeXComponent* component, void* window) { int32_t ret = OH_NativeXComponent_GetTouchEvent(component, window, &touchEvent_); if (ret == OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { LOGD("Touch Info : x = %{public}f, y = %{public}f screenx = %{public}f, screeny = %{public}f", touchEvent_.x, touchEvent_.y, touchEvent_.screenX, touchEvent_.screenY); for (int i=0;i<touchEvent_.numPoints;i++) { LOGE("Touch Info : dots[%{public}d] id %{public}d x = %{public}f, y = %{public}f", i, touchEvent_.touchPoints[i].id, touchEvent_.touchPoints[i].x, touchEvent_.touchPoints[i].y); LOGE("Touch Info : screenx = %{public}f, screeny = %{public}f", touchEvent_.touchPoints[i].screenX, touchEvent_.touchPoints[i].screenY); LOGE("vtimeStamp = %{public}llu, isPressed = %{public}d", touchEvent_.touchPoints[i].timeStamp, touchEvent_.touchPoints[i].isPressed); } } else { LOGE("Touch fail"); } } napi_value PluginRender::Export(napi_env env, napi_value exports) { LOGE("PluginRender::Export"); // Register JS API napi_property_descriptor desc[] = { DECLARE_NAPI_FUNCTION("changeShape", PluginRender::NapiChangeShape), DECLARE_NAPI_FUNCTION("drawTriangle", PluginRender::NapiDrawTriangle), DECLARE_NAPI_FUNCTION("changeColor", PluginRender::NapiChangeColor), }; NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc)); return exports; } napi_value PluginRender::NapiChangeShape(napi_env env, napi_callback_info info) { LOGD("NapiChangeShape"); napi_value exportInstance; napi_value thisArg; napi_status status; OH_NativeXComponent *nativeXComponent = nullptr; int32_t ret; char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; // napi_value thisArg; NAPI_CALL(env, napi_get_cb_info(env, info, NULL, NULL, &thisArg, NULL)); status = napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance); if (status != napi_ok) { return nullptr; }; status = napi_unwrap(env, exportInstance, reinterpret_cast<void**>(&nativeXComponent)); if (status != napi_ok) { return nullptr; } ret = OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize); if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { return nullptr; } std::string id(idStr); PluginRender* instance = PluginRender::GetInstance(id); if (instance) { instance->eglCore_->ChangeShape(); } return nullptr; } napi_value PluginRender::NapiDrawTriangle(napi_env env, napi_callback_info info) { LOGD("NapiDrawTriangle"); napi_value exportInstance; napi_value thisArg; napi_status status; OH_NativeXComponent *nativeXComponent = nullptr; int32_t ret; char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; // napi_value thisArg; NAPI_CALL(env, napi_get_cb_info(env, info, NULL, NULL, &thisArg, NULL)); status = napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance); if (status != napi_ok) { return nullptr; }; status = napi_unwrap(env, exportInstance, reinterpret_cast<void**>(&nativeXComponent)); if (status != napi_ok) { return nullptr; } ret = OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize); if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { return nullptr; } std::string id(idStr); PluginRender* instance = PluginRender::GetInstance(id); if (instance) { instance->eglCore_->DrawTriangle(); } return nullptr; } napi_value PluginRender::NapiChangeColor(napi_env env, napi_callback_info info) { LOGD("NapiChangeColor"); napi_value exportInstance; napi_value thisArg; napi_status status; OH_NativeXComponent *nativeXComponent = nullptr; int32_t ret; char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {}; uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1; // napi_value thisArg; NAPI_CALL(env, napi_get_cb_info(env, info, NULL, NULL, &thisArg, NULL)); status = napi_get_named_property(env, thisArg, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance); if (status != napi_ok) { return nullptr; } status = napi_unwrap(env, exportInstance, reinterpret_cast<void**>(&nativeXComponent)); if (status != napi_ok) { return nullptr; } ret = OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize); if (ret != OH_NATIVEXCOMPONENT_RESULT_SUCCESS) { return nullptr; } std::string id(idStr); PluginRender* instance = PluginRender::GetInstance(id); if (instance) { instance->eglCore_->ChangeColor(); } return nullptr; } #ifdef __cplusplus } #endif
-
业务逻辑适配
#include "egl_core.h" #include "plugin_common.h" #include "plugin_render.h" #include <EGL/egl.h> #include <GLES3/gl3.h> EGLConfig getConfig(int version, EGLDisplay eglDisplay) { int attribList[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_ALPHA_SIZE, 8, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE }; EGLConfig configs = NULL; int configsNum; if (!eglChooseConfig(eglDisplay, attribList, &configs, 1, &configsNum)) { LOGE("eglChooseConfig ERROR"); return NULL; } return configs; } char vertexShader[] = "#version 300 es\n" "layout(location = 0) in vec4 a_position;\n" "layout(location = 1) in vec4 a_color;\n" "out vec4 v_color;\n" "void main()\n" "{\n" " gl_Position = a_position;\n" " v_color = a_color;\n" "}\n"; char fragmentShader[] = "#version 300 es\n" "precision mediump float;\n" "in vec4 v_color;\n" "out vec4 fragColor;\n" "void main()\n" "{\n" " fragColor = v_color;\n" "}\n"; void EGLCore::GLContextInit(void* window, int w, int h) { LOGD("EGLCore::GLContextInit window = %{public}p, w = %{public}d, h = %{public}d.", window, w, h); width_ = w; height_ = h; mEglWindow = static_cast<EGLNativeWindowType>(window); // 1. create sharedcontext mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); if (mEGLDisplay == EGL_NO_DISPLAY) { LOGE("EGLCore::unable to get EGL display."); return; } EGLint eglMajVers, eglMinVers; if (!eglInitialize(mEGLDisplay, &eglMajVers, &eglMinVers)) { mEGLDisplay = EGL_NO_DISPLAY; LOGE("EGLCore::unable to initialize display"); return; } mEGLConfig = getConfig(3, mEGLDisplay); if (mEGLConfig == nullptr) { LOGE("EGLCore::GLContextInit config ERROR"); return; } // 2. Create EGL Surface from Native Window EGLint winAttribs[] = {EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR, EGL_NONE}; if (mEglWindow) { mEGLSurface = eglCreateWindowSurface(mEGLDisplay, mEGLConfig, mEglWindow, winAttribs); if (mEGLSurface == nullptr) { LOGE("EGLCore::eglCreateContext eglSurface is null"); return; } } // 3. Create EGLContext from int attrib3_list[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; mEGLContext = eglCreateContext(mEGLDisplay, mEGLConfig, mSharedEGLContext, attrib3_list); if (!eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext)) { LOGE("EGLCore::eglMakeCurrent error = %{public}d", eglGetError()); } mProgramHandle = CreateProgram(vertexShader, fragmentShader); if (!mProgramHandle) { LOGE("EGLCore::Could not create CreateProgram"); return; } DrawTriangle(); } void EGLCore::DrawTriangle() { GLfloat color[] = { 0.5f, 0.6f, 0.3f, 1.0f }; const GLfloat triangleVertices[] = { 0.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f }; glViewport(0, 0, width_, height_); glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glUseProgram(mProgramHandle); GLint positionHandle = glGetAttribLocation(mProgramHandle, "a_position"); glVertexAttribPointer(positionHandle, 2, GL_FLOAT, GL_FALSE, 0, triangleVertices); glEnableVertexAttribArray(positionHandle); glVertexAttrib4fv(1, color); glDrawArrays(GL_TRIANGLES, 0, 3); glDisableVertexAttribArray(positionHandle); glFlush(); glFinish(); eglSwapBuffers(mEGLDisplay, mEGLSurface); } void EGLCore::ChangeShape() { if (!eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext)) { LOGE("EGLCore::eglMakeCurrent error = %{public}d", eglGetError()); } GLfloat color[] = { 0.7f, 0.2f, 0.2f, 1.0f }; const GLfloat triangleVertices[] = { -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 0.0f }; glViewport(0, 0, width_, height_); glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glUseProgram(mProgramHandle); GLint positionHandle = glGetAttribLocation(mProgramHandle, "a_position"); glVertexAttribPointer(positionHandle, 2, GL_FLOAT, GL_FALSE, 0, triangleVertices); glEnableVertexAttribArray(positionHandle); glVertexAttrib4fv(1, color); glDrawArrays(GL_TRIANGLES, 0, 3); glDisableVertexAttribArray(positionHandle); Update(); } void EGLCore::ChangeColor() { if (!eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext)) { LOGE("EGLCore::eglMakeCurrent error = %{public}d", eglGetError()); } GLfloat color[] = { 0.9f, 0.5f, 0.7f, 1.0f }; const GLfloat triangleVertices[] = { 0.0f, 1.0f, -1.0f, -1.0f, 1.0f, -1.0f }; glViewport(0, 0, width_, height_); glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glUseProgram(mProgramHandle); GLint positionHandle = glGetAttribLocation(mProgramHandle, "a_position"); glVertexAttribPointer(positionHandle, 2, GL_FLOAT, GL_FALSE, 0, triangleVertices); glEnableVertexAttribArray(positionHandle); glVertexAttrib4fv(1, color); glDrawArrays(GL_TRIANGLES, 0, 3); glDisableVertexAttribArray(positionHandle); Update(); } void EGLCore::Update() { eglSwapBuffers(mEGLDisplay, mEGLSurface); } GLuint EGLCore::LoadShader(GLenum type, const char *shaderSrc) { GLuint shader; GLint compiled; shader = glCreateShader(type); if (shader == 0) { LOGE("LoadShader shader error"); return 0; } glShaderSource(shader, 1, &shaderSrc, nullptr); glCompileShader(shader); 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); LOGE("Error compiling shader:\n%s\n",infoLog); free(infoLog); } glDeleteShader(shader); return 0; } return shader; } GLuint EGLCore::CreateProgram(const char *vertexShader, const char *fragShader) { GLuint vertex; GLuint fragment; GLuint program; GLint linked; vertex = LoadShader(GL_VERTEX_SHADER, vertexShader); if (vertex == 0) { LOGE("CreateProgram vertex error"); return 0; } fragment = LoadShader(GL_FRAGMENT_SHADER, fragShader); if (fragment == 0) { LOGE("CreateProgram fragment error"); glDeleteShader(vertex); return 0; } program = glCreateProgram(); if (program == 0) { LOGE("CreateProgram program error"); glDeleteShader(vertex); glDeleteShader(fragment); return 0; } glAttachShader(program, vertex); glAttachShader(program, fragment); glLinkProgram(program); glGetProgramiv(program, GL_LINK_STATUS, &linked); if (!linked) { LOGE("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); LOGE("Error linking program:\n%s\n",infoLog); free(infoLog); } glDeleteShader(vertex); glDeleteShader(fragment); glDeleteProgram(program); return 0; } glDeleteShader(vertex); glDeleteShader(fragment); return program; } bool EGLCore::checkGlError(const char* op) { LOGE("EGL ERROR CODE = %{public}x", eglGetError()); GLint error; for (error = glGetError(); error; error = glGetError()) { LOGE("ERROR: %{public}s, ERROR CODE = %{public}x", op, error); return true; } return false; }
小结
通过上述方式,我们就能编译并安装运行应用了,上述代码链接在:https://toscode.gitee.com/openharmony/app_samples/tree/master/ETSUI/XComponent
本文作者:左翼风发
https://ost.51cto.com/#bkwz
标签:return,盲盒,OH,so,env,HAP,PluginManager,id,napi From: https://blog.51cto.com/harmonyos/5933913