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
  • GoF之工廠模式 @目錄GoF之工廠模式每博一文案1. 簡單說明“23種設計模式”1.2 介紹工廠模式的三種形態1.3 簡單工廠模式(靜態工廠模式)1.3.1 簡單工廠模式的優缺點:1.4 工廠方法模式1.4.1 工廠方法模式的優缺點:1.5 抽象工廠模式1.6 抽象工廠模式的優缺點:2. 總結:3 ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 本章將和大家分享ES的數據同步方案和ES集群相關知識。廢話不多說,下麵我們直接進入主題。 一、ES數據同步 1、數據同步問題 Elasticsearch中的酒店數據來自於mysql資料庫,因此mysql數據發生改變時,Elasticsearch也必須跟著改變,這個就是Elasticsearch與my ...
  • 引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...