ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

鸿蒙笔记3:用Lazarus程序取得资源文件路径

鸿蒙笔记3:用Lazarus程序取得资源文件路径

目录

1 简介

2 Lazarus要读写的文件夹放在哪?

3 增加 napi_init.cpp

4 修改原有的 libLazarusOHOS_Wrapper.cpp

5 编译libLazarusOHOS_Wrapper.cpp

6 鸿蒙项目增加文件 libLazarusOHOS_Wrapper.d.ts

7 鸿蒙项目修改文件 QAbilityStage.ets

8 lazarus 程序增加一个单元 OHOSPaths

9 修改Lazarus程序主窗体代码

10 运行结果


本文基于秋风的10多篇lazarus鸿蒙开发博文及资源整理修改: 秋·风 - 博客园

1 简介

鸿蒙应用安装后,资源被自动解压到应用沙箱路径中,通过 context.resourceDir 获取目录后可直接以文件路径访问(只读)。如果需要读写操作,需要先将文件复制到 filesDir 沙箱目录中。Lazarus程序不能直接使用 context.resourceDir,需要采取另外办法取得该路径进行读写操作。另外,不同环境下,这些目录不同,不能写死在Lazarus程序中。

秋风的博客内容及资源,成功解决了鸿蒙与Lazarus的整合,在特定细节需求方面,需要自行修改完善。本文简要介绍鸿蒙打包lazarus程序,如何获取资源的准确路径。

2 Lazarus要读写的文件夹放在哪?

Lazarus需要读写的文件夹,假设是:cust_data ,放在鸿蒙项目目录:

\entry\src\main\resources\resfile

3 增加 napi_init.cpp

在1.LazarusOHOS_Wrapper文件夹中,增加 napi_init.cpp,负责从 AbilityContext 中提取路径,并提供给 Lazarus 侧使用。内容:

// 这个文件负责从 AbilityContext 中提取路径,并提供给 Lazarus 侧使用 // napi_init.cpp #include <napi/native_api.h> #include <cstring> #include <hilog/log.h> // 缓存真实沙箱路径(静态存储,与 OHOS_GetFilesDir 等共享) static char g_realFilesDir[1024] = {0}; static char g_realCacheDir[1024] = {0}; static char g_realResourceDir[1024] = {0}; static bool g_pathsReady = false; // 辅助函数:从 context 对象获取字符串属性并缓存 static bool GetAndCachePath(napi_env env, napi_value context, const char* propertyName, char* buffer, size_t bufSize) { napi_value prop; napi_status status = napi_get_named_property(env, context, propertyName, &prop); if (status != napi_ok) { OH_LOG_ERROR(LOG_APP, "[NAPI] Failed to get property: %{public}s", propertyName); return false; } // 可能返回的是 resourceManager 或 FilePath 对象,需要区分处理 // 对于 filesDir/cacheDir/resourceDir,在 context 下通常是直接字符串或 getter 函数 // HarmonyOS API 9+ 中 context.filesDir 直接返回 string size_t strLen = 0; status = napi_get_value_string_utf8(env, prop, buffer, bufSize, &strLen); if (status != napi_ok) { OH_LOG_ERROR(LOG_APP, "[NAPI] Failed to get string for: %{public}s", propertyName); return false; } buffer[strLen] = '\0'; OH_LOG_INFO(LOG_APP, "[NAPI] %{public}s = %{public}s", propertyName, buffer); return true; } // 外部可调用的初始化接口 extern "C" __attribute__((visibility("default"))) napi_value OHOS_InitPaths(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; napi_status status = napi_get_cb_info(env, info, &argc, args, nullptr, nullptr); if (status != napi_ok || argc < 1) { OH_LOG_ERROR(LOG_APP, "[NAPI] OHOS_InitPaths: No context provided"); napi_value ret; napi_get_boolean(env, false, &ret); return ret; } napi_value context = args[0]; // 依次获取路径 bool success = true; success &= GetAndCachePath(env, context, "filesDir", g_realFilesDir, sizeof(g_realFilesDir)); success &= GetAndCachePath(env, context, "cacheDir", g_realCacheDir, sizeof(g_realCacheDir)); success &= GetAndCachePath(env, context, "resourceDir", g_realResourceDir, sizeof(g_realResourceDir)); g_pathsReady = success; napi_value result; napi_get_boolean(env, success, &result); return result; } // Lazarus 侧调用的 C 接口(替代原来依赖 Qt 的函数) extern "C" const char* OHOS_GetFilesDir() { if (g_pathsReady) return g_realFilesDir; else return ""; // 未初始化时返回空串 } extern "C" const char* OHOS_GetCacheDir() { if (g_pathsReady) return g_realCacheDir; else return ""; } extern "C" const char* OHOS_GetResourceDir() { if (g_pathsReady) return g_realResourceDir; else return ""; } // NAPI 模块注册 static napi_value RegisterInitPaths(napi_env env, napi_value exports) { napi_property_descriptor desc[] = { {"OHOS_InitPaths", nullptr, OHOS_InitPaths, nullptr, nullptr, nullptr, napi_default, nullptr} }; napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc); return exports; } static napi_module demoModule = { .nm_version = 1, .nm_flags = 0, .nm_filename = nullptr, .nm_register_func = RegisterInitPaths, .nm_modname = "lazarusohos", .nm_priv = nullptr, .reserved = {0}, }; extern "C" __attribute__((constructor)) void RegisterModule(void) { napi_module_register(&demoModule); }

