How to pass header to URL in Flutter - flutter

I have a question regarding how to view a PDF from URL.
I’m using flutter_pdfview library and I try to get a PDF from an URL and to view it in my Flutter app.
The problem is that my URL can be accessed ONLY with a token (session ID/header), but I don’t know how to pass it because is not working on the way I do it at the moment.
Here is an example of how the owner of the flutter_pdfview library is getting the PDF from an URL (without a Header): https://github.com/endigo/flutter_pdfview/blob/master/example/lib/main.dart#L49
And here is my code where I don’t know how else to pass the header than like this:
Future<File> createFileOfPdfUrl() async {
Completer<File> completer = Completer();
if (kDebugMode) {
print("Start download file from internet!");
}
try {
String url =
"$customURL.pdf";
if (kDebugMode) {
print("url: $url");
}
final filename = url.substring(url.lastIndexOf("/") + 1);
var client = HttpClient();
HttpClientRequest request = await client.getUrl(Uri.parse(url));
request.headers.add(
HttpHeaders.acceptHeader,
HeaderValue(
"text/plain", {'APPAUTH': '${widget.authService.loginToken}'})); // this method doesn't seems to work for me. I'm getting an empty PDF.
var response = await request.close();
var bytes = await consolidateHttpClientResponseBytes(response);
var dir = await getApplicationDocumentsDirectory();
if (kDebugMode) {
print("Download files");
print("${dir.path}/$filename");
}
File file = File("${dir.path}/$filename");
await file.writeAsBytes(bytes, flush: true);
completer.complete(file);
} catch (e) {
throw Exception('Error parsing asset file!');
}
return completer.future;
}

DO NOT do this:
request.headers.add(
HttpHeaders.acceptHeader, // here is the problem
HeaderValue(
"text/plain", {'APPAUTH': '${widget.authService.loginToken}'}));
SOLUTION for me:
request.headers.add("APPAUTH", "12345abcde67890defgh");
For some reason if you provide a HeaderValue you also need to provide a string value before it, which can be HttpHeaders.acceptHeader or HttpHeaders.serverHeader etc. I tried a lot of them from that enum list and none worked for me so I used the above solution where you don't need to pass that HttpHeader value type.

Related

Flutter await does not await until return of function

I tried to find an answer but my problem is still there.
In my asynchronous upload function I return at the and the generated name of the image, which I want to use to make my database request.
This is my upload function:
Future<String> upload(File imageFile) async {
var stream =
new http.ByteStream(DelegatingStream.typed(imageFile.openRead()));
// get file length
var length = await imageFile.length();
var uri = Uri.parse("http://localhost:8080/upload");
var request = new http.MultipartRequest("POST", uri);
var multipartFile = new http.MultipartFile('file', stream, length,
filename: basename(imageFile.path));
request.files.add(multipartFile);
var response = await request.send();
print(response.statusCode);
var createdFileName = "";
response.stream.transform(utf8.decoder).listen((value) {
createdFileName = value;
print(createdFileName);
});
return createdFileName;
}
I call it like this:
List createdFileNames = [];
for (var e in imagefiles) {
createdFileNames.add(await upload(File(e)));
}
I don't know why, but the createdFileNames are ["",""], but the upload gives as result the right name. In debug mode I can see, that the loop does not wait until the upload has finished.
Do you have any suggestions?
Thank you very much!
response.stream.transform(utf8.decoder).listen((value) {
createdFileName = value;
print(createdFileName);
});
This part in your function is asynchronous, it uses a callback.
But you don't wait for it to finish in any form. You just continue to return the createdFileName, that by that time most likely has not been filled.
I don't know what your stream looks like, if you only need the first value, you could await that instead of listening:
createdFileName = await response.stream.transform(utf8.decoder).first;
Replace
response.stream.transform(utf8.decoder).listen((value) {
createdFileName = value;
print(createdFileName);
});
with
createdFileName=await response.stream.bytesToString();
change code
for (var e in imagefiles) {
upload(File(e)).then((value) => createdFileNames.add(value));
}

How to save pdf file in flutter?

I have a pdf file. I want to write that file in phone memory? Below is the code.
First I am scanning then I am converting the image to pdf, Now I want to save that pdf to phone memory. Please help me.
void onDocumentScanner(BuildContext context) async {
try {
File scannedDocumentFile;
var doc = await DocumentScannerFlutter.launchForPdf(context);
if (doc != null) {
refreshDownloadedFiles();
scannedDocumentFile = doc;
String fileName = basename(scannedDocumentFile.path);
final directory = (await getExternalStorageDirectory())!.path;
File saveFilePath = File('$directory/$fileName');
saveFilePath.openWrite(); //Here I want to save to the file
print("Path = $fileName");
Get.toNamed(AppRoutes.viewDownloadedFile,
arguments: [scannedDocumentFile.path, fileName, folderId])!
.whenComplete(() {
refreshFetchedData();
});
}
} catch (e) {
print(e);
}
}
I haven't seen the .openWrite() method before, but the documentation says that it has 2 named arguments FileMode and encoding - try to specify them.
If it won't work, I can only share my solution, with .writeAsBytes method.
Instead of saveFilePath.openWrite() you can bundle the data first and then save it.
final byteData = await rootBundle.load(fileName);
await saveFilePath.writeAsBytes(byteData.buffer
.asUint8List(byteData.offsetInBytes, byteData.lengthInBytes));

How to use Uri function properly in Flutter? Difference between Uri and Url

