鸿蒙笔记3:用Lazarus程序取得资源文件路径
目录
4 修改原有的 libLazarusOHOS_Wrapper.cpp
5 编译libLazarusOHOS_Wrapper.cpp
6 鸿蒙项目增加文件 libLazarusOHOS_Wrapper.d.ts
本文基于秋风的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程序弹出窗口:

更多推荐
所有评论(0)