2012-07-02 15 views
22

Próbuję utworzyć aplikację na Androida, która korzysta z funkcji NDK w wersji NativeActivity. Mam następującą strukturę:Android - zapisywanie/zapisywanie plików tylko z kodu natywnego

  • grono rodzimych współdzielonych bibliotek zainstalowanych w /system/vendor/<company>; Pracuję z niestandardowy zbudowany Android obrazu, więc nie ma problemu konieczności bibliotek tam z odpowiednie uprawnienia i wszystko
  • kilka aplikacji wykorzystujących NativeActivity, które zależą z kolei od bibliotek wymienionych powyżej

Biblioteki zainstalowane w/system/vendor i moje aplikacje używają kilku plików konfiguracyjnych . Nie ma problemu z odczytaniem ich przy użyciu standardowego interfejsu API C fopen/fclose. Ale te biblioteki i moja aplikacja muszą również przechowywać niektóre pliki w wyniku ich działania, takie jak konfiguracja, niektóre parametry czasu pracy, dane kalibracji , pliki dziennika itp. Przy zapisywaniu plików występuje niewielki problem, ponieważ "nie wolno mi pisać do /system/vendor/... (ponieważ system plików w"/system/... "jest montowany tylko do odczytu i nie chcę na tym siekać).

Jaki byłby najlepszy sposób tworzenia i przechowywania tych plików i gdzie znajduje się najlepszy "zgodny z Androidem" obszar pamięci?

Czytałem kilka wątków w grupie android-ndk Google i tutaj na SO, które wymieniały the internal application private storage lub the external SD card, ale ponieważ nie mam rozszerzonego doświadczenia z Androidem, nie jestem pewien, co byłoby właściwe podejście. Jeśli podejście obejmuje pewien specyficzny interfejs API systemu Android, bardzo mały przykład kodu w C++ byłby bardzo pomocny; Widziałem kilka przykładów z udziałem Javy i JNI (e.g. in this SO question), ale chciałbym teraz trzymać się z dala od tego. Występuje również problem z używaniem z C++ natywnej aktywności: internalDataPath/externalDataPath para (a bug that makes them be always NULL).

Odpowiedz

23

Dla względnie małych plików (pliki konfiguracyjne aplikacji, pliki parametrów, pliki dzienników itp.) Najlepiej jest użyć wewnętrznej pamięci prywatnej aplikacji, czyli /data/data/<package>/files. Pamięć zewnętrzna, jeśli w ogóle istnieje (jest to karta SD lub nie), powinna być używana w przypadku dużych plików, które nie wymagają częstego dostępu lub aktualizacji.

dla zewnętrznego przechowywania danych natywna aplikacja musi „żądanie” odpowiednie uprawnienia w aplikacji 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> 

dla aplikacji wewnętrznej prywatnego przechowywania fopen/fclose (lub C++ ekwiwalentów strumienia jeśli są dostępne) API może być używany. Poniższy przykład ilustruje używanie systemu Android NDK AssetManager do pobierania i odczytywania pliku konfiguracyjnego. Plik należy umieścić w katalogu projektu natywnej aplikacji w katalogu assets, aby kompilacja NDK mogła je spakować wewnątrz pliku APK. Błąd internalDataPath/externalDataPath, o którym wspomniałem w pytaniu, został naprawiony dla wersji 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); 
     } 
    } 
} 
Powiązane problemy