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 MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...