4 修改原有的 libLazarusOHOS_Wrapper.cpp

内容为:

// libLazarusOHOS_Wrapper.cpp - HarmonyOS Qt5 + Lazarus LCL wrapper // QApplication is already created by Qt OHOS plugin (libqohos.so) // before this library is loaded. Do NOT create another one. // 现在 OHOS_GetFilesDir 等函数已经在 napi_init.cpp 中实现了, // 原来的 wrapper 就不需要再通过 Qt 获取路径了, // 可以保留 wrapper 的 main 函数用于加载 Lazarus 库, // 但删除路径获取代码。 // libLazarusOHOS_Wrapper.cpp #include <cstdio> #include <dlfcn.h> // 路径函数声明由 napi_init.cpp 提供,这里不用定义 extern "C" const char* OHOS_GetFilesDir(); extern "C" const char* OHOS_GetCacheDir(); extern "C" const char* OHOS_GetBundleDir(); // 不再使用,可留空实现返回 "" typedef void (*InitAndShowFormFunc)(); extern "C" int main(int, char**) { // 此时路径可能还未初始化,打印为空 fprintf(stderr, "[Wrapper] OHOS_GetFilesDir: %s\n", OHOS_GetFilesDir()); fprintf(stderr, "[Wrapper] OHOS_GetCacheDir: %s\n", OHOS_GetCacheDir()); // QApplication already exists from libqohos.so void* lib = dlopen("libOHOS_QT_Lazarus.so", RTLD_NOW | RTLD_GLOBAL); if (!lib) { fprintf(stderr, "[Wrapper] dlopen failed: %s\n", dlerror()); return 1; } InitAndShowFormFunc InitAndShowForm = (InitAndShowFormFunc)dlsym(lib, "InitAndShowForm"); if (!InitAndShowForm) { fprintf(stderr, "[Wrapper] dlsym failed: %s\n", dlerror()); dlclose(lib); return 1; } InitAndShowForm(); return 0; }

5 编译libLazarusOHOS_Wrapper.cpp


执行以下指令,生成 aarch64 格式的so文件。为了访问hap包安装后的资源文件目录和沙箱目录,此处经过修改,与原文有所不同。原文指令:
lazarus鸿蒙开发3:编译libLazarusOHOS_Wrapper.so - 秋·风 - 博客园

注意先删除原来存在的文件: libLazarusOHOS_Wrapper.so

SET NATIVE_OHOS_SDK=d:/fpc4ohos/sdk/default/openharmony/native SET SYSROOT=%NATIVE_OHOS_SDK%/sysroot SET QT5DIR=d:/oh/Qt-5.12.12-ohos-aarch64 %NATIVE_OHOS_SDK%\llvm\bin\clang++ -shared ^ -o libLazarusOHOS_Wrapper.so ^ -I"%SYSROOT%\usr\include" ^ -I"%SYSROOT%\usr\include\napi" ^ -I"%QT5DIR%\include" ^ -I"%QT5DIR%\include\QtCore" ^ -I"%QT5DIR%\include\QtGui" ^ -I"%QT5DIR%\include\QtWidgets" ^ -L"%SYSROOT%\usr\lib\aarch64-linux-ohos" ^ -L"%QT5DIR%\lib" ^ -lace_napi.z ^ -lQt5Core ^ -lQt5Gui ^ -lQt5Widgets ^ -lc ^ -ldl ^ --sysroot="%SYSROOT%" ^ -target aarch64-linux-ohos ^ -fPIC ^ napi_init.cpp ^ libLazarusOHOS_Wrapper.cpp

执行以下指令,生成 x86_64 格式的so文件。为了访问hap包安装后的资源文件目录和沙箱目录,此处经过修改,与原文有所不同。原文指令:
lazarus鸿蒙开发3:编译libLazarusOHOS_Wrapper.so - 秋·风 - 博客园

