2012-07-02 10 views
22

Estoy tratando de crear una aplicación para Android que haga uso de la instalación NativeActivity del NDK. estoy teniendo la siguiente estructura:Android - escribir/guardar archivos desde código nativo solo

  • un montón de bibliotecas compartidas nativas instaladas en /system/vendor/<company>; Estoy trabajando con una imagen Android hecha a la medida por lo que no hay ningún problema con las bibliotecas allí con permisos adecuados y todo
  • un par de aplicaciones que utilizan la NativeActivity que dependen a su vez de las bibliotecas mencionados anteriormente

Las bibliotecas instaladas en/system/vendor y my applications usan un par de archivos de configuración . No hay problema para leerlos con la norma C API fopen/fclose. Pero esas bibliotecas y mi aplicación también necesitan almacenar algunos archivos como resultado de su operación, como configuración, algunos parámetros de tiempo de ejecución, datos de calibración , archivos de registro, etc. Con el almacenamiento de los archivos hay un pequeño problema ya que No puedo escribir en /system/vendor/... (ya que el sistema de archivos en "/ system/..." está montado como de solo lectura y no quiero hackearlo).

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

He estado leyendo un par de temas en el grupo de Google android-ndk y aquí en SO que mencionan the internal application private storage o the external SD card, pero como no tengo una experiencia extendida con Android no estoy seguro de cuál sería el enfoque apropiado. Si el enfoque implica alguna API de Android específica, un pequeño ejemplo de código en C++ sería muy útil; He visto un par de ejemplos que involucran a Java y JNI (e.g. in this SO question) pero me gustaría mantenerme alejado de eso en este momento. También parece que hay un problema con el uso de C++ el par de la actividad nativa (a bug that makes them be always NULL).

Respuesta

23

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

Para el almacenamiento externo de datos la aplicación nativa tiene que "solicitud" los permisos correctos en 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 de almacenamiento privado fopen/fclose (o C++ equivalentes corriente si está disponible) API podría ser usado. 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 del proyecto de la aplicación nativa para que la compilación NDK pueda empaquetarlos dentro del APK. El error internalDataPath/externalDataPath que mencioné en la pregunta se corrigió 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); 
     } 
    } 
} 
Cuestiones relacionadas