跟着小白一起学鸿蒙—HAP应用调用SO库方法
作者:王石 2022-12-09 15:34:38系统 OpenHarmony 在ETS的框架接口里OpenHarmony提供了一种更方便快捷的方式就是利用XComponent组件和NDK的方式快速进行业务层逻辑实现和动态库(so)的调用。
想了解更多关于开源的内容,请访问:
51CTO开源基础软件社区
https://ost.51cto.com
概述
在《[#跟着小白一起学鸿蒙# 七] 写个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@Componentstruct 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 SHAREDrender/egl_core.cpprender/plugin_render.cppplugin_manager.cppnapi/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
#include#include#include#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(&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(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#include "plugin_render.h"#include "plugin_common.h"#include "plugin_manager.h"#ifdef __cplusplusextern "C" {#endifstd::unordered_map 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(&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(&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(&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 #includeEGLConfig 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(window);// 1. create sharedcontextmEGLDisplay = 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 WindowEGLint 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 fromint 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。
想了解更多关于开源的内容,请访问:
51CTO开源基础软件社区
https://ost.51cto.com。
责任编辑:jianghua 来源:51CTO 开源基础软件社区 鸿蒙HAP应用调用