I ended up using multiple libraries - one for desktop, one for mobile, and one for web. This is because file_picker wasn’t working for snap, but file_selector doesn’t work for mobile, and neither work for saving files when running on the web.
I’ve outlined it below for anyone else having this issue (the below is changed from my own code to make it simpler/clearer for the sake of the example).
pubspec.yaml
dependencies:
file_picker: ^8.1.2
file_selector: ^1.0.3
import_data.dart
import "package:file_picker/file_picker.dart";
import "package:file_selector/file_selector.dart";
Future<void> _openDesktop() async {
XTypeGroup types = const XTypeGroup(
label: "JSON",
extensions: ["json"],
);
XFile? file = await openFile(
acceptedTypeGroups: [types],
);
if (file != null) {
String contents = await file.readAsString();
}
}
Future<void> _openMobile() async {
FilePickerResult? path = await FilePicker.platform.pickFiles(
dialogTitle: "Open File",
type: FileType.custom,
allowedExtensions: ["json"],
withReadStream: true,
lockParentWindow: true,
);
if (result != null) {
Stream<List<int>> stream = result.files.first.readStream!
StringBuffer buffer = StringBuffer();
stream.transform(utf8.decoder).listen((data) {
buffer.write(data);
},
onError: (exception) {
// Show an error message
},
onDone: () {
String contents = buffer.toString();
}
}
}
Future<void> _openWeb() async {
XTypeGroup types = const XTypeGroup(
label: "JSON",
extensions: ["json"],
);
FilePickerResult? result = openFile(
acceptedTypeGroups: [types],
);
if (result != null) {
String contents = await result.readAsString();
}
}
export_data.dart (obviously the contents isn’t valid JSON, just providing an example)
import "package:file_picker/file_picker.dart";
import "package:file_selector/file_selector.dart";
import "package:ledger/web_empty.dart"
if(dart.library.web) "package:web/web.dart";
Future<void> _saveDesktop() async {
XTypeGroup types = const XTypeGroup(
label: "JSON",
extensions: ["json"],
);
FileSaveLocation? result = await getSaveLocation(
acceptedTypeGroups: [types],
suggestedName: "Data.json",
);
if (result != null) {
await File(result.path).writeAsString("contents");
}
}
Future<void> _saveMobile() async {
await FilePicker.platform.saveFile(
dialogTitle: "Save File",
fileName: "Data.json",
type: FileType.custom,
allowedExtensions: ["json"],
bytes: utf8.encode("contents"),
lockParentWindow: true,
);
}
Future<void> _saveWeb() async {
String data = Uri.encodeComponent("contents");
HTMLAnchorElement()
..href = "data:text/plain;charset=utf-8,$data"
..download = "Data.json"
..click();
}
web_empty.dart (I had to create this otherwise it wouldn’t compile for snap - see the conditional import in export_data.dart)
class HTMLAnchorElement {
String download = "";
String href = "";
void click() {}
}
Hope this helps!