HarmonyOS NEXT應用開發之預載入so並讀取RawFile文件

来源:https://www.cnblogs.com/HarmonyOSNext/p/18139644
-Advertisement-
Play Games

介紹 本示例主要介紹在TaskPool子線程中使用 dlopen 預載入 so 庫並使用句柄調用庫函數的方法,以及在Native中使用 pread 系統函數讀取Rawfile文件的部分文本內容,並添加 HiLog 日誌。 效果圖預覽 使用說明 rawfile路徑下存在一個有內容的文本文件rawfil ...


介紹

本示例主要介紹在TaskPool子線程中使用 dlopen 預載入 so 庫並使用句柄調用庫函數的方法,以及在Native中使用 pread 系統函數讀取Rawfile文件的部分文本內容,並添加 HiLog 日誌。

效果圖預覽

image

使用說明

  1. rawfile路徑下存在一個有內容的文本文件rawfile.txt。
  2. 輸入開始讀取位置、需要讀取的長度,點擊“開始讀取”,即可通過調用Native側暴露的getRawFileContent介面把讀取到的內容顯示在界面上。

具體代碼可參考MainPage.ets

實現思路

在TaskPool子線程中使用dlopen預載入so庫和使用句柄調用so庫函數的方式

  1. 將需要載入的.so文件放到工程中,在CMakeLists中使用target_link_directories命令將包含這些庫文件的目錄添加到預載入庫的鏈接目錄。
target_link_directories(preloadso PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../../../libs/${OHOS_ARCH}/
  1. 使用target_link_libraries命令將需要預載入的so庫鏈接到項目中。
target_link_libraries(preloadso PUBLIC libhilog_ndk.z.so libace_napi.z.so global_handlers libnativerawfile.so)
  1. 定義一個全局對象global_handlers用於存放載入so庫所得句柄,其他需要使用global_handlers的cpp文件需要引入定義全局對象的頭文件。
std::unordered_map<std::string, void *> global_handlers;
  1. 在 Native 層的 Preload 介面中,遍歷傳入的 .so 路徑數組,使用 dlopen 函數載入庫,並將句柄保存到 global_handlers 中。
// 獲取傳入的so庫路徑數組的長度
uint32_t arrayLength;
napi_get_array_length(env, args[0], &arrayLength);
for (uint32_t i = 0; i < arrayLength; i++) {
    napi_get_element(env, args[0], i, &pathString); // 獲取數組的第 i 個元素
    napi_status status = napi_get_value_string_utf8(env, pathString, path, sizeof(path), &pathLength);
    if (status != napi_ok) {
        // 處理獲取路徑失敗的情況
        continue;
    }
    // TODO:知識點:使用dlopen動態載入so庫,返回so庫的句柄
    void *handler = dlopen(path, RTLD_LAZY);
    if (handler == nullptr) {
        // TODO:知識點:dlerror拋出載入庫失敗的錯誤
        dlerror();
        continue; // 載入下一個
    }
    // 將句柄保存到全局對象global_handlers中
    global_handlers[std::string(path)] = handler;
}
  1. 暴露Preload介面給ArkTS層使用,使其能夠通過preload調用Native層的Preload介面。
napi_property_descriptor desc[] = {{"preload", nullptr, Preload, nullptr, nullptr, nullptr, napi_default, nullptr}};
  1. ArkTS層使用TaskPool創建子線程,通過preload介面調用Native側的Preload介面,實現在TaskPool子線程中載入.so庫,導出preloadSOByTaskPool函數。
@Concurrent
function preloadSO(): string[] {
  return napi.preload(Constants.LIBRARY_PATH_ARRAY);
}
export function preloadSOByTaskPool(): void {
  // TODO: 知識點:使用new taskpool.Task()創建任務項,傳入任務執行函數和所需參數
  let task: taskpool.Task = new taskpool.Task(preloadSO);
  try {
    // TODO:知識點:使用taskpool.execute將待執行的函數放入TaskPool內部任務隊列等待執行
    taskpool.execute(task, taskpool.Priority.HIGH).then((res: string[]) => {
    // so庫預載入完成的處理
    logger.info(TAG, '%{public}s', 'PreloadSOByTaskPool:' + JSON.stringify(res));
    })
  } catch (err) {
     logger.error(TAG, "PreloadSOByTaskPool: execute failed, " + (err as BusinessError).toString());
  }
}
  1. 在Ability的onCreate生命周期函數中,調用preloadSOByTaskPool開啟子線程,完成so庫的預載入。
    onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
        // 在TaskPool子線程預載入so
        preloadSOByTaskPool();
    }
  1. 後續可以通過句柄使用so庫中的函數。
  • 在Native層引入頭文件global_handlers.h。
    #include "global\_handlers.h"
  • 編寫napi介面,用於實現ArkTS層和so庫之間的交互
