miDeb / digitales_register

Inoffizielle App für das Digitale Register (https://digitalesregister.it)
GNU General Public License v3.0
16 stars 3 forks source link

Message attachments can't be opened on iOS, macOS (and maybe other platforms) #18

Closed jbksr closed 10 months ago

jbksr commented 1 year ago

Flutter run log on macOS: [log] failed to download file https://osz-schlanders.digitalesregister.it/v2/api/message/messageSubmissionDownloadEntry: PathAccessException: Cannot open file, path = '/Users/user/Library/Containers/com.package/Data/Downloads/msg_22_9_07.09.2023 Mitteilung Eltern.pdf' (OS Error: Operation not permitted, errno = 1)

Flutter run log on iOS: [log] failed to download file https://osz-schlanders.digitalesregister.it/v2/api/message/messageSubmissionDownloadEntry: PathNotFoundException: Cannot open file, path = '/var/mobile/Containers/Data/Application/F0C2B614-0C82-4C09-BBEA-52669AEB7E52/Downloads/msg_22_9_07.09.2023 Mitteilung Eltern.pdf' (OS Error: No such file or directory, errno = 2)

jbksr commented 1 year ago

Seems to fail on these lines in middleware.dart. Permission issue?

final sink = saveFile.openWrite();
await sink.addStream((result.data as dio.ResponseBody).stream);
await sink.flush();
await sink.close();
jbksr commented 1 year ago
Future<bool> downloadFile(
  String url,
  String fileName,
  Map<String, dynamic> parameters,
) async {
  await wrapper.ensureLoggedIn();

  File saveFile = File(
    "${await _getAttachmentDownloadDirectory()}/$fileName",
  );

  // TODO: Just temporary
  if (Platform.isIOS) {
    saveFile = File(
      "${(await getApplicationDocumentsDirectory()).path}/$fileName",
    );
  }

  ...
}

This could work?

miDeb commented 1 year ago

I think the problem is that the downloads directory does not exist yet, we have to create it before being able to use it. I will have a look later today.

jbksr commented 1 year ago
Future<String> _getAttachmentDownloadDirectory() async {
  try {
    Directory? directory;

    if (Platform.isIOS || Platform.isMacOS) {
      directory = await getApplicationDocumentsDirectory();
    } else {
      directory = await getDownloadsDirectory();
    }

    if (directory != null) {
      return directory.path;
    }
  } catch (_) {}
  return (await getApplicationDocumentsDirectory()).path;
}

This seems to work both for iOS and macOS. But I'm worried this might break something for devices running older iOS and macOS versions.

jbksr commented 1 year ago

Also worth mentioning is that the Play Store Android version has a similar behaviour (does not open the file). But for some weird reason it works just fine when debugging.

This might be specific to my phone though. I'll ask my classmates if they also have this issue on Android.

jbksr commented 12 months ago

Sorry for that above, accidentally pressed the wrong button.

Screenshot_2023-09-25-07-08-46-543_com android chrome-edit docs.flutter.dev

This Flutter docs article states that we should use the documents directory for persisting user data.

Future<String> get _localPath async {
  final directory = await getApplicationDocumentsDirectory();

  return directory.path;
}

I'll try to migrate the _getAttachmentDownloadDirectory function to use this instead of the getDownloadsDirectory and then test it on different devices.

miDeb commented 11 months ago

Sounds good, did you get to checking if this works better? For what it's worth I'm receiving some bug reports along the lines of

ProcessException: Das System kann die angegebene Datei nicht finden.

  Command: open "C:\Users\xxx\Downloads/hw_409_1534_xxxxxxxxxxx xxxxx xxx.png"

Seems those issues on windows platforms are also related to this bug.

jbksr commented 11 months ago

Oh damn, I haven’t looked at this in ages. But thanks for reminding me, I‘ll go work on this in the holidays. It’s very annoying.

miDeb commented 11 months ago

No worries :) Let me know when you're stuck on something, I should also have more time in the holidays to respond much quicker

jbksr commented 11 months ago

Awesome, thank you so much for the support! :) I decided to get started on fixing the download directory issue. This is what I've come up with:

Note: It's very similar to the previous implementation but seems to be more reliable. Android and macOS seem to use the system download directory. iOS not, it just works using the application documents directory. This may or may not be solved by updating some permissions, not sure. I will try to test it on Windows and Linux now and will post an update as soon I know more. 👍

Future<String> _getAttachmentDownloadDirectory() async {
  // TODO: this remains to be tested on all platforms
  try {
    return (await getExternalStorageDirectories(
            type: StorageDirectory.downloads))!.first.path;
  } catch (_) {
    log("failed to get download directory, falling back to application storage");
    return (await getApplicationDocumentsDirectory()).path;
  }
}
jbksr commented 11 months ago

I've had some issues compiling for Linux (Zorin OS 16.3), but it works now. Files get downloaded and opened, but they're not getting stored in downloads, but in some temporary directory. Weird, because the getExternalStorageDirectories function does not fail. This might become a problem at a later point, I hope not.

Now Windows, another adventure probably 😂

miDeb commented 11 months ago

Did you test the flatpak version for linux? I don't know if it behaves differently because it is supposed to be a sandbox and not allow programs to access user files. But it shouldn't be a problem because if I remember correctly the file will just be downloaded again if it no longer exists. Anyway, most users are probably using Android or iOS, so it's important those platforms work, and only a few are on macOS, Windows and even fewer on Linux. But I appreciate your testing... I have to admit I usually only tested one or two platforms when making changes like this.

jbksr commented 11 months ago

Hmm, no I haven't tested that. I just used the normal Flutter release build on Linux. But like you said, I think there are very few people using Linux so it should be fine. Anyways, I've compiled it for Windows, it launches but I can't log in. It says there's no internet connection. I've also tried the existing version directly from the Microsoft Store and still the same thing. So unfortunately I wasn't able to test that. "Keine Verbindung mit "..." möglich. Bitte überprüfe deine Internetverbindung. Wenn du ..."

I've just created a pull request #20 and hopefully the Windows internet issues are just specific to my machine.

miDeb commented 10 months ago

Anyways, I've compiled it for Windows, it launches but I can't log in. It says there's no internet connection. I've also tried the existing version directly from the Microsoft Store and still the same thing. So unfortunately I wasn't able to test that. "Keine Verbindung mit "..." möglich. Bitte überprüfe deine Internetverbindung. Wenn du ..."

I couldn't reproduce this on my machine on a fresh install (I get the correct user_not_found error from the server), so it's hopefully not a bug with the app.

miDeb commented 10 months ago

Closing this, as hopefully this has now been fixed by #20.