2012-07-02 10 views
22

Ich versuche eine Android-App zu erstellen, die die NativeActivity-Funktion des NDK verwendet. ich die folgende Struktur:Android - Schreiben/Speichern von Dateien nur aus nativem Code

  • eine Reihe von nativen gemeinsam genutzten Bibliotheken in /system/vendor/<company> installiert; Ich arbeite mit einem benutzerdefinierten Android Bild gebaut, so gibt es kein Problem gibt es die Bibliotheken, die mit richtigen Berechtigungen und alles
  • ein paar Anwendungen, die die NativeActivity verwenden, die oben
  • erwähnten auf den Bibliotheken wiederum von

Die im/system/vendor und in meinen Anwendungen installierten Bibliotheken verwenden einige Konfigurationsdateien . Es ist kein Problem, sie mit der Standard-C-API fopen/fclose zu lesen. Aber diese Bibliotheken und meine Anwendung müssen auch einige Dateien als Ergebnis ihrer Operation speichern, wie Konfiguration, einige Laufzeit-Parameter, Kalibrierung Daten, Protokolldateien usw. Mit dem Speichern der Dateien gibt es ein kleines Problem, wie ich Ich darf nicht in /system/vendor/... schreiben (da das Dateisystem unter "/ system/..." schreibgeschützt ist und ich will das nicht hacken).

Also, was wäre der beste Weg, um diese Dateien zu erstellen und zu speichern und wo wäre die beste "konform mit Android" Speicherbereich?

Ich habe in der Android-NDK Google-Gruppe ein paar Threads zu lesen und hier auf, so dass entweder the internal application private storage oder the external SD card, erwähnt aber da ich keine Erfahrung mit Android erweitert habe wir bin ich nicht sicher, was das sein würde, richtiger Ansatz. Wenn der Ansatz eine bestimmte Android-API umfasst, wäre ein kleines Codebeispiel in C++ sehr hilfreich. Ich habe ein paar Beispiele gesehen, die Java und JNI betreffen (e.g. in this SO question), aber ich möchte mich jetzt davon fernhalten. Es scheint auch ein Problem bei der Verwendung von C++ der nativen Aktivität internalDataPath/externalDataPath-Paar (a bug that makes them be always NULL) zu sein.

Antwort

23

Für relativ kleine Dateien (Anwendungskonfigurationsdateien, Parameterdateien, Protokolldateien usw.) empfiehlt es sich, den internen privaten Anwendungsspeicher zu verwenden, also /data/data/<package>/files. Der externe Speicher (falls es eine SD-Karte ist oder nicht) sollte für große Dateien verwendet werden, die keinen häufigen Zugriff oder Aktualisierungen benötigen.

Für die externe Datenspeicherung der native Anwendung hat auf „Anfrage“ über die richtigen Berechtigungen in der AndroidManifest.xml Anwendung:

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

Für die interne Anwendung privaten Lagerhaltung fopen/fclose (oder C++ Stream-Äquivalente falls vorhanden) API sein könnte benutzt. Das folgende Beispiel veranschaulicht die Verwendung des Android NDK AssetManager zum Abrufen und Lesen einer Konfigurationsdatei. Die Datei muss in das Verzeichnis assets im Projektordner der nativen Anwendung platziert werden, damit der NDK-Build sie in das APK packen kann. Der internalDataPath/externalDataPath Bug, den ich in der Frage erwähnt habe, wurde für die NDK r8 Version behoben.

... 
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); 
     } 
    } 
} 
Verwandte Themen