static napi_value GetTotalRawFileContent(napi_env env, napi_callback_info info){}
static napi_value GetRawFileContent(napi_env env, napi_callback_info info) {}
  • 在napi介面中從全局對象global_handlers中取出對應so庫的句柄。
// 從全局對象中獲取指定so庫的句柄
void *handler = global_handlers["libnativerawfile.so"];
  • 句柄不為空時,使用dlsym查找和調用so庫中的符號。
// TODO:知識點:使用dlsym查找和調用so庫中的符號
GetTotalRawFileContentWrapperFunc getTotalRawFileContentWrapper =
    reinterpret_cast<GetTotalRawFileContentWrapperFunc>(dlsym(handler, "GetTotalRawFileContentWrapper"));
if (getTotalRawFileContentWrapper) {
    // 調用 GetRawFileContentWrapper 函數
    napi_value result = getTotalRawFileContentWrapper(env, info);
    OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, " GetRawFileContentWrapper finish");
    return result;
} else {
    // 處理無法獲取函數指針的情況
    OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, " GetTotalRawFileContentWrapper fn failed");
    return nullptr;
}
  • 在ArkTS層調用編寫的napi介面,就可以使用so庫導出的函數
this.rawfileContent = nativeRawfileApi.getRawFileContent(getContext().resourceManager, 'rawfile.txt', 2, 5);

Native中加入hilog日誌的實現主要步驟如下

  1. 在CMakeLists中通過target_link_libraries導入日誌模塊libhilog_ndk.z.so。
target_link_libraries(nativerawfile PUBLIC libace_napi.z.so libhilog_ndk.z.so librawfile.z.so)
  1. 在需要列印hilog日誌的cpp文件開頭引入頭文件 #include "hilog/log.h"。
#include "hilog/log.h"
  1. 在需要列印日誌的地方通過OH_LOG_Print列印日誌。日誌級別有LOG_INFO、LOG_ERROR等
OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "GetRawFileContent Begin");

Native讀取Rawfile中文本文件部分內容主要步驟如下:

  1. 在前端通過調用Native中的getRawFileContent介面讀取文件部分內容。傳入的參數為文件名、開始讀取位置、讀取文件長度。
Button($r('app.string.ReadButton'))
  .onClick(()=> {
     this.rawfileContent = nativeRawfileApi.getRawFileContent(getContext().resourceManager, 'rawfile.txt', this.ReadStartPos, this.readLength);
}).margin($r('app.string.rawfile_margin'))
  1. 在Native側native_rawfile.cpp的getRawFileContent介面中通過Rawfile的API介面以及pread函數讀取Rawfile文件部分內容。
 // TODO 知識點:通過pread讀取文件部分內容。
 if ((ret = pread(descriptor.fd, buf, lenContent,  descriptor.start + startPos)) == -1) {
     OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "GetRawFileContent pread error!");
 } else {
     buf[lenContent] = '\0';
     OH_LOG_Print(LOG_APP, LOG_INFO, GLOBAL_RESMGR, TAG, "GetRawFileContent: %{public}ld: %{public}ld: %{public}s\n",
                  descriptor.start, len, buf);
 }

高性能知識點

不涉及

工程結構&模塊類型

