Flutter cannot get download url firebase-storage - flutter

While trying to upload byteArray to the bucket in firebase storage, the file uploads to the storage but I cannot get the downloadUrl back from the file. I am getting the reference of bucket like this:
Future<Reference> get storageRef async {
final _bucketUrl = await bucketUrl;
return FirebaseStorage.instanceFor(bucket: _bucketUrl).ref();
}
And Uploading image like this:
Future<String> uploadImageByteArray({
#required Uint8List byteArray,
String fileName,
}) async {
final name = fileName ?? DateTime.now().toIso8601String();
final _ref = await storageRef;
final _refUrl = _ref.child("images/$name.png");
print(_refUrl.fullPath);
final uploadTask = _refUrl.putData(byteArray);
final snapshot = await uploadTask;
return snapshot.ref.getDownloadURL();
}
From above code I am getting this error:
Unhandled Exception: type 'NoSuchMethodError' is not a subtype of type 'Exception'.
It works if I get reference for the FirebaseStorage only and not the bucket like this:
Future<Reference> get storageRef{
return FirebaseStorage.instance.ref();
}
I cannot implement without using bucket reference because there can be different bucket urls depending on the tenants. What am I doing wrong?
Edit => Recent Developments:
I found out that it works if I get the downloadurl from the _refUrl itself. i.e:
String downloadUrl = _refUrl.getDownloadUrl();
It works but I can't help but wonder if it is correct implementation.

Your edit makes perfect sense since you have the reference to the uploaded file with _refUrl, fetching its long-lived download URL works as expected (That's how I have done it before btw). I don't have access to a project with FirebaseStorage to test this, but You can try printing snapshot.ref.fullPath and compare it with the fullPath of _refUrl.

try this
Future<String> uploadImageByteArray({
#required Uint8List byteArray,
String fileName,
}) async {
final name = fileName ?? DateTime.now().toIso8601String();
final _ref = await storageRef;
final _refUrl = _ref.child("images/$name.png");
print(_refUrl.fullPath);
final uploadTask = _refUrl.putData(byteArray);
final snapshot = (await uploadTask);
String url = await snapshot.ref.getDownloadURL(); // await
return url;
}

Related

Flutter Solve: 'Offset is outside the bounds of the DataView' error only on Firebase Hosting

Code saving file:
on<GeneratePDFFromInvoice>((event, emit) async {
final aspHeaderLogo =
await rootBundle.loadString('assets/images/asp_logo.svg');
final aspFooterSlogan =
await rootBundle.loadString('assets/images/asp_slogan.svg');
final fontBold = Font.ttf(
await rootBundle.load('fonts/Mulish/static/Mulish-Regular.ttf'));
final regFont = Font.ttf(
await rootBundle.load('fonts/Mulish/static/Mulish-Bold.ttf'));
final pw.Document pdf =
pw.Document(theme: PDFTheme(fontBold, regFont).themeData());
PDF(
pdf: pdf,
invoice: event.invoice,
aspHeaderLogo: aspHeaderLogo,
aspFooterSlogan: aspFooterSlogan)
.createPDF();
String fileName =
'${event.invoice.projectNumber}-${event.invoice.invoiceNumber} Invoice.pdf';
final Uint8List fileData = await pdf.save();
const String mimeType = 'application/pdf';
final XFile pdfFile =
XFile.fromData(fileData, mimeType: mimeType, name: fileName);
await pdfFile.saveTo(fileName);
});
Error from browser console is:
Uncaught RangeError: Offset is outside the bounds of the DataView
at DataView.getUint32 (<anonymous>)
at atE.a5A (main.dart.js:92807:5)
at Object.aJI (main.dart.js:25128:3)
at HD.U4 (main.dart.js:94596:28)
at HD.py (main.dart.js:94570:37)
at anw.$3 (main.dart.js:95329:97)
at q_.atL (main.dart.js:95196:7)
at Wp.agb (main.dart.js:95253:8)
at Wp.cm (main.dart.js:95279:22)
at Oj.cm (main.dart.js:94447:16)
The error occurs regardless of which browser I am on, but only happens when I deploy Firebase. There is no error on localhosting. The error doesn't seem to happen when I don't load a font into the PDF. Also using pdf_package link below.
https://pub.dev/packages/pdf
await rootBundle.load('assets/fonts/Mulish/static/Mulish-Bold.ttf'));
Simple type was the issue. missing 'assets' directory reference. Thanks to #Greg Fenton

