Подтвердить что ты не робот

Android - запись/сохранение файлов только из собственного кода

Я пытаюсь создать приложение для Android, которое использует средство NativeActivity для NDK. У меня есть следующая структура:

  • набор встроенных общих библиотек, установленных в /system/vendor/<company>; я работаю с пользовательским образцом для Android, поэтому нет проблем с наличием там библиотек с правильные разрешения и все
  • несколько приложений, использующих NativeActivity, которые в свою очередь зависят от библиотек упомянутый выше

Библиотеки, установленные в /system/vendor, и мои приложения используют пару файлы конфигурации. Там нет проблем с их чтением с использованием стандартного API C fopen/fclose. Но эти библиотеки и мое приложение также должны хранить некоторые файлы в результате их работы, например, конфигурации, некоторых параметров времени выполнения, калибровки данные, файлы журналов и т.д. При хранении файлов возникает небольшая проблема, так как мне не разрешено писать в /system/vendor/... (поскольку файловая система под "/system/..." смонтирована только для чтения, а я не хотите взламывать это).

Итак, что было бы лучшим способом создания и хранения этих файлов, и где бы лучше всего "соответствовать области Android"?

Я читал пару потоков в группе Android android-ndk Google, и здесь, на SO, которые упоминают либо внутреннее хранилище частных приложений, либо внешняя SD-карта, но, поскольку у меня нет расширенного опыта работы с Android, я не уверен, какой будет правильный подход. Если подход включает в себя некоторые конкретные Android API, небольшой пример кода на С++ будет очень полезен; Я видел несколько примеров, связанных с Java и JNI (например, в этом вопросе SO), но я хотел бы держаться подальше от этого прямо сейчас. Также, похоже, проблема с использованием на С++ родной активности internalDataPath/externalDataPath пара (ошибка, которая делает их всегда NULL).

4b9b3361

Ответ 1

Для относительно небольших файлов (файлы конфигурации приложений, файлы параметров, файлы журналов и т.д.) лучше использовать личное хранилище внутреннего приложения, то есть /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 (или эквиваленты потоков С++, если доступно) API может использоваться. Следующий пример иллюстрирует использование Android NDK AssetManager для извлечения и чтения файла конфигурации. Файл должен быть помещен в каталог 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 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 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);
        }
    }
}