nativerawfile                               // har類型
|---libs\
|   |---arm64-v8a\libnativeRawFile.so       // arm64-v8a類型so庫
|   |---armeabi-v7a\libnativeRawFile.so     // armeabi-v7a類型so庫
|   |---x86_64\libnativeRawFile.so          // x86_64類型so庫
|---src\main\ets\components\mainpage\
|   |---MainPage.ets                        // 視圖層-Rawfile場景主頁面
|---src\main\ets\utils\
|   |---Constants.ets                       // 常量數據
|   |---TaskPool.ets                        // TaskPool子線程載入so庫
|---src\main\cpp\
|   |---include\global_handlers.h           // native層-全局句柄頭文件
|   |---global_handlers.cpp                 // native層-定義全局句柄對象
|   |---preloadso.cpp                       // native層-載入libnativeRawFile.so業務邏輯
|   |---nativeRawFile.cpp                   // native層-讀取Rawfile文件部分內容業務邏輯,libnativeRawFile.so源代碼
|   |---native_rawfile_api.cpp              // native層-libnativeRawFile.so和ArkTS中間層介面

模塊依賴

  1. 本實例依賴common模塊來實現公共組件FunctionDescription

參考資料

公共組件FunctionDescription


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 目錄一、什麼是哨兵模式1、為什麼需要哨兵機制2、哨兵架構拓撲3、Redis Sentinel的功能:二、搭建哨兵架構1、涉及主機2、拓撲結構3、設置一主兩從4、master伺服器狀態5、編輯哨兵的配置文件6、啟動哨兵7、驗證哨兵埠8、查看哨兵日誌9、驗證當前sentinel狀態三、故障轉移1、re ...
  • 近日,由新一代信息技術產業研究院、賽迪未來產業研究中心共同主辦,中國電子學會區塊鏈分會、至頂科技聯合承辦的“2024未來信息技術大會暨首屆數據要素創新發展論壇”於北京成功舉辦。大會公佈了“2023年度數據要素價值創新標桿示範案例”評選結果,天翼雲“海南省數據產品超市公共數據資源開發利用平臺”與“福州... ...
  • 在當今快速發展的世界中,數據被視為新的石油。隨著對數據驅動洞察的日益依賴,大數據工程師的角色比以往任何時候都更為關鍵。 這些專業人員在管理和優化組織內的數據操作中扮演著至關重要的角色。在本文中,我們將探索2024年大數據工程師必須具備的十項技能。 理解大數據工程師的角色 在深入技能之前,瞭解大數據工 ...
  • 內容介紹 hive on spark的調優,那必然涉及到這一系列框架的記憶體模型。本章就是來講一下這些框架的記憶體模型。 hive on spark的任務,從開始到結束。總共涉及了3個框架。分別是:yarn、hive、spark 其中,hive只是一個客戶端的角色。就不涉及任務運行時的記憶體。所以這裡主要 ...
  • 介紹 本示例介紹使用第三方庫的Axios獲取GBK格式的網路數據時,通過util實現GBK轉換UTF-8格式。該場景多用於需要轉換編碼格式的應用。 效果圖預覽 使用說明 直接進入頁面就可獲取GBK格式的用戶名信息併進行解碼操作。 實現思路 使用第三方庫Axios獲取網路數據,並將獲取數據類型設置為A ...
  • 介紹 圖片預覽在應用開發中是一種常見場景,在諸如QQ、微信、微博等應用中均被廣泛使用。本模塊基於Image組件實現了簡單的圖片預覽功能。 使用說明: 雙指捏合縮放圖片大小 雙擊圖片進行圖片的大小切換 圖片在放大模式下,滑動圖片查看圖片的對應位置 效果圖預覽 實現思路 image組件的objectFi ...
  • 有的時候,我們可能需要多次執行同一塊代碼。一般情況下,語句是按順序執行的:函數中的第一個語句先執行,接著是第二個語句,依此類推。 編程語言提供了更為複雜執行路徑的多種控制結構。 迴圈語句允許我們多次執行一個語句或語句組,下麵是大多數編程語言中迴圈語句的流程圖: for 迴圈 TypeScript ...
  • 一、Shape Shape組件是用於創建2D形狀和粒子效果的組件。它可以創建包括圓形、正方形、三角形和多邊形等基本形狀,同時還可以自定義形狀。Shape組件創建各種不同的效果,例如火花、煙霧、雨滴等。在使用Shape組件時,可以通過編輯頂點、路徑和大小等屬性來控制形狀的外觀和行為。 1.創建 ...
