Android-escribir / guardar archivos solo desde código nativo


Estoy tratando de construir una aplicación para Android que hace uso de la instalación NativeActivity del NDK. Estoy teniendo la siguiente estructura:

  • un montón de bibliotecas compartidas nativas instaladas en /system/vendor/<company>; Estoy trabajando con una imagen de Android personalizada, por lo que no hay problema en tener las bibliotecas allí con permisos adecuados y todo
  • un par de aplicaciones usando el NativeActivity que dependen a su vez de las bibliotecas antes mencionado

Las bibliotecas instaladas en el /system / vendor y mis aplicaciones utilizan un par de archivos de configuración. No hay problema en leerlos usando la API C estándar fopen/fclose. Pero esas bibliotecas y mi aplicación también necesitan almacenar algunos archivos como resultado de su funcionamiento, como la configuración, algunos parámetros de tiempo de ejecución, calibración datos, archivos de registro, etc. Con el almacenamiento de los archivos hay un pequeño problema ya que no se me permite escribir en /system/vendor/... (como el sistema de archivos bajo "/system/..."está montado de solo lectura y no quiero hackear sobre eso).

Entonces, ¿cuál sería la mejor manera de crear y almacenar esos archivos y dónde estaría el mejor" conforme con Android " área de almacenamiento ?

He estado leyendo un par de hilos en el grupo de Google android-ndk y aquí para que mencione ya sea la aplicación interna de almacenamiento privado o la tarjeta SD externa, pero como no tengo experiencia extendida con Android No estoy seguro de cuál sería el enfoque adecuado. Si el enfoque implica algún Android API un pequeño ejemplo de código en C++ sería muy útil; he visto un par de ejemplos que involucran Java y JNI (por ejemplo, en esta pregunta SO), pero me gustaría mantenerme alejado de eso en este momento. También parece haber un problema con el uso de C++ de la actividad nativa internalDataPath/externalDataPath par (un error que hace que sean siempre NULL).

Author: Community, 0000-00-00

1 answers

Para archivos relativamente pequeños(archivos de configuración de aplicaciones, archivos de parámetros, archivos de registro, etc.) lo mejor es utilizar la aplicación interna almacenamiento privado, que es /data/data/<package>/files. El almacenamiento externo si existe (ya sea tarjeta SD o no) debe usarse para archivos grandes que no necesitan acceso frecuente o actualizaciones.

Para el almacenamiento de datos externo la aplicación nativa tiene que" solicitar " los permisos correctos en el AndroidManifest.xml de la aplicación:

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

Para la aplicación interna privada se podría usar la API storage fopen/fclose(o equivalentes de flujo de C++ si están disponibles). El siguiente ejemplo ilustra el uso de Android NDK AssetManager para recuperar y leer un archivo de configuración. El archivo debe colocarse en el directorio assets dentro de la carpeta de proyecto de la aplicación nativa para que la compilación NDK pueda empaquetarlos dentro del APK. El error internalDataPath/externalDataPath que mencionaba en la pregunta fue corregido para la versión 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);
        }
    }
}
 25
Author: celavek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-06-26 14:48:44