I am confused with the URL and Uri in dart/flutter.
I created this function to be used in my PDF viewer.
static Future<File> loadNetwork(String url) async {
final response = await http.get(Uri.parse(url));
final bytes = response.bodyBytes;
return _storeFile(url, bytes);
}
and I want to call this function to display the specific PDF after clicking a button.
onTap: () async {
setState(() {
isLoading = true;
});
final url = 'http://www.africau.edu/images/default/sample.pdf';
final file = await PDFApi.loadNetwork(url);
openPDF(context, file);
setState(() {
isLoading = false;
});
},
But, still, how do I properly use the Uri and fetch the pdf link. There is an error and I suspect I am using the function wrongly.
It says invalid internet address.
Thanks!
To convert a url to Uri use Uri.parse("url here")

Flutter AZURE BLOB IMAGE UPLOAD - How to upload image captured using mobile camera to azure blob storage

I have been working for few since yesterday to try upload an image to azure blob storage taken using mobile camera form iOS/Android device.
I am able to upload the files but for some reason they being corrupted not able to open the image uploaded.
Please check the image error while opening the uploaded image
I am using flutter package http with different approach all work in uploading image file to azure blob store but it gets corrupted somehow , I tried forcing the ContentType to image/jpeg but no help.
Here is code I am using an http API -
takePicture() async {
final pickedFile = await picker.getImage(source: ImageSource.camera);
setState(() {
if (pickedFile != null) {
_image = File(pickedFile.path);
String fileName = basename(pickedFile.path);
uploadFile(fileName, image);
} else {
print('No image selected.');
}
});
}
First approach -->
http.Response response = await http.put(
uri,
headers: {
"Content-Type": 'image/jpeg',
"X-MS-BLOB-TYPE": "BlockBlob",
},
body: image.path,
);
print(response.statusCode);
Using Approach second -->
final data = image.readAsBytesSync();
var dio = Dio();
dio.options.headers['x-ms-blob-type'] = 'BlockBlob';
dio.options.headers['Content-Type'] = 'image/jpeg';
try {
final response = await dio.put(
'$url/$fileName?$token',
data: data,
onSendProgress: (int sent, int total) {
if (total != -1) {
print((sent / total * 100).toStringAsFixed(0) + "%");
}
},
);
print(response.statusCode);
} catch (e) {
print(e);
}
Approach third -->
var request = new http.MultipartRequest("PUT", postUri);
request.headers['X-MS-BLOB-TYPE'] = 'BlockBlob';
request.headers['Content-Type'] = 'image/jpeg';
request.files.add(
new http.MultipartFile.fromBytes(
'picture',
await image.readAsBytes(),
),
);
request.send().then((response) {
uploadResponse.add(response.statusCode);
}, onError: (err) {
print(err);
});
Help here is much appreciated.
If you want to upload the image to Azure Blob Storage in the flutter application, you can use the Dart Package azblob to implement it. Regarding how to use the package, please refer to here.
For example
import 'package:image_picker/image_picker.dart';
import 'package:flutter/material.dart';
import 'package:azblob/azblob.dart';
import 'package:mime/mime.dart';
...
//use image_picker to get image
Future uploadImageToAzure(BuildContext context) async {
try{
String fileName = basename(_imageFile.path);
// read file as Uint8List
Uint8List content = await _imageFile.readAsBytes();
var storage = AzureStorage.parse('<storage account connection string>');
String container="image";
// get the mine type of the file
String contentType= lookupMimeType(fileName);
await storage.putBlob('/$container/$fileName',bodyBytes: content,contentType: contentType,type: BlobType.BlockBlob);
print("done");
} on AzureStorageException catch(ex){
print(ex.message);
}catch(err){
print(err);
}
Unfortunately, the multipart form is causing break of image. I don't know how it works on azure side, because there is little or no information about multipart uploads, but it's clearly broken because of multipart form. I replicated the problem in .net core application and whenever i am using multipart form data to upload image - it is broken. When i am using simple ByteArrayContent - it works. I couldn't find flutter equivalent to ByteArrayContent, so i am lost now :( The package mentioned by #Jim is useless for me, because i want to give clients sas url, so they have permission to upload image on client side. I do not want to store azure storage account secrets in flutter app.
EDIT. I found the solution to send raw byte data with Dio package. You can do that also with http package.
final dio = new Dio();
final fileBytes = file.readAsBytesSync();
var streamData = Stream.fromIterable(fileBytes.map((e) => [e]));
await dio.put(uploadDestinationUrl,
data: streamData,
options: Options(headers: {
Headers.contentLengthHeader: fileBytes.length,
"x-ms-blob-type": "BlockBlob",
"content-type": "image/jpeg"
}));

How to upload .m4a to firebase storage using flutter?

How do I ensure the content type in firebase storage is "audio/m4a"? It is currently being stored as application/json; charset=UTF-8
.
When you use putFile to upload the file, be sure to pass a StorageMetadata object as the second argument. Be sure set the contentType property of that object to whatever you need.
Expanding #Doug Stevenson Answer with code.
StorageUploadTask uploadTask = ref.putFile(
file,
StorageMetadata(
contentType: 'audio/m4a',
customMetadata: <String, String>{'file': 'audio'},
),
);
ref is StorageReference.
this worked for me:
Future<void> uploadGorsel(XFile filePath,String name) async {
try {
String referance =
'${FirebaseAuth.instance.currentUser!.uid}/Record/$name';
final metadata = SettableMetadata(
contentType: 'audio/m4a',
customMetadata: {'picked-file-path': filePath.path});
storage
.ref(referance)
.putData(await filePath.readAsBytes(), metadata)
.then((p0) async {
var url = await p0.ref.getDownloadURL();
print(url);
print(p0.ref);
});
} on FirebaseException catch (e) {
print(e.message);
}
}