I'm using Flutter Downloader to download PDF files from an API. On Android I have no issues with the plugin, but on iOS, when the file download URL comes with a space, the file is not downloaded.
final status = await Permission.storage.request();
if (status.isGranted) {
final fileType = widget.billet.uRL.split(".").last;
final rng = Random();
final externalDir = Platform.isIOS
? Platform.isIOS
? await getApplicationDocumentsDirectory()
: await getExternalStorageDirectory()
: await getExternalStorageDirectory();
await FlutterDownloader.enqueue(
url: 'https://${widget.billet.uRL}',
savedDir: externalDir.path,
fileName: '${rng.nextInt(1000).toString()}_boleto_MF7.$fileType',
openFileFromNotification: true,
showNotification: true,
);
} else {
print('No download permission');
}
Example:
File is successfully downloaded: https://company.com/arq/file_123.pdf
File is NOT downloaded successfully: https://company.com/arq/file 123.pdf
When I try to download a file on iOS with the URL with a space, I get the following alert on the console:
"Error retrieving thread information (os/kern) invalid argument"
Is there a way to pass the URL with a space?
It's likely that the URL with spacing wasn't encoded properly which why the download request fails. What you can do here is encode the URL with Uri.encodeFull(url);
Related
I'm trying to create an application using
flutter_inappwebview: ^6.0.0-beta.14
base on the the following steps:
download html zipfile from internet.
extract on local storage (at path getting from getApplicationDocumentsDirectory())
use flutter_inappwebview to run localhost server and try to set the documentRoot to the path of getApplicationDocumentsDirectory()
but it show the blank screen and it seems like it cannot find the html file that was extracted. I've explored the directory and already see the html files and folder on that path.
But if I create an html file inside assets folder and run localhost server and access http://localhost:8080/index.html, it was success. But what I want is download html from internet
final dir = (await getApplicationDocumentsDirectory()).path;
final zippedFile = File('$dir/html.zip');// downloaded from internet
await zippedFile.writeAsBytes(zip.data);
final bytes = await zippedFile.readAsBytes();
final archive = ZipDecoder().decodeBytes(bytes);
for (final file in archive) {
final fileName = '$dir/${file.name}';
if (file.isFile && !fileName.contains("__MACOSX")) {
debugPrint(fileName);
final outFile = File(fileName);
await outFile.create(recursive: true);
await outFile.writeAsBytes(file.content);
}
}
and here is code to run localhost server
final dir = (await getApplicationDocumentsDirectory()).path;
final localhostServer = InAppLocalhostServer(
port: 8080,
documentRoot: $dir
);
if (!localhostServer.isRunning()) {
await localhostServer.start();
debugPrint('LOCALHOSTSERVER STARTED');
}
I'm trying to download *.xlsx file using dio.download, and it's throwing the errors:
Unhandled Exception: FileSystemException: Cannot open file, path = '/storage/emulated/0/Android/data/com.example.foodagator_app/files/file.xlsx' (OS Error: No such file or directory, errno = 2)
Another one error from try/catch block:
FileSystemException: Creation failed, path = 'File: '' (OS Error: Read-only file system, errno = 30)
I wrote the permission in androidmanifest for external storage, and also tried temporary directory, but it's not working. Can anyone help me with this? Here is my code
void download() async {
var tempDir = await getExternalStorageDirectory();
File file = File(tempDir!.path + '/file.xlsx');
try {
Response response = await dio.download(
url,
file,
options: Options(
responseType: ResponseType.bytes,
followRedirects: false,
),
);
var raf = file.openSync(mode: FileMode.write);
// response.data is List<int> type
raf.writeFromSync(response.data);
await raf.close();
} catch (e) {
print('Error is: $e');
}
}
void readFile() async {
var tempDir = await getExternalStorageDirectory();
var filePath = tempDir!.path + "/file.xlsx";
var bytes = File(filePath).readAsBytesSync();
var decoder = SpreadsheetDecoder.decodeBytes(bytes, update: true);
for (var table in decoder.tables.keys) {
print(table);
print(decoder.tables[table]!.maxCols);
print(decoder.tables[table]!.maxRows);
for (var row in decoder.tables[table]!.rows) {
print('$row');
}
}
}
This error is getting because there is no file named file.xlsx you can check if file exists or not
if(file.existsSync())
if file does not exist, you can create one using,
new File('$path/file.xlsx').create(recursive: true);
in android 11 and higher use below permission, without tools:ignore="ScopedStorage"
<uses-permission
android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
In my case, it was caused because I had moved a dart file to another folder but my other files were still referencing that file using the old path, you can import the file again using the new path and using the "package:" keyword to solve this error.
Moral: Don't use relative paths to import a file anywhere in your project, always use the "package:" scheme.
You could make a custom name as well.
String createDownloadDocName(){
return'${fileName}-${DateTime.now().microsecond}';
}
Sorry, I had problem with await usage - I tried to get access to file before I downloaded it
I am trying to download a .pdf file from an URL having a POST request with body in Flutter.
I am using Dio plugin for network calls.
Here is what I tried to do so far:
Dio dio = Dio();
late Response response;
Future<APIResponse> downloadFile({token}) async {
await dio
.post('https://www.example.com/sample/download',
data: {
{"month": "January", "year": "2022"}
},
options: Options(
headers: {
'Authorization': 'Bearer $token',
},
))
.then((value) {
if (value.statusCode == 200) {
response = value;
// here I need the file to be downloaded
// specific folder would be /downloads folder in Internal Storage
}
});
return APIResponse.fromJson(response.data);
}
But Dio doesn't have POST method with download option, as far as I have checked.
This is what is given in Dio docs:
For downloading a file:
response = await dio.download('https://www.google.com/', './xx.html');
But here we cannot add request body or headers.
Also I need to download the file to a specific folder in the device such as /downloads folder in internal storage.
When download is successful, we can open the file right from that screen.
How to proceed? I am very new to Flutter.
You can use options parameter. You also can add cookie or other parameters.
response = await dio.download(
'https://www.google.com/', './xx.html',
options: Options(
headers: {'cookie': 'any_cookie'},
method: 'POST',
),
);
When I upload .zip file or .docx ,it deos not work ,but when I choose .c files they work fine
[ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: FileSystemException: Failed to decode data using encoding 'utf-8', path = '/storage/emulated/0/New Text Document.zip'
File _file;
Future upload() async {
if (_file == null) { return; }
String path = _file.path.split("/").last;
var pdf = _file.readAsStringSync();
var url ="http://192.168.1.112/flutter/upload_file.php";
var data = { "path": path, "pdf": pdf };
var response = await http.post(url, body: data);
}
Future pickFile() async {
final myfile = await FilePicker.getFile();
setState(() {
_file = File(myfile.path);
});
}
Here is my php file I tried to use readAsBytesSync and it gave me error
<?php
include 'connection.php';
include 'register.php';
$pdf = $_POST['pdf'];
$file_name = $_POST['path'];
file_put_contents("uploads\\".$file_name, $pdf);
?>
_file.readAsStringSync()
This assumes that your file is plain text. A *.c file most likely is. Neither zip, nor doc nor pdf files are.
What you need to do is read your file as bytes:
var contents = _file.reasAsBytesSync();
Now, I don't know what your API expects to get, so I cannot really help you with how to get the bytes transferred. But this is the way to go.
I have tried uploading image using formData which Dio plugin supports.
FormData formData = new FormData.from(
{"profile_image": UploadFileInfo(image, "profile_image.jpg")});
var response = await _dio.post(ApiConfiguration.getUploadImageUrl().toString(),data: formData);
But its returning error.
DioError [DioErrorType.DEFAULT]: SocketException: OS Error: Connection reset by peer, errno = 54, address = 3.122.199.93, port = 62181
Any help would be appreciated.
UploadFileInfo and FormData.from deprecated in v3. Documentation needs to be clearer and updated. I wasted a good part of a day with this.
I used dio for post a file path with some other information in this way :
Dio dio = new Dio();
FormData formData = new FormData();
formData.add(
"apiKey",
"my_api_key",
);
formData.add(
"file",
"image_path",
);
Response response = await dio.post(
"https://localhost",
data: formData,
onSendProgress: (int sent, int total) {
// do something
},
).catchError((onError) {
throw Exception('something');
});
Faced something similar in Release version of the app, Dio was failing to upload images. This could be due to two reasons, one is mentioned above that you are using a deprecated methods in v3 or You can try adding this permission to the Manifest
Add this permission
<uses-permission android:name="android.permission.INTERNET" />
to your app level Manifest.
android/app/src/main/AndroidManifest.xml
Solution can be found here
https://stackoverflow.com/a/59392036/14641365
Although the other work around to upload an image to the server that I used is something as follows
String url = "YOUR_URL_TO_UPLOAD";
FormData formData = FormData.fromMap({
"QUERY_PARAM_NAME": await MultipartFile.fromFile("IMAGE_PATH", filename:"TESTING.jpg"),
});
var response = await dio.post(url, data: formData);