Is there a way to download folder from firebase storage with flutter?

I want to download .epub files from firebase storage. I can download image file cause I know imageUrl but not .epub file url. How should I do? I store fileName, imageUrl in Firestore but I don't know epub file's url . So I can't store it.
downloadFile(fileName,imageUrl) async{
Dio dio=Dio();
final storageRef=FirebaseStorage.instance.ref();
final imageUrls =await storageRef.child("Featured").child('a clock orange/Anthony-Burgess-A-Clockwork-Orange-W.-W.-Norton-_-Company-_1986_.epub').getDownloadURL();
String savePath= await getPath(fileName);
dio.download(imageUrls, savePath,
onReceiveProgress: (rcv,total){
setState((){
progress=((rcv/total) *100).toStringAsFixed(0);
});
if (progress == '100') {
setState(() {
isDownloaded = true;
});
}
}).then((_){
if (progress=="100"){
setState(() {
isDownloaded=true;
});
}
});}
I tried this. But it didn't work.
.
Use Firebase's writeToFile instead of dio's download.
final fileRef = storageRef.child("<path here>");
final appDocDir = await getApplicationDocumentsDirectory();
final filePath = "${appDocDir.absolute}/<path here>";
final file = File(filePath);
final downloadTask = fileRef.writeToFile(file);
downloadTask.snapshotEvents.listen((taskSnapshot) {
...
}
See Download to a local file for details.

Unhandled Exception: PlatformException(download_error, Object does not exist at location., null, null), but my Object does exists at the location

I m trying to upload the image on firebase, using this code:
Future<String> uploadCourseImage(filePath, courseName) async{
File file = File(filePath);
var timestamp = Timestamp.now().millisecondsSinceEpoch;
FirebaseStorage _storage = FirebaseStorage.instance;
try{
await _storage.ref().child('courseImage/${this.TeacherName}/$courseName$timestamp').putFile(file);
}on Exception catch(e){
print(e.hashCode);
}
String downloadURL = await _storage.ref().child('courseImage/${this.TeacherName}/$courseName$timestamp').getDownloadURL();
this.courseURL =downloadURL;
notifyListeners();
return downloadURL;
}
But I get this error:
Unhandled Exception: PlatformException(download_error, Object does not exist at location., null, null), but my Object does exists at the location
Using UploadTask class object helps in uploading the file I think.
Try this method for uploading image to Firebase Storage and extracting url after uploading is done.
Future uploadImage(BuildContext context) async {
FirebaseStorage storage = FirebaseStorage.instance;
String? email = FirebaseAuth.instance.currentUser!.email!;
Reference ref =
storage.ref().child('users/${email + DateTime.now().toString()}/Profile Image: ${DateTime.now().toString()}');
UploadTask uploadTask = ref.putFile(_image!);
final TaskSnapshot downloadUrl = (await uploadTask);
imageUrl = await downloadUrl.ref.getDownloadURL();
}
The below code worked fro me:
//Create a reference to the location you want to upload to in firebase
StorageReference reference =
storage.ref().child('courseImage/${this.TeacherName}/$courseName$timestamp');
//Upload the file to firebase
StorageUploadTask uploadTask = reference.putFile(image);
StorageTaskSnapshot taskSnapshot = await uploadTask.onComplete;
// Waits till the file is uploaded then stores the download url
String url = await taskSnapshot.ref.getDownloadURL();

how can i store multiple data in sharedpreferences?

I am getting user information like the username , profile pic and name .I want to store all that info inside Sharedpreferences so that i wont have to call firebase every time I need them.
here is how i am getting the data ,how can i store this data so that later on i can get user's name and its profilepic by checking it through its username ?
storeUsersInfo()async{
print('STORE CALLED');
QuerySnapshot querySnapshot = await DatabaseMethods().getUsers();
var length = querySnapshot.docs.length ;
print(length);
int i = 0 ;
while ( i < length ) {
print(name = "${querySnapshot.docs[i]["name"]}");
print(profilePicUrl = "${querySnapshot.docs[i]["profileURL"]}");
i++;
}
}
here is the firebase call
Future<QuerySnapshot> getUsers() async {
return await FirebaseFirestore.instance
.collection("users")
.get();
}
and if anyone needs anything else please ask .
You can store all the information in SharePreference by encoding picture objects to Base64String before storing them.
How you can encode it:
Future<String> encodeImageToBase64String(String imageUrl) async {
final response = await client.get(Uri.parse(imageUrl));
final base64 = base64Encode(response.bodyBytes);
return base64;
}
After Encoding the image, you can cache it to sharedPreference using
SharedPreferences pref = await SharedPreferences.getInstance();
//Save string to SharedPreference
pref.setString('image', encodedImageString);
How to Decode and use Image Later
//Get Encoded Image String from SharedPreferences
final base64String = pref.getString('image');
///Decodes Images file encoded to Base64String to Image
Uint8List decodeImageFromBase64String(String base64String) {
return base64Decode(base64String);
}
Finally, you can use this in your Image Widget like so
...
Image(image: MemoryImage(decodeImageFromBase64String))
Assuming you want to cache name, username and image gotten from firebase
//Create a model for the firebase data
class UserModel{
final String name;
final String username;
final String encodedImage;
UserModel(this.name, this.username, this.encodedImage);
String toJson(){
Map<String, dynamic> userMap = {
'name': name,
'username': username,
'image': encodedImage,
};
return json.encode(userMap);
}
}
//Encode the image HERE
encodeImageToBase64String(imageUrl);
//Pass in the parameters to the UserModel() constructor and Call //the toJson(), then Cache the Resulting String
String stringToCache = UserModel(nameString, usernameString, encodedImageString).toJson();
SharedPreferences takes a key and the data.
use this in an async funtion.
This syntax is sharedPreferences.setString(key, value)
So in a function,
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
sharedPreferences.setString("token", jsonResponse['access_token'].toString());
sharedPreferences.setString("userId", jsonResponse['customer_id'].toString());
You can get the stored data by sharedPreferences.getString(key).Like
var token = sharedPreferences.getString("token");
You can use a cache like https://pub.dev/packages/firestore_cache which does that for you.

getDownloadURL returns null when uploadTask is complete but uploads image to storage

The image I am trying to upload to storage is successful, however when I want to use that image that was uploaded to store the URL into the database, it returns null for some reason.
Future<String> _uploadPic(String docRef, File file) {
FirebaseStorage _storage = FirebaseStorage.instance;
auth.currentUser().then((userID) async{
StorageReference reference = _storage.ref().child(userID).child(docRef);
StorageUploadTask uploadTask = reference.putFile(file);
String downloadURL = (await uploadTask.onComplete).ref.getDownloadURL().toString();
return downloadURL;
});
}
Log:
I/flutter (17507): debug: the uri is: null
Future<dynamic> _uploadPic(String docRef, File file) {
FirebaseStorage _storage = FirebaseStorage.instance;
// you need to return the result...
return auth.currentUser().then((userID) async {
StorageReference reference = _storage.ref().child(userID).child(docRef);
StorageUploadTask uploadTask = reference.putFile(file);
return (await uploadTask.onComplete).ref.getDownloadURL();
});
}
The getDownloadURL() method returns a Future. So if you call toString() on that, you get the string representation of the future, and not a download URL. Instead you'll want to wait for the getDownloadURL() future to also complete, and that will give you the URL.
String downloadURL = (await (await uploadTask.onComplete).ref.getDownloadURL()).toString();