Android - запись / сохранение файлов только из собственного кода
Я пытаюсь создать приложение для Android, которое использует NativeActivity
Учреждение НДК. У меня есть следующая структура:
- куча собственных общих библиотек, установленных в
/system/vendor/<company>
; Я работаю с пользовательским образом Android, так что нет проблем с библиотеками с соответствующими разрешениями и всем - пара приложений, использующих
NativeActivity
которые в свою очередь зависят от библиотек, упомянутых выше
Библиотеки, установленные в /system/vendor, и мои приложения используют несколько файлов конфигурации. Там нет проблем, читая их с помощью стандартного C APIfopen/fclose
, Но эти библиотеки и мое приложение также должны хранить некоторые файлы в результате их работы, такие как конфигурация, некоторые параметры времени выполнения, данные калибровки, файлы журналов и т. Д. При хранении файлов возникает небольшая проблема, поскольку я не разрешено писать в /system/vendor/...
(поскольку файловая система в "/system/..." монтируется только для чтения, и я не хочу взламывать это).
Итак, что будет лучшим способом для создания и хранения этих файлов и где будет наилучшая область хранения "в соответствии с Android"?
Я читал несколько веток в группе Google android-ndk и здесь, на SO, в которых упоминается либо внутреннее частное хранилище приложения, либо внешняя SD-карта, но поскольку у меня нет большого опыта работы с Android, я не уверен, что будет правильным подходом. Если в подходе используется какой-то конкретный Android API, небольшой пример кода на C++ был бы очень полезен; Я видел пару примеров, связанных с Java и JNI ( например, в этом вопросе SO), но я бы хотел избежать этого прямо сейчас. Также, кажется, есть проблема с использованием из C++ нативной активностиinternalDataPath/externalDataPath
пара ( ошибка, которая делает их всегда NULL).
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
(или C++ потоковые эквиваленты, если доступны) 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'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);
}
}
}