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
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...