HarmonyOS鸿蒙Next中项目中resources目录下的文件,C++层/native侧应该怎么访问

HarmonyOS鸿蒙Next中项目中resources目录下的文件,C++层/native侧应该怎么访问

开发场景: 从网络下载文件,然后把文件的访问路径通过 N-API 传递给 C++

目前问题:

  1. 目前的做法是从下载目录或者工程静态目录resources下,将文件拷贝到沙盒中,然后将沙盒中的路径发给C++ 我想了解一下,目前是需要这种实现方式吗? 可以类似安卓通过开通权限C++直接访问某些目录文件吗 目前有将文件拷贝到沙盒中的API方法吗? 谢谢
3 回复

解决措施

可以通过createModuleContext(moduleName)接口创建同应用中不同module的上下文,获取到resourceManager对象后,在Native侧使用Native Rawfile接口操作Rawfile目录和文件来跨模块访问资源。

具体使用方式可参考以下代码:

  1. 在src/main/cpp/CMakeLists.txt文件中,添加依赖资源librawfile.z.so

    target_link_libraries(nativecrossmoduleaccessres PUBLIC libace_napi.z.so libace_napi.z.so libhilog_ndk.z.so librawfile.z.so)
    
  2. 在src/main/cpp/types/libentry/index.d.ts文件中,声明应用侧函数getRawFileContent。

    import { resourceManager } from "@kit.LocalizationKit";
    export const getRawFileContent: (resMgr: resourceManager.ResourceManager, path: string) => Uint8Array;
    
  3. 在src/main/cpp/napi_init.cpp文件中实现功能代码。

    #include "napi/native_api.h"
    #include <rawfile/raw_file.h>
    #include <rawfile/raw_file_manager.h>
    #include "hilog/log.h"
    
    const int GLOBAL_RESMGR = 0xFF00;
    const char *TAG = "[Sample_rawfile]";
    
    namespace {
        napi_value CreateJsArrayValue(napi_env env, std::unique_ptr<uint8_t[]> &data, long length)
        {
            napi_value buffer;
            napi_status status = napi_create_external_arraybuffer(
                env, data.get(), length,
                [](napi_env env, void *data, void *hint) {
                    delete[] static_cast<char *>(data);
                },
                nullptr, &buffer);
            if (status != napi_ok) {
                OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "Failed to create external array buffer");
                return nullptr;
            }
            napi_value result = nullptr;
            status = napi_create_typedarray(env, napi_uint8_array, length, buffer, 0, &result);
            if (status != napi_ok) {
                OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "Failed to create media typed array");
                return nullptr;
            }
            data.release();
            return result;
        }
    }
    
    static napi_value GetRawFileContent(napi_env env, napi_callback_info info)
    {
        OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "GetFileContent Begin");
        size_t requireArgc = 3;
        size_t argc = 2;
        napi_value argv[2] = { nullptr };
        // 获取参数信息
        napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr);
        // argv[0]即为函数第一个参数Js资源对象,OH_ResourceManager_InitNativeResourceManager转为Native对象。
        NativeResourceManager *mNativeResMgr = OH_ResourceManager_InitNativeResourceManager(env, argv[0]);
        size_t strSize;
        char strBuf[256];
        napi_get_value_string_utf8(env, argv[1], strBuf, sizeof(strBuf), &strSize);
        std::string filename(strBuf, strSize);
        // 获取rawfile指针对象
        RawFile *rawFile = OH_ResourceManager_OpenRawFile(mNativeResMgr, filename.c_str());
        if (rawFile != nullptr) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, GLOBAL_RESMGR, TAG, "OH_ResourceManager_OpenRawFile success");
        }
        // 获取rawfile大小并申请内存
        long len = OH_ResourceManager_GetRawFileSize(rawFile);
        std::unique_ptr<uint8_t[]> data= std::make_unique<uint8_t[]>(len);
        // 一次性读取rawfile全部内容
        int res = OH_ResourceManager_ReadRawFile(rawFile, data.get(), len);
        // 关闭打开的指针对象
        OH_ResourceManager_CloseRawFile(rawFile);
        OH_ResourceManager_ReleaseNativeResourceManager(mNativeResMgr);
        // 转为js对象
        return CreateJsArrayValue(env, data, len);
    }
    
  4. ArkTS侧调用,此处需要传入资源对象。

    import testNapi from 'libnativecrossmoduleaccessres.so';
    
    @Entry
    @Component
    struct Index {
        @State message: string = 'Native Cross Module Access Resource';
        private resMgr = getContext().createModuleContext('NativeAccessRes').resourceManager; // 获取本应用包的资源对象
        build() {
            Row() {
                Column() {
                    Text(this.message)
                        .fontSize(50)
                        .fontWeight(FontWeight.Bold)
                        .onClick(() => {
                            let rawfileContext = testNapi.getRawFileContent(this.resMgr, 'rawfile.txt');
                            console.log("rawfileContext" + rawfileContext);
                        })
                }
                .width('100%')
            }
            .height('100%')
        }
    }
    

转载自如何在Native侧跨模块访问资源-NDK开发-NDK开发-应用框架开发-开发 - 华为HarmonyOS开发者 (huawei.com)

更多关于HarmonyOS鸿蒙Next中项目中resources目录下的文件,C++层/native侧应该怎么访问的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS鸿蒙Next中,C++层或native侧访问resources目录下的文件,可以通过OH_ResourceManager接口实现。首先使用OH_ResourceManager_Init初始化资源管理器,然后通过OH_ResourceManager_GetResource获取资源文件路径或内容。具体资源路径可通过OH_ResourceManager_GetResourcePath获取,资源内容可通过OH_ResourceManager_GetResourceData读取。确保在config.json中正确配置资源路径。

在HarmonyOS Next中,C++/native层访问resources目录文件的最佳实践是通过沙盒机制。目前确实需要先将文件从resources或下载目录拷贝到应用沙盒中,再将沙盒路径传递给C++层。

关于具体实现:

  1. 资源文件访问:推荐使用@ohos.fileio模块的copy接口将resources文件拷贝到应用沙盒目录(context.filesDir)
  2. 下载文件处理:网络下载的文件应直接保存到沙盒目录,无需二次拷贝
  3. 路径传递:将沙盒中的文件路径通过NAPI传递给C++层

当前HarmonyOS的安全机制限制了native层直接访问非沙盒目录,这是出于安全考虑的设计。与Android不同,HarmonyOS没有提供直接开放目录权限给native层访问的机制。

对于文件操作,可以使用@ohos.file.fs模块的相关API进行文件拷贝和管理。例如使用copyFile()方法将文件复制到沙盒目录。

回到顶部