#盲盒+码# #跟着小白一起学鸿蒙#HAP应用调用so库方法 原创 精华

左翼风发
发布于 2022-12-8 10:58
浏览
3收藏

作者:王石

概述

在《[#跟着小白一起学鸿蒙# 七] 写个NAPI子系统》的文章里我们熟悉了如何用NAPI框架实现一个HAP应用的业务接口,但是这只是OpenHarmony提供的一种实现方式。在ETS的框架接口里OpenHarmony提供了一种更方便快捷的方式就是利用XComponent组件和NDK的方式快速进行业务层逻辑实现和动态库(so)的调用。

XComponent组件

参考文档链接:https://developer.harmonyos.com/cn/docs/documentation/doc-references/ts-basic-components-xcomponent-0000001333800561

  1. 接口

    XComponent(value: {id: string, type: string, libraryname?: string, controller?: XComponentController})

    参数:

    参数名 参数类型 必填 描述
    id string 组件的唯一标识,支持最大的字符串长度128。
    type string 用于指定XComponent组件类型,可选值为: -surface:组件内容单独送显,直接合成到屏幕。 -component:组件内容与其他组件合成后统一送显。
    libraryname string 应用Native层编译输出动态库名称。
    controller XComponentcontroller 给组件绑定一个控制器,通过控制器调用组件方法。
  2. 事件

    • 插件加载完毕后的回调事件(onLoad):onLoad(callback: (event?: object) => void )

      参数:

      参数名 参数类型 必填 描述
      event object 获取XComponent实例对象的context,context上挂载的方法由开发者在c++层定义。
    • 插件卸载完毕后的回调(onDestroy):onDestroy(event: () => void )

  3. 获取C++实例对象接口

    getXComponentContext()

    返回值:

    类型 描述
    Object 获取XComponent实例对象的context,context包含的具体接口方法由开发者自定义。

样例开发

  1. 应用层开发

    和一般的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%')
      }
    }
    
    1. 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

©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
6
收藏 3
回复
举报
6条回复
按时间正序
/
按时间倒序
红叶亦知秋
红叶亦知秋

直接调用接口还是更方便些

回复
2022-12-8 11:46:21
麻辣香锅配馒头
麻辣香锅配馒头

结尾链接中的三角形渲染也很不错

回复
2022-12-8 14:15:57
喝一大口可乐
喝一大口可乐

很完整的开发样例

回复
2022-12-9 11:28:07
笨笨的婧婧
笨笨的婧婧

Component组件只能在C++使用吗

回复
2022-12-9 18:40:29
左翼风发
左翼风发 回复了 笨笨的婧婧
Component组件只能在C++使用吗

xcomponent组件有很多用法,调用c++库只是一种方式,

回复
2022-12-10 18:05:07
wx64bf91cbe46c5
wx64bf91cbe46c5

请教个问题:

render目录中egl_core.cpp中,

bool EGLCore::EglContextInit(void *window, int width, int height)

中,为什么如下代码有红色标签:

我点

EGLNativeWindowType

,连接到如下图的地方,是不是不对?这个是我原样拷贝的。

不过若不看拷贝,直接在这个附件的代码里看又是好的,且点击EGLNativeWindowType链接到如下图的地方。这个是我哪里设置不对吗?


点击EGLNativeWindowType是指点击render目录下的egl_core.h中的如下代码:

已于2023-8-31 23:02:48修改
回复
2023-8-31 23:00:19
回复
    相关推荐