一周排行
    -Advertisement-
    Play Games
  • 基於.NET Framework 4.8 開發的深度學習模型部署測試平臺,提供了YOLO框架的主流系列模型,包括YOLOv8~v9,以及其系列下的Det、Seg、Pose、Obb、Cls等應用場景,同時支持圖像與視頻檢測。模型部署引擎使用的是OpenVINO™、TensorRT、ONNX runti... ...
  • 十年沉澱,重啟開發之路 十年前,我沉浸在開發的海洋中,每日與代碼為伍,與演算法共舞。那時的我,滿懷激情,對技術的追求近乎狂熱。然而,隨著歲月的流逝,生活的忙碌逐漸占據了我的大部分時間,讓我無暇顧及技術的沉澱與積累。 十年間,我經歷了職業生涯的起伏和變遷。從初出茅廬的菜鳥到逐漸嶄露頭角的開發者,我見證了 ...
  • C# 是一種簡單、現代、面向對象和類型安全的編程語言。.NET 是由 Microsoft 創建的開發平臺,平臺包含了語言規範、工具、運行,支持開發各種應用,如Web、移動、桌面等。.NET框架有多個實現,如.NET Framework、.NET Core(及後續的.NET 5+版本),以及社區版本M... ...
  • 前言 本文介紹瞭如何使用三菱提供的MX Component插件實現對三菱PLC軟元件數據的讀寫,記錄了使用電腦模擬,模擬PLC,直至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1. PLC開發編程環境GX Works2,GX Works2下載鏈接 https:// ...
  • 前言 整理這個官方翻譯的系列,原因是網上大部分的 tomcat 版本比較舊,此版本為 v11 最新的版本。 開源項目 從零手寫實現 tomcat minicat 別稱【嗅虎】心有猛虎,輕嗅薔薇。 系列文章 web server apache tomcat11-01-官方文檔入門介紹 web serv ...
  • 1、jQuery介紹 jQuery是什麼 jQuery是一個快速、簡潔的JavaScript框架,是繼Prototype之後又一個優秀的JavaScript代碼庫(或JavaScript框架)。jQuery設計的宗旨是“write Less,Do More”,即倡導寫更少的代碼,做更多的事情。它封裝 ...
  • 前言 之前的文章把js引擎(aardio封裝庫) 微軟開源的js引擎(ChakraCore))寫好了,這篇文章整點js代碼來測一下bug。測試網站:https://fanyi.youdao.com/index.html#/ 逆向思路 逆向思路可以看有道翻譯js逆向(MD5加密,AES加密)附完整源碼 ...
  • 引言 現代的操作系統(Windows,Linux,Mac OS)等都可以同時打開多個軟體(任務),這些軟體在我們的感知上是同時運行的,例如我們可以一邊瀏覽網頁,一邊聽音樂。而CPU執行代碼同一時間只能執行一條,但即使我們的電腦是單核CPU也可以同時運行多個任務,如下圖所示,這是因為我們的 CPU 的 ...
  • 掌握使用Python進行文本英文統計的基本方法,並瞭解如何進一步優化和擴展這些方法,以應對更複雜的文本分析任務。 ...
  • 背景 Redis多數據源常見的場景: 分區數據處理:當數據量增長時,單個Redis實例可能無法處理所有的數據。通過使用多個Redis數據源,可以將數據分區存儲在不同的實例中,使得數據處理更加高效。 多租戶應用程式:對於多租戶應用程式,每個租戶可以擁有自己的Redis數據源,以確保數據隔離和安全性。 ...