Android Berechtigung neu erstellter Datei (Flutter/Dart)

Drexel

Lt. Commander
Registriert
Jan. 2012
Beiträge
1.917
Hallo Forum,

ich entwickel gerade eine Android (und potenziell auch iOS) App mit Flutter. Ich habe auch einen Datenexport für die App geschrieben, der funtkioniert auch soweit.

Hier der Code dazu:

Code:
  Future<void> exportDatabase() async {
    _fileTransfering = true;
    await _database!.close();
    //will probably only work on Android, for iOS maybe another solution like the os' share functionality is needed
    Directory exportDirectory = Directory(join((await getExternalStorageDirectory())!.path, OpenEatsJournalStrings.export));
    await exportDirectory.create(recursive: true);
    String targetFile = join(exportDirectory.path, _databaseFileName);
    File sourceFile = File(_databaseFile);
    await sourceFile.copy(targetFile);
    _database = await _initDb();
    _fileTransfering = false;
  }

Den Zielpfad hole ich mittels getExternalStorageDirectory() aus der path_provider Extension, das ist ein Bereich wo eine App ohne weitere App Berechtigungen reinschreiben darf.

Bis hierhin dachte ich, dass es gut funktioniert, bis ich probiert habe auf die Datei von meinem PC aus zuzugreifen. Ich sehe die Datei zwar, aber kann sie nicht lesen/kopieren. Ich habe festgestellt, dass das an den Dateiberechtigungen liegt, es scheint auch im Bereich des normalen zu sein.

So sehen die Dateiberechtigungen auf der Command Line mit
c:\sdks\Android\platform-tools\adb -s 28051FDH300A6D shell ls -all /storage/emulated/0/Android/data/com.drexeldevelopment.openeatsjournal/files/export/
aus:
1769174034349.png

Nur der Owner darf lesen und schreiben. Das scheint wohl je nach Verzeichnis auch relativ normales Verhalten zu sein, habe diesen Artikel dazu gefunden:
https://waqasyounis334.medium.com/u...permissions-in-android-and-linux-f1ec1eb2b0b7
Ich denke die Group ext_data_rw brauch auch noch Berechtigungen, so sieht es zumindest bei anderen Apps in der Verzeichnisstruktur aus und darauf kann ich dann auch zugreifen:

c:\sdks\Android\platform-tools\adb -s 28051FDH300A6D shell ls -all /storage/emulated/0/Android/data/com.ebay.kleinanzeigen/files/logs
1769174493845.png

So nun finde ich wenige Infos dazu, wie man die Dateiberechtigungen mit Flutter/Dart richtig setzt, hat jemand Erfahrung damit?

Da denk ich mir immer, das kann doch bei sowas trivialem wie eine Datei zu speichern nicht sein. :D
 
Du hast nicht dazu geschrieben, was du erreichen willst. Die kurze Antwort: Das ist "so kompliziert", weil du es wahrscheinlich falsch machst.

Entweder, die Datei ist "Interna" deiner App. Das ist, wie du es aktuell machst, und dann sind die Rechte auch fein so.
Oder, die Datei ist als "Export" gedacht, dann ist dein Ansatz falsch. Wenn du das machen willst, musst du die Datei "teilen", und der User entscheidet, was er damit tun möchte (bekommt seine Apps vorgeschlagen, die was mit Dateien machen können, bzw. in Windows automatisch den Datei speichern Dialog, wenn man das share plus package nutzt).
 
Ok, dann wie gesagt, ist vorgesehen das mit dem share Feature zu machen.
Ich habe eine App, die ganz genau das gleiche tut, also seine DB ex- und importieren kann, plattformunabhängig.
 
  • Gefällt mir
Reaktionen: Drexel
Ok, dann werde ich das auch nochmal so machen, dann braucht die App Storage Berechtigungen im Manifest oder? Hatte ja schon im Kommentar vermerkt, dass es für andere OS' wahrscheinlich nur über die Share Funktionalität funktioniert...

Dennoch frage ich mich wie andere Apps das machen... Habe bisher auch eine andere Nutrition App genutzt, die ich durch meine eigene gerade ersetze, die exportiert auch CSV Files in den Android/Data/App-Name Ordner, die ich ganz einfach auf meinen PC kopieren kann...
 
Zuletzt bearbeitet:
Jau danke bin schon am umbauen. Die von Dir verlinkten Seiten und Artikel habe ich auch alle schon gesehen. ;)
Ergänzung ()

Ok Share war auch nicht die richtige Lösoung, mit einem Binary File gibt einem der Share Dialog keine lokalen Ziele wie die File App.

Aber die Lösung lag so nahe, ich habe ja eh schon das FilePicker Plugin, ich mach das jetzt damit.
Erstmal die Datenbank in ein internes Verzeichnis wegkopieren im geschlossenen Zustande:

Code:
  Future<String> exportDatabase() async {
    _fileTransfering = true;
    await _database!.close();
    //will probably only work on Android, for iOS maybe another solution like the os' share functionality is needed
    Directory exportDirectory = Directory(join((await getApplicationDocumentsDirectory()).path, OpenEatsJournalStrings.export));
    await exportDirectory.create(recursive: true);
    String targetFile = join(exportDirectory.path, _databaseFileName);
    File sourceFile = File(_databaseFile);
    await sourceFile.copy(targetFile);
    _database = await _initDb();
    _fileTransfering = false;
    return targetFile;
  }

Und dann den User fragen wohin gespeichert werden soll:
Code:
  Future<bool> exportDatabase() async {
    String exportPath = await _settingsRepository.exportDatabase();
    String? outputFile = await FilePicker.platform.saveFile(fileName: basename(exportPath), bytes: await File(exportPath).readAsBytes());
    if (outputFile != null) {
      return true;
    }
    return false;
  }
 
Zuletzt bearbeitet:
Enurian schrieb:
Deine Datenbankdatei wird eben inklusive Rechten kopiert. Andere Apps erstellen die Datei vielleicht direkt in dem Verzeichnis oder nutzen kein Flutter.
Ich hab jetzt eine funktionierende Lösung, aber rein aus Interesse werde ich mal versuchen, eine neue Datei in dem getExternalStorageDirectory Ordner zu erstellen und dann einen ByteStream reinzuschreiben, mal sehen ob das geht.
 
  • Gefällt mir
Reaktionen: Enurian
Ok, das war der entscheidende Hinweis, bin jetzt wieder zur alten Lösung zurück mit ein paar Anpasungen:

Code:
  Future<bool> exportDatabase() async {
    _fileTransfering = true;
    try {
      await _database!.close();
      //will probably only work on Android, for iOS maybe another solution like the os' share functionality is needed
      Directory exportDirectory = Directory(join((await getExternalStorageDirectory())!.path, OpenEatsJournalStrings.export));
      await exportDirectory.create(recursive: true);
      File targetFile = File(join(exportDirectory.path, _databaseFileName));
      if (targetFile.existsSync()) {
        targetFile.deleteSync();
      }
      File sourceFile = File(_databaseFile);
      IOSink targetStream = targetFile.openWrite();
      await targetStream.addStream(sourceFile.openRead());
      _database = await _initDb();
    } catch (e) {
      return false;
    }
    _fileTransfering = false;
    return true;
  }

So kann ich sie per USB aus dem Verzeichnis kopieren. Und es wird über Streams gelesen und geschrieben, d.h. es sollte auch wenn die Datei größer wird keine Probleme geben. Bei der FilePicker Lösung musste der gesamt Bytestream im voraus geladen werden...
 
Zurück
Oben