I am using package flutter_downloader for ios.
The file seems to be downloading fine, but I cannot find the file on my device anywhere after it is downloaded.
I download it like this:
final taskId = await FlutterDownloader.enqueue(
url: ref.read(resumeUrlSD),
headers: {}, // optional: header send with url (auth token etc)
// savedDir: externalDir!.path,
savedDir: _localPath,
showNotification: true,
openFileFromNotification: true,
saveInPublicStorage: _saveInPublicStorage,
);
In the console it shows:
externalStorageDirPath IOS: /var/mobile/Containers/Data/Application/014DCD70-5E34-41A3-95E0-868FEA48A189/Documents
This is where I set up the download task:
late String _localPath;
late bool _permissionReady;
final bool _saveInPublicStorage = true;
final ReceivePort _port = ReceivePort();
bool hasResume = false;
@override
void initState() {
super.initState();
_bindBackgroundIsolate();
FlutterDownloader.registerCallback(downloadCallback, step: 1);
_prepare();
}
@pragma('vm:entry-point')
static void downloadCallback(
String id,
DownloadTaskStatus status,
int progress,
) {
print(
'Callback on background isolate: '
'task ($id) is in status ($status) and process ($progress)',
);
IsolateNameServer.lookupPortByName('downloader_send_port')
?.send([id, status, progress]);
if(status.toString() == "DownloadTaskStatus(3)" && progress == 100){
print('2124:DOWNLOAD COMPLETE');
FlutterDownloader.open(taskId: id);
}
}
@override
void dispose() {
_unbindBackgroundIsolate();
super.dispose();
}
void _bindBackgroundIsolate() {
final isSuccess = IsolateNameServer.registerPortWithName(
_port.sendPort,
'downloader_send_port',
);
if (!isSuccess) {
_unbindBackgroundIsolate();
_bindBackgroundIsolate();
return;
}
_port.listen((dynamic data) {
final taskId = (data as List<dynamic>)[0] as String;
final status = data[1] as DownloadTaskStatus;
final progress = data[2] as int;
print(
'Callback on UI isolate: '
'task ($taskId) is in status ($status) and process ($progress)',
);
print('2124: PROGRESS $progress');
if(progress == 100){
print('2124: PROGRESS 100');
OpenFilex.open(_localPath);
Fluttertoast.showToast(
msg: 'Coming soon', toastLength: Toast.LENGTH_LONG, timeInSecForIosWeb: 3);
}
// if (_tasks != null && _tasks!.isNotEmpty) {
// final task = _tasks!.firstWhere((task) => task.taskId == taskId);
// setState(() {
// task
// ..status = status
// ..progress = progress;
// });
// }
});
}
void _unbindBackgroundIsolate() {
IsolateNameServer.removePortNameMapping('downloader_send_port');
}
Future<void> _prepareSaveDir() async {
_localPath = (await _getSavedDir())!;
final savedDir = Directory(_localPath);
if (!savedDir.existsSync()) {
await savedDir.create();
}
}
Future<String?> _getSavedDir() async {
String? externalStorageDirPath;
if (Platform.isAndroid) {
try {
externalStorageDirPath = await AndroidPathProvider.downloadsPath;
print('2124: externalStorageDirPath: $externalStorageDirPath');
} catch (err, st) {
print('failed to get downloads path: $err, $st');
final directory = await getExternalStorageDirectory();
externalStorageDirPath = directory?.path;
}
} else if (Platform.isIOS) {
externalStorageDirPath =
(await getApplicationDocumentsDirectory()).absolute.path;
print('2124: externalStorageDirPath IOS: $externalStorageDirPath');
}
return externalStorageDirPath;
}
Future<void> _prepare() async {
_permissionReady = await _checkPermission();
if (_permissionReady) {
await _prepareSaveDir();
}
}
Future<bool> _checkPermission() async {
if (Platform.isIOS) {
return true;
}
if (Platform.isAndroid) {
final status = await Permission.storage.status;
if (status == PermissionStatus.granted) {
return true;
}
final result = await Permission.storage.request();
return result == PermissionStatus.granted;
}
throw StateError('unknown platform');
}
It seems to download fine. Here is the log:
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(1)) and process (0)
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (1)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (3)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (5)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (7)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (9)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (11)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (13)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (15)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (17)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (19)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (21)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (23)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (25)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (27)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (29)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (31)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (33)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (35)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (37)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (39)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (41)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (43)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (45)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (47)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (49)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (51)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (53)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (56)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (58)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (60)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (62)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (64)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (66)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (68)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (70)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (72)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (74)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (76)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (78)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (80)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (82)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (84)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (86)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (88)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (90)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (92)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (94)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (96)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (98)
Query was executed successfully. Affected rows = 1
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(2)) and process (100)
Query was executed successfully. Affected rows = 1
-[FlutterDownloaderPlugin URLSession:downloadTask:didFinishDownloadingToURL:] HTTP status code: 200
SuggestedFileName: --PDF.pdf
Query was executed successfully. Affected rows = 1
savedDir: /var/mobile/Containers/Data/Application/014DCD70-5E34-41A3-95E0-868FEA48A189/Documents
filename: --PDF.pdf
flutter: Callback on background isolate: task (com.mekudeshet.download.task.31006.1683227407.679338) is in status (DownloadTaskStatus(3)) and process (100)
Query was executed successfully. Affected rows = 1
-[FlutterDownloaderPlugin URLSession:task:didCompleteWithError:] HTTP status code: 200
But I can’t find it in the files folder on my device?
2
Answers
The answer is:
Add to info.plist:
As posted here: https://stackoverflow.com/questions/59501445/flutter-how-to-save-a-file-on-ios#:~:text=Add%20to%20info.plist%3A%20%3Ckey%3EUISupportsDocumentBrowser%3C/key%3E%20%3Ctrue/%3E%20%3Ckey%3ELSSupportsOpeningDocumentsInPlace%3C/key%3E%20%3Ctrue/%3E%20%3Ckey%3EUIFileSharingEnabled%3C/key%3E%20%3Ctrue/%3E
Usually downloaded files are inside temporary files of this app. You can use any library (for example path_provider ) to localize this file.
If You want use Android
Download
folder, You need special permission (access to phone directories).Maybe here You have everything what You need: https://pub.dev/packages/path_provider
and moreover: https://docs.flutter.dev/cookbook/persistence/reading-writing-files