I've been building an ios app and in it, it'll download a bunch of pdf from an API and save it to the local storage using the path_provider package in flutter:
This is the code I use to fetch the path:
Future<String> get localPath async {
final directory = await getApplicationDocumentsDirectory();
currentDir.value = directory.path;
return directory.path;}
And this is how I save it to the device:
Future<void> saveFilesToLocal(String url, String fileName) async {
try {
final path = await localPath;
final file = File('$path/$fileName');
if (await file.exists() == false) {
final response = await Dio().get(url,
options: Options(
responseType: ResponseType.bytes,
followRedirects: false,
receiveTimeout: 0));
final raf = file.openSync(mode: FileMode.write);
raf.writeFromSync(response.data);
await raf.close();
} else {
print("file already exists");
}
} catch (e) {
print('error: $e');
}
}
After I download and save the files to the storage, it'll be displayed as a gridview in the home page. To fetch that list of files I use this:
List<FileSystemEntity> files = [];
Future<void> getFilesList() async {
files.clear();
final path = await localPath;
Directory dir = Directory('$path');
files =
dir.listSync(recursive: true, followLinks: false);
update();
}
And all of this works fine in the ios device. But the current issue I'm facing while trying to run it on web is:
The package path_provider is not available for flutter web. I've been asked to create it as a web app too and I can't find an alternative for it. While looking for one I saw a post saying flutter web won't allow access to a device's local storage like that so it's not possible. Is it true? Is there a workaround? If it's about security, the app will only be run on specific devices. It won't be given to the public.
I am working on an app that should manage downloaded files.
For now I am able to download a file on both platforms, but I would need to know how can I get the downloaded files from the device.
This is the code used to download a file from Internet.
Future<void> downloadFile() async {
bool downloading = false;
var progressString = "";
final imgUrl = "https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4";
Dio dio = Dio();
try {
var dir = await getApplicationDocumentsDirectory();
print("path ${dir.path}");
await dio.download(imgUrl, "${dir.path}/demo.mp4",
onReceiveProgress: (rec, total) {
print("Rec: $rec , Total: $total");
downloading = true;
progressString = ((rec / total) * 100).toStringAsFixed(0) + "%";
});
} catch (e) {
print(e);
}
downloading = false;
progressString = "Completed";
print("Download completed");
}
The path print output for Android is:
path /data/user/0/red.faro.labelconciergeflutter/app_flutter
The path print output for iOS is:
path /var/mobile/Containers/Data/Application/9CFDC9E3-D9A9-4594-901E-427D44E48EB9/Documents
What I need is to know how can an app user access the downloaded files when the app is closed or there is no internet connection to open the file from the original URL?
For getting files from the device you may use file_picker package.
FilePickerResult? result = await FilePicker.platform.pickFiles();
if (result != null) {
File file = File(result.files.single.path);
} else {
// User canceled the picker
}
You also can use the File class from the dart:io library.
Future<File> get _localFile async {
final path = await _localPath;
return File('$path/counter.txt');
}
If your goal is to access commonly used locations on the device’s file system you can use the path_provider plugin.
Directory tempDir = await getTemporaryDirectory();
String tempPath = tempDir.path;
Directory appDocDir = await getApplicationDocumentsDirectory();
String appDocPath = appDocDir.path
I am tring to develop a app using Flutter Web to provide a gallery of mediafiles stored in an apache server. Currently I am using Dio to get files as bytes and then call saveAs javascript function to downloand files to client computer. While this approach works for small sized files, it gives out of memory error for big files in browser. My code to get files is as follows. Can you suggest me a better way to get files? Thanks.
response = await dio.get(
medialink,
cancelToken: cancelToken,
onReceiveProgress: (rcv, total) {
if (total != -1) {
setState(() {
progress = ((rcv / total) * 100).toStringAsFixed(0);
});
if (rcv == total) {
setState(() {
isDownloaded = true;
downloading = false;
});
}
}
else {
print("-1");
}
},
//Received data with List<int>
options: Options(
responseType: ResponseType.bytes,
followRedirects: false,
validateStatus: (status) { return status! < 500; }
),
);
I am stuck in issue with upload large file. A flutter application compiled for Web and App (Native) when file upload from app is working fine but web it hanged. how to send large file as stream request.
I am new in flutter and working on current existing app which has a feature to upload large tutorial video files and PDF files. requirement is to show the progress bar during the upload the file, currently app has I used dio but it hanged in web version and not file not upload operation going failed.
File size approximate 400MB to 700MB
Currently using following packages
dependencies:
http: ^0.12.2
dio: ^3.0.10
Could you please help me out for this issue?
I am trying to achieve with below code but some how it not working.
https://github.com/salk52/Flutter-File-Upload-Download
It's thrown an error like "Memory buffer allocation failed ", I am unable to update the version of dio or http due to other package goes disturb. somehow I have to achieve it using httpclient or dio. I could not update the version for package because it messed up other package dependency.
Sample ref. code as below:
File size approximate around 500 MB to 700MB
For ref. following code which using in code.
Dio package example:
#Dio example start
Future<NormalResponse> addSubjectMaterial(
{GetSubjectMaterial objSubMat,
bool isDelete,
PlatformFile objfile,
Function sendProgress,
Function receiveProgress,
dio.CancelToken cancelToken}) async {
NormalResponse objRes = NormalResponse();
try {
print(objSubMat.objMaterial.subjectId);
dio.FormData formData = dio.FormData();
formData.fields.add(MapEntry("ObjSubMat", json.encode(objSubMat)));
formData.fields.add(MapEntry("IsDelete", isDelete.toString()));
formData.fields
.add(MapEntry("ClassesId", AppConstants.classesId().toString()));
if (objfile != null) {
formData.files.add(
MapEntry("objfile", await getMultipartFile(objfile, "objfile")));
}
var resp = await dio.Dio().post(
AppConstants.addUpdateSubjectMaterial,
data: formData,
options: requestConfig,
cancelToken: cancelToken,
onSendProgress: sendProgress,
onReceiveProgress: receiveProgress,
);
// String respStr = resp.toString();
// objRes = NormalResponse.fromJson(json.decode(respStr));
objRes = NormalResponse.fromJson(resp.data);
} catch (err) {
objRes.err = err.toString();
objRes.isSuccess = false;
objRes.newId = -1;
sendProgress = null;
receiveProgress = null;
}
return objRes;
}
#Dio example end
#httpclient example code is there any solution with progress bar in this sample code.
Future<NormalResponse> addUpdateSubjectMaterialHttp(
{GetSubjectMaterial objSubMat,
bool isDelete,
PlatformFile objfile,
Function sendProgress,
Function receiveProgress,
dio.CancelToken cancelToken}) async {
NormalResponse objRes = NormalResponse();
try {
var req = http.MultipartRequest(
"POST",
Uri.parse(AppConstants.addUpdateSubjectMaterial),
);
req.headers.addAll({
'Content-type': 'application/json',
'Accept': 'application/json',
});
req.fields['ObjSubMat'] = json.encode(objSubMat);
req.fields['IsDelete'] = isDelete.toString();
req.fields['ClassesId'] = AppConstants.classesId().toString();
if (objfile != null) {
req.files.add(http.MultipartFile(
"objFile", objfile.readStream, objfile.size,
filename: objfile.name));
}
var resp = await req.send();
String result = await resp.stream.bytesToString();
objRes = NormalResponse.fromJson(json.decode(result));
print(objRes.isSuccess);
print(objRes.err);
print("Here done");
} catch (err) {
print(err);
throw err;
}
return objRes;
}
#httpclient
Http package example:
#example start
Future<NormalResponse> addSubjectMaterial(
{GetSubjectMaterial objSubMat,
bool isDelete,
PlatformFile objfile,
Function sendProgress,
Function receiveProgress,
dio.CancelToken cancelToken}) async {
NormalResponse objRes = NormalResponse();
try {
print(objSubMat.objMaterial.subjectId);
dio.FormData formData = dio.FormData();
formData.fields.add(MapEntry("ObjSubMat", json.encode(objSubMat)));
formData.fields.add(MapEntry("IsDelete", isDelete.toString()));
formData.fields
.add(MapEntry("ClassesId", AppConstants.classesId().toString()));
if (objfile != null) {
formData.files.add(
MapEntry("objfile", await getMultipartFile(objfile, "objfile")));
}
var resp = await dio.Dio().post(
AppConstants.addUpdateSubjectMaterial,
data: formData,
options: requestConfig,
cancelToken: cancelToken,
onSendProgress: sendProgress,
onReceiveProgress: receiveProgress,
);
// String respStr = resp.toString();
// objRes = NormalResponse.fromJson(json.decode(respStr));
objRes = NormalResponse.fromJson(resp.data);
} catch (err) {
objRes.err = err.toString();
objRes.isSuccess = false;
objRes.newId = -1;
sendProgress = null;
receiveProgress = null;
}
return objRes;
}
#example end
You must use Future, await and async which continues the task of streams in background thread while the UI of your application works smoothly.
import 'package:http/http.dart' as http;
import 'package:image_picker_saver/image_picker_saver.dart';
try {
var response = await http.get(imageURL); // problem is here (only working on http URL)
debugPrint(response.statusCode.toString());
var filePath = await ImagePickerSaver.saveFile(
fileData: response.bodyBytes);
var savedFile= File.fromUri(Uri.file(filePath));
print('Image path: $savedFile');
/* setState(() {
_imageFile = Future<File>.sync(() => savedFile);
});*/
} on PlatformException catch (error) {
print(error);
}
It looks similar to this: How to Download Video from Online and store it local Device then play video on Flutter apps Using video player?
Here's the answer I've given at the time:
You might wanna give a try to the dio package it is an http client that supports file downloading and save it locally to a given path.
Here's a code sample (source: iampawan's Github)
Future downloadFile(String url) async {
Dio dio = Dio();
try {
var dir = await getApplicationDocumentsDirectory();
await dio.download(url, "${dir.path}/myFile.txt", onProgress: (rec, total) {
print("Rec: $rec , Total: $total");
});
} catch (e) {
print(e);
}
print("Download completed");
}
You will also need path_provider tu use getApplicationDocumentsDirectory().