SET NATIVE_OHOS_SDK=d:/fpc4ohos/sdk/default/openharmony/native SET SYSROOT=%NATIVE_OHOS_SDK%/sysroot SET QT5DIR=d:/oh/Qt-5.12.12-ohos-x86_64 %NATIVE_OHOS_SDK%\llvm\bin\clang++ -shared ^ -o libLazarusOHOS_Wrapper.so ^ -I"%SYSROOT%\usr\include" ^ -I"%SYSROOT%\usr\include\napi" ^ -I"%QT5DIR%\include" ^ -I"%QT5DIR%\include\QtCore" ^ -I"%QT5DIR%\include\QtGui" ^ -I"%QT5DIR%\include\QtWidgets" ^ -L"%SYSROOT%\usr\lib\x86_64-linux-ohos" ^ -L"%QT5DIR%\lib" ^ -lace_napi.z ^ -lQt5Core ^ -lQt5Gui ^ -lQt5Widgets ^ -lc ^ -ldl ^ --sysroot="%SYSROOT%" ^ -target x86_64-linux-ohos ^ -fPIC ^ napi_init.cpp ^ libLazarusOHOS_Wrapper.cpp

6 鸿蒙项目增加文件 libLazarusOHOS_Wrapper.d.ts

D:\fpc4ohos\ohos_demo\2.ohos_hap_project\entry\src\main\ets\common\libLazarusOHOS_Wrapper.d.ts

内容为:

// entry/src/main/ets/common/libLazarusOHOS_Wrapper.d.ts export interface Wrapper { OHOS_InitPaths(context: object): boolean; } declare const wrapper: Wrapper; export default wrapper;

7 鸿蒙项目修改文件 QAbilityStage.ets

D:\fpc4ohos\ohos_demo\2.ohos_hap_project\entry\src\main\ets\qabilitystage\QAbilityStage.ets

代码:

// import lazarushos from 'libLazarusOHOS_Wrapper.so'; // 新增导入 import lazarushos from 'libLazarusOHOS_Wrapper.so'; import { Wrapper } from '../common/libLazarusOHOS_Wrapper'; // 导入接口 // import AbilityStage from '@ohos.app.ability.AbilityStage'; import QAbility from '../qability/QAbility'; import QChildProcess from '../process/QChildProcess'; import QtUtils from '../qability/QtUtils'; import Want from '@ohos.app.ability.Want'; import common from '@ohos.app.ability.common'; import hilog from '@ohos.hilog'; import qpa from 'libqohos.so'; import {APP_LIBRARY_NAME, LOG_DOMAIN, LOG_TAG} from '../common/QtAppConstants'; import { AbilityStage } from '@kit.AbilityKit'; import { fileIo } from '@kit.CoreFileKit'; export default class QAbilityStage extends AbilityStage { // setting "appArgs" overrides arguments from initial Want object private static appArgs?: Array<string>; private static setupQtApplicationCalled: boolean = false; private static initQtAppContextImpl(appContext: common.ApplicationContext, abilityClassName: string, uiExtensionMode: boolean): void { if (!QAbilityStage.setupQtApplicationCalled) { hilog.info(LOG_DOMAIN, LOG_TAG, 'ccc QAbilityStage::initQtAppContextImpl: init with uiExtensionMode=' + uiExtensionMode); QAbilityStage.setupQtApplicationCalled = true; qpa.setupQtApplication({ appContext: appContext, modules: QtUtils.getModulesMapForQt(), appName: APP_LIBRARY_NAME, appArgs: QAbilityStage.appArgs, abilityClassName: abilityClassName, uiExtensionMode: uiExtensionMode, _unusedQChildProcess: new QChildProcess(), }); } else { hilog.info(LOG_DOMAIN, LOG_TAG, 'ccc QAbilityStage::initQtAppContextImpl: already initialized'); } } public static initQtAppContextIfNeeded(appContext: common.ApplicationContext): void { QAbilityStage.initQtAppContextImpl(appContext, QAbility.name, false); } public static initQtAppContextInUiExtensionMode(appContext: common.ApplicationContext, abilityClassName: string): void { QAbilityStage.initQtAppContextImpl(appContext, abilityClassName, true); } // 直接使用 fileIo.copyDirSync(适用于层级少、文件小的场景) // public static copyDirSimple(srcPath: string, destPath: string): void { // // 检查目标目录是否已存在 // let destExists: boolean = fileIo.accessSync(destPath, fileIo.AccessModeType.EXIST); // if (destExists) { // console.info(`目标目录已存在,跳过复制: ${destPath}`); // return; // } // // 直接复制整个目录 // fileIo.copyDirSync(srcPath, destPath); // } onCreate(): void { hilog.info(LOG_DOMAIN, LOG_TAG, 'QAbilityStage::onCreate()'); qpa.handleAbilityStageOnCreate(this); // 获取 AbilityStageContext let context: common.AbilityStageContext = this.context; // 初始化 wrapper 的路径缓存(必须在 wrapper.main 执行之前) try { // 直接通过 as 断言调用,杜绝 any 类型 let initResult: boolean = (lazarushos as Wrapper).OHOS_InitPaths(context); console.info(`ccc [QAbilityStage] OHOS_InitPaths result: ${initResult}`); } catch (e) { console.error(`ccc [QAbilityStage] OHOS_InitPaths failed: ${e}`); } // 获取 resfile 资源目录(只读)和 filesDir 沙箱目录(可读写) let resourceDir: string = context.resourceDir; let filesDir: string = context.filesDir; console.info(`ccc resourceDir: ${resourceDir}`); console.info(`ccc filesDir: ${filesDir}`); } onNewProcessRequest(want: Want): string { hilog.info(LOG_DOMAIN, LOG_TAG, 'QAbilityStage::onNewProcessRequest: want.parameters: ' + JSON.stringify(want.parameters)); QAbilityStage.initQtAppContextIfNeeded(this.context.getApplicationContext()); let processKey: string = qpa.handleAbilityStageOnNewProcessRequest(this, want); hilog.info(LOG_DOMAIN, LOG_TAG, 'ccc QAbilityStage::onNewProcessRequest: processKey: "' + processKey + '"'); return processKey; } onAcceptWant(want: Want): string { hilog.info(LOG_DOMAIN, LOG_TAG, 'ccc QAbilityStage::onAcceptWant: want.parameters: ' + JSON.stringify(want.parameters)); QAbilityStage.initQtAppContextIfNeeded(this.context.getApplicationContext()); let instanceKey: string = qpa.handleAbilityStageOnAcceptWant(this, want); hilog.info(LOG_DOMAIN, LOG_TAG, 'ccc QAbilityStage::onAcceptWant: instanceKey: "' + instanceKey + '"'); return instanceKey; } onDestroy() { hilog.info(LOG_DOMAIN, LOG_TAG, 'ccc QAbilityStage::onDestroy()'); qpa.handleAbilityStageOnDestroy(this); } }

