W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
XComponent組件作為一種繪制組件,通常用于滿足開發(fā)者較為復雜的自定義繪制需求,例如相機預覽流的顯示和游戲畫面的繪制。
其可通過指定其type字段來實現(xiàn)不同的功能,主要有兩個“surface”和“component”字段可供選擇。
對于“surface”類型,開發(fā)者可將相關數(shù)據(jù)傳入XComponent單獨擁有的“NativeWindow”來渲染畫面。
對于“component”類型則主要用于實現(xiàn)動態(tài)加載顯示內容的目的。
XComponent設置為surface類型時通常用于EGL/OpenGLES和媒體數(shù)據(jù)寫入,并將其顯示在XComponent組件上。
設置為“surface“類型時XComponent組件可以和其他組件一起進行布局和渲染。
同時XComponent又擁有單獨的“NativeWindow“,可以為開發(fā)者在native側提供native window用來創(chuàng)建EGL/OpenGLES環(huán)境,進而使用標準的OpenGL ES開發(fā)。
除此之外,媒體相關應用(視頻、相機等)也可以將相關數(shù)據(jù)寫入XComponent所提供的NativeWindow,從而實現(xiàn)呈現(xiàn)相應畫面。
HarmonyOS的應用如果要通過js來橋接native,一般需要使用napi接口來處理js交互,XComponent同樣不例外,具體使用請參考Native API在應用工程中的使用指導。
Native側處理js邏輯的文件類型為so:
對于使用XComponent進行標準OpenGL ES開發(fā)的場景,CMAKELists.txt文件內容大致如下:
- cmake_minimum_required(VERSION 3.4.1)
- project(XComponent) # 項目名稱
- set(NATIVERENDER_ROOT_PATH ${CMAKE_CURRENT_SOURCE_DIR})
- # 頭文件查找路徑
- include_directories(${NATIVERENDER_ROOT_PATH}
- ${NATIVERENDER_ROOT_PATH}/include
- )
- # 編譯目標so,SHARED表示動態(tài)庫
- add_library(nativerender SHARED
- xxx.cpp
- )
- # 查找相關庫 (包括OpenGL ES相關庫和XComponent提供的ndk接口)
- find_library( EGL-lib
- EGL )
- find_library( GLES-lib
- GLESv3 )
- find_library( libace-lib
- ace_ndk.z )
- # 編譯so所需要的依賴
- target_link_libraries(nativerender PUBLIC ${EGL-lib} ${GLES-lib} ${libace-lib} libace_napi.z.so libc++.a)
- static napi_value Init(napi_env env, napi_value exports)
- {
- // 定義暴露在模塊上的方法
- napi_property_descriptor desc[] ={
- DECLARE_NAPI_FUNCTION("changeColor", PluginRender::NapiChangeColor),
- };
- // 通過此接口開發(fā)者可在exports上掛載native方法(即上面的PluginRender::NapiChangeColor),exports會通過js引擎綁定到js層的一個js對象
- NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
- return exports;
- }
- static napi_module nativerenderModule = {
- .nm_version = 1,
- .nm_flags = 0,
- .nm_filename = nullptr,
- .nm_register_func = Init, // 指定加載對應模塊時的回調函數(shù)
- .nm_modname = "nativerender", // 指定模塊名稱,對于XComponent相關開發(fā),這個名稱必須和ArkTS側XComponent中l(wèi)ibraryname的值保持一致
- .nm_priv = ((void*)0),
- .reserved = { 0 },
- };
- extern "C" __attribute__((constructor)) void RegisterModule(void)
- {
- // 注冊so模塊
- napi_module_register(&nativerenderModule);
- }
NativeXComponent為XComponent提供了在native層的實例,可作為js層和native層XComponent綁定的橋梁。XComponent所提供的的NDK接口都依賴于該實例。具體NDK接口可參考Native XComponent。
可以在模塊被加載時的回調內(即Napi模塊注冊中的Init函數(shù))解析獲得NativeXComponent實例
- {
- // ...
- napi_status status;
- napi_value exportInstance = nullptr;
- OH_NativeXComponent *nativeXComponent = nullptr;
- // 用來解析出被wrap了NativeXComponent指針的屬性
- status = napi_get_named_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance);
- if (status != napi_ok) {
- return false;
- }
- // 通過napi_unwrap接口,解析出NativeXComponent的實例指針
- status = napi_unwrap(env, exportInstance, reinterpret_cast<void**>(&nativeXComponent));
- // ...
- }
依賴解析XComponent組件的NativeXComponent實例拿到的NativeXComponent指針,通過OH_NativeXComponent_RegisterCallback接口進行回調注冊
- {
- ...
- OH_NativeXComponent *nativeXComponent = nullptr;
- // 解析出NativeXComponent實例
- OH_NativeXComponent_Callback callback;
- callback->OnSurfaceCreated = OnSurfaceCreatedCB; // surface創(chuàng)建成功后觸發(fā),開發(fā)者可以從中獲取native window的句柄
- callback->OnSurfaceChanged = OnSurfaceChangedCB; // surface發(fā)生變化后觸發(fā),開發(fā)者可以從中獲取native window的句柄以及XComponent的變更信息
- callback->OnSurfaceDestroyed = OnSurfaceDestroyedCB; // surface銷毀時觸發(fā),開發(fā)者可以在此釋放資源
- callback->DispatchTouchEvent = DispatchTouchEventCB; // XComponent的touch事件回調接口,開發(fā)者可以從中獲得此次touch事件的信息
- OH_NativeXComponent_RegisterCallback(nativeXComponent, callback);
- ...
- }
在注冊的OnSurfaceCreated回調中開發(fā)者能拿到native window的句柄(其本質就是XComponent所單獨擁有的NativeWindow),因此可以在這里創(chuàng)建應用自己的EGL/OpenGLES開發(fā)環(huán)境,由此開始具體渲染邏輯的開發(fā)。
- EGLCore* eglCore_; // EGLCore為封裝了OpenGL相關接口的類
- uint64_t width_;
- uint64_t height_;
- void OnSurfaceCreatedCB(OH_NativeXComponent* component, void* window)
- {
- int32_t ret = OH_NativeXComponent_GetXComponentSize(component, window, &width_, &height_);
- if (ret === OH_NATIVEXCOMPONENT_RESULT_SUCCESS) {
- eglCore_->GLContextInit(window, width_, height_); // 初始化OpenGL環(huán)境
- }
- }
開發(fā)者在ArkTS側使用如下代碼即可用XComponent組件進行利用EGL/OpenGLES渲染的開發(fā)。
- XComponent({ id: 'xcomponentId1', type: 'surface', libraryname: 'nativerender' })
- .onLoad((context) => {})
- .onDestroy(() => {})
- import nativerender from "libnativerender.so"
該加載方式和import加載方式的區(qū)別在于,在加載動態(tài)庫是會將XComponent的NativeXComponent實例暴露到應用的native層中,從而讓開發(fā)者可以使用XComponent的NDK接口。
觸發(fā)時刻:XComponent組件被銷毀時觸發(fā)與一般ArkUI的組件銷毀時機一致,其和native側的OnSurfaceDestroyed的時序如下圖:
XComponent所持有的NativeWindow符合“生產(chǎn)者-消費者”模型
HarmonyOS上Camera、AVPlayer等符合生產(chǎn)者設計的部件都可以將數(shù)據(jù)寫入XComponent持有的NativeWindow并通過XComponent顯示。
開發(fā)者可通過綁定XComponentController獲得對應XComponent的surfaceId(該id可以唯一確定一個surface),從而傳給相應的部件接口。
- @State surfaceId:string = "";
- mXComponentController: XComponentController = new XComponentController();
- XComponent({ id: '', type: 'surface', controller: this.mXComponentController })
- .onLoad(() => {
- this.surfaceId = this.mXComponentController.getXComponentSurfaceId()
- })
具體部件接口可參考: VideoPlayer、 等。
- @Builder
- function addText(label: string): void {
- Text(label)
- .fontSize(40)
- }
- @Entry
- @Component
- struct Index {
- @State message: string = 'Hello XComponent'
- @State messageCommon: string = 'Hello World'
- build() {
- Row() {
- Column() {
- XComponent({ id: 'xcomponentId-container', type: 'component' }) {
- addText(this.message)
- Divider()
- .margin(4)
- .strokeWidth(2)
- .color('#F1F3F5')
- .width("80%")
- Column() {
- Text(this.messageCommon)
- .fontSize(30)
- }
- }
- }
- .width('100%')
- }
- .height('100%')
- }
- }
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: