28

我正在尝试构建一个利用NativeActivityNDK 功能的 Android 应用程序。我有以下结构:

  • 一堆本地共享库安装在/system/vendor/<company>;我正在使用自定义构建的 Android 映像,因此那里的库具有适当的权限和一切都没有问题
  • 使用 的几个应用程序NativeActivity又依赖于上面提到的库

/system/vendor 中安装的库和我的应用程序使用了几个配置文件。使用标准 C API 阅读它们没有问题 fopen/fclose。但是这些库和我的应用程序还需要存储一些文件作为它们的操作结果,比如配置、一些运行时参数、校准数据、日志文件等。随着文件的存储,我有一个小问题不允许写入/system/vendor/...(因为“/system/...”下的文件系统是只读安装的,我不想破解它)。

那么创建和存储这些文件的最佳方式是什么?最好的“符合 Android”存储区域在哪里?

我一直在阅读 android-ndk Google 组中的几个线程,并且在这里提到了内部应用程序私有存储外部 SD 卡,但由于我没有使用 Android 的扩展经验,我不确定是什么将是正确的方法。如果该方法涉及某些特定的 Android API,则 C++ 中的小代码示例将非常有帮助;我见过几个涉及 Java 和 JNI 的例子(例如在这个 SO question 中),但我现在想远离那个。internalDataPath/externalDataPath从 C++ 使用本机活动的对似乎也存在问题 (一个使它们始终为 NULL 的错误)。

4

1 回答 1

29

对于比较小的文件(应用配置文件、参数文件、日志文件等)最好使用内部应用私有存储,即/data/data/<package>/files. 如果外部存储存在(无论是否为 SD 卡),则应将其用于不需要频繁访问或更新的大文件。

对于外部数据存储,本机应用程序必须“请求”应用程序的正确权限AndroidManifest.xml

<manifest>
    ... 
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE">
    </uses-permission>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"> 
    </uses-permission>
</manifest>  

对于内部应用程序私有存储fopen/fclose(或 C++ 流等价物,如果可用),可以使用 API。以下示例说明了使用 Android NDKAssetManager检索和读取配置文件。该文件必须放在assets本机应用程序的项目文件夹内的目录中,以便 NDK 构建可以将它们打包到 APK 中。我在问题中提到的internalDataPath/externalDataPath错误已针对 NDK r8 版本修复。

...
void android_main(struct android_app* state)
{
    // Make sure glue isn't stripped 
    app_dummy();

    ANativeActivity* nativeActivity = state->activity;                              
    const char* internalPath = nativeActivity->internalDataPath;
    std::string dataPath(internalPath);                               
    // internalDataPath points directly to the files/ directory                                  
    std::string configFile = dataPath + "/app_config.xml";

    // sometimes if this is the first time we run the app 
    // then we need to create the internal storage "files" directory
    struct stat sb;
    int32_t res = stat(dataPath.c_str(), &sb);
    if (0 == res && sb.st_mode & S_IFDIR)
    {
        LOGD("'files/' dir already in app's internal data storage.");
    }
    else if (ENOENT == errno)
    {
        res = mkdir(dataPath.c_str(), 0770);
    }

    if (0 == res)
    {
        // test to see if the config file is already present
        res = stat(configFile.c_str(), &sb);
        if (0 == res && sb.st_mode & S_IFREG)
        {
            LOGI("Application config file already present");
        }
        else
        {
            LOGI("Application config file does not exist. Creating it ...");
            // read our application config file from the assets inside the apk
            // save the config file contents in the application's internal storage
            LOGD("Reading config file using the asset manager.\n");

            AAssetManager* assetManager = nativeActivity->assetManager;
            AAsset* configFileAsset = AAssetManager_open(assetManager, "app_config.xml", AASSET_MODE_BUFFER);
            const void* configData = AAsset_getBuffer(configFileAsset);
            const off_t configLen = AAsset_getLength(configFileAsset);
            FILE* appConfigFile = std::fopen(configFile.c_str(), "w+");
            if (NULL == appConfigFile)
            {
                LOGE("Could not create app configuration file.\n");
            }
            else
            {
                LOGI("App config file created successfully. Writing config data ...\n");
                res = std::fwrite(configData, sizeof(char), configLen, appConfigFile);
                if (configLen != res)
                {
                    LOGE("Error generating app configuration file.\n");
                }
            }
            std::fclose(appConfigFile);
            AAsset_close(configFileAsset);
        }
    }
}
于 2012-07-18T08:49:30.687 回答