8 lazarus 程序增加一个单元 OHOSPaths

unit OHOSPaths; interface uses SysUtils; //function OHOS_GetFilesDir: PChar; cdecl; external 'libLazarusOHOS_Wrapper.so'; //function OHOS_GetCacheDir: PChar; cdecl; external 'libLazarusOHOS_Wrapper.so'; //function OHOS_GetBundleDir: PChar; cdecl; external 'libLazarusOHOS_Wrapper.so'; function OHOS_GetFilesDir: PChar; cdecl; external 'libLazarusOHOS_Wrapper.so'; function OHOS_GetCacheDir: PChar; cdecl; external 'libLazarusOHOS_Wrapper.so'; function OHOS_GetResourceDir: PChar; cdecl; external 'libLazarusOHOS_Wrapper.so'; //function GetOHOSFilesPath: string; //function GetOHOSCachePath: string; //function GetOHOSBundlePath: string; function GetOHOSFilesPath: string; function GetOHOSResourcePath: string; function GetOHOSCachePath: string; implementation //function SafeStr(P: PChar): string; inline; //begin // if P = nil then Result := '' else Result := StrPas(P); //end; // //function GetOHOSFilesPath: string; //begin // Result := SafeStr(OHOS_GetFilesDir); // if Result <> '' then Result := IncludeTrailingPathDelimiter(Result); //end; // //function GetOHOSCachePath: string; //begin // Result := SafeStr(OHOS_GetCacheDir); // if Result <> '' then Result := IncludeTrailingPathDelimiter(Result); //end; // //function GetOHOSBundlePath: string; //begin // Result := SafeStr(OHOS_GetBundleDir); // if Result <> '' then Result := IncludeTrailingPathDelimiter(Result); //end; function GetOHOSFilesPath: string; begin Result := string(AnsiString(OHOS_GetFilesDir)); end; function GetOHOSCachePath: string; begin Result := string(AnsiString(OHOS_GetCacheDir)); end; function GetOHOSResourcePath: string; begin Result := string(AnsiString(OHOS_GetResourceDir)); end; end.

9 修改Lazarus程序主窗体代码

uses OHOSPaths; ...... showmessage(format('GetOHOSFilesPath: %s, GetOHOSResourcePath: %s', [GetOHOSFilesPath, GetOHOSResourcePath])); ......

10 运行结果

DevEco:

模拟器中,Lazarus程序弹出窗口:

返回列表