I am trying to store images from firebase storage to the phone so that they can be available offline (downloaded). I am aware of this Stack Overflow question Download an image from Firebase to Flutter
-- but that solution seems outdated as the "getData()" method now requires a maxSize-- (I just pick a high number like 9999999).
My current attempt looks like this. My thought process is that by downloading the data, I can then write it to a local file. I am using the path_provider pub.
static Future<List<int>> downloadImage(String title, String route) async{
List<int> data = await FirebaseStorage.instance.ref().child("English/routes/" + route + "/" + title +".jpg").getData(1000000);
var text = new String.fromCharCodes(data);
print("data= "+data.toString());
print("text= " +text);
return data;
}
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> localFile(String fileName) async {
final path = await _localPath;
return new File('$path/'+fileName+'.txt');
}
Future<File> writeImage(List<int> bytes, File file) async {
// Write the file
return file.writeAsBytes(bytes);
}
When I run downloadImage, I get the following errors over and over again, overflowing my console.
I can't tell whether the error is due to authentication, because of the following error message
(E/StorageUtil(15931): error getting token java.util.concurrent.ExecutionException: com.google.firebase.internal.api.FirebaseNoSignedInUserException: Please sign in before trying to get a token.)
Or maybe something to do with the "maxSize", because of this error message
java.lang.IndexOutOfBoundsException: the maximum allowed buffer size was exceeded.
Or maybe both! But my rules are set to true for reading and writing so I don't even see how authentication has anything to do with it. I've not had to sign in before.
E/StorageException(15931): StorageException has occurred.
E/StorageException(15931): An unknown error occurred, please check the HTTP result code and inner exception for server response.
E/StorageException(15931): Code: -13000 HttpResult: 200
E/StorageException(15931): the maximum allowed buffer size was exceeded.
E/StorageException(15931): java.lang.IndexOutOfBoundsException: the maximum allowed buffer size was exceeded.
E/StorageException(15931): at com.google.firebase.storage.zzi.doInBackground(Unknown Source)
E/StorageException(15931): at com.google.firebase.storage.StreamDownloadTask.run(Unknown Source)
E/StorageException(15931): at com.google.firebase.storage.StorageTask.zzl(Unknown Source)
E/StorageException(15931): at com.google.firebase.storage.zzq.run(Unknown Source)
E/StorageException(15931): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
E/StorageException(15931): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
E/StorageException(15931): at java.lang.Thread.run(Thread.java:762)
E/StorageUtil(15931): error getting token java.util.concurrent.ExecutionException: com.google.firebase.internal.api.FirebaseNoSignedInUserException: Please sign in before trying to get a token.
E/flutter (15931): [ERROR:topaz/lib/tonic/logging/dart_error.cc(16)] Unhandled exception:
E/flutter (15931): PlatformException(download_error, An unknown error occurred, please check the HTTP result code and inner exception for server response., null)
E/flutter (15931): #0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:547:7)
E/flutter (15931): #1 MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:279:18)
E/flutter (15931): <asynchronous suspension>
E/flutter (15931): #2 StorageReference.getData (package:firebase_storage/firebase_storage.dart:207:42)
E/flutter (15931): <asynchronous suspension>
E/flutter (15931): #3 Utils.downloadImage (package:flutter_alight/utils/utils.dart:88:108)
E/flutter (15931): <asynchronous suspension>
E/flutter (15931): #4 BusRouteItemState.downloadPois.<anonymous closure> (package:flutter_alight/UI/busRouteCards.dart:56:23)
E/flutter (15931): #5 _RootZone.runUnaryGuarded (dart:async/zone.dart:1316:10)
E/flutter (15931): #6 _BufferingStreamSubscription._sendData (dart:async/stream_impl.dart:330:11)
E/flutter (15931): #7 _DelayedData.perform (dart:async/stream_impl.dart:578:14)
E/flutter (15931): #8 _StreamImplEvents.handleNext (dart:async/stream_impl.dart:694:11)
E/flutter (15931): #9 _PendingEvents.schedule.<anonymous closure> (dart:async/stream_impl.dart:654:7)
E/flutter (15931): #10 _microtaskLoop (dart:async/schedule_microtask.dart:41:21)
E/flutter (15931): #11 _startMicrotaskLoop (dart:async/schedule_microtask.dart:50:5)
W/NetworkRequest(15931): no auth token for request
I/System.out(15931): (HTTPLog)-Static: isSBSettingEnabled false
I/System.out(15931): (HTTPLog)-Static: isSBSettingEnabled false
E/StorageReference(15931): the maximum allowed buffer size was exceeded.
W/StreamDownloadTask(15931): Exception occurred calling doInBackground.
W/StreamDownloadTask(15931): java.lang.IndexOutOfBoundsException: the maximum allowed buffer size was exceeded.
Maybe the high number you picked isn't high enough for what you want to download.
1mb is 1024*1024 = 1048576, which is higher than what you set as max limit.
And your data could be larger than 1mb.
Check your data and set the max limit accordingly.
Related
I'm getting this null error when calling the firebase firestore database. It's working fine with my other data. Only getting error with this nested List of 'orientation'. Please help with this.
E/flutter (21191): [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: NoSuchMethodError: The method '[]' was called on null.
E/flutter (21191): Receiver: null
E/flutter (21191): Tried calling: []("orientation")
E/flutter (21191): #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:38:5)
E/flutter (21191): #1 new User.fromDocument (package:meetapp/models/user_model.dart:59:41)
E/flutter (21191): #2 TabbarState.getUserList.<anonymous closure>.<anonymous closure> (package:meetapp/Screens/Tab.dart:407:40)
E/flutter (21191): #3 TabbarState.getUserList.<anonymous closure>.<anonymous closure> (package:meetapp/Screens/Tab.dart:399:26)
E/flutter (21191): #4 _rootRunUnary (dart:async/zone.dart:1434:47)
E/flutter (21191): #5 _CustomZone.runUnary (dart:async/zone.dart:1335:19)
E/flutter (21191): <asynchronous suspension>
E/flutter (21191):
As you see, your doc.data() is not null, but you should also null-check ['sexualOrientation'] property. In your case, it's null, and you should write catch method for this case, because now you trying to call another property without asserting it. Let me explain.
Here is your data:
doc.data()! | is not null
↓
['sexualOrientation'] | is null so next value cant be accessed
↓
['orientation'] | cant be accessed because previous is null
What can you do:
Add assertation for second, potentionally nullable field. You can use ! or ? to check if it's null, like doc.data()!['sexualOrientation']!['orientation'] ?? []
Im using Firestore for mu Flutter project.
I cannot update a field in a document. It results in error (error performing update, No document found)
Code:
await Firestore.instance.collection('QuizProfile').document("20200528-KYUMI").updateData(
{
'Slot': 'asdfg',
},
);
}
Error message ::
E/flutter (18326): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception:
PlatformException(Error performing updateData, NOT_FOUND:
No document to update: projects/fir-2d2f0/databases/(default)/documents/QuizProfile/20200528-KYUMI, null)
E/flutter (18326): #0 StandardMethodCodec.decodeEnvelope
package:flutter/…/services/message_codecs.dart:569
E/flutter (18326): #1 MethodChannel.invokeMethod
package:flutter/…/services/platform_channel.dart:321
E/flutter (18326): <asynchronous suspension>
E/flutter (18326): #2 MethodChannelDocumentReference.updateData
package:cloud_firestore_platform_interface/…/method_channel/method_channel_document_reference.dart:41
E/flutter (18326): #3 DocumentReference.updateData
package:cloud_firestore/src/document_reference.dart:60
E/flutter (18326): #4 Model.pushscore
package:firestoredemo/models/QA_Model.dart:214
E/flutter (18326): <asynchronous suspension>
E/flutter (18326): #5 _CustomTextState.initState
package:firestoredemo/CustomText.dart:21
Firestore database screenshot
I am getting this exception while creating a document in Firestore transaction using Flutter cloud_firestore package:
PlatformException(Error performing transaction, Every document read in a transaction must also be written., null)
This is the code:
DocumentSnapshot postSnapshot = await tx.get(post.reference);
await tx.set(Firestore.instance.collection('users').document(userId).collection('stars').
document(),docNew);
await tx.update(postSnapshot.reference, stockUpdate);
Below is the exception details:
E/flutter ( 7157): [ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: PlatformException(Error performing transaction, Every document read in a transaction must also be written., null)
E/flutter ( 7157): #0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:569:7)
E/flutter ( 7157): #1 MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:321:33)
E/flutter ( 7157): <asynchronous suspension>
E/flutter ( 7157): #2 MethodChannel.invokeMapMethod (package:flutter/src/services/platform_channel.dart:349:48)
E/flutter ( 7157): #3 MethodChannelFirestore.runTransaction (package:cloud_firestore_platform_interface/src/method_channel/method_channel_firestore.dart:123:10)
E/flutter ( 7157): #4 Firestore.runTransaction (package:cloud_firestore/src/firestore.dart:85:22)
As you see in the code, I try to create doc in one collection and update a field in another document.
Any hints to debug this? Thank you.
I'm writing my first app in Flutter and got stuck with the Firestore security rules. I can allow write & read and everything works fine, but if I want to limit adding of objects to users who have an account, things break.
More specifcally I have the following rules:
match /ratings/{anyRatingFile=**} {
allow create: if request.auth.uid == get(/databases/$(database)/documents/$(request.resource.data.user)).id;
}
Basically, if the user ID from the request exists, then I will accept the creating request. I can use the online simulator and it works! If the UID is not registered I get rejected and otherwise the request is accepted. But when I try to create an object in my flutter App, it always crashes with the following stack trace:
W/Firestore(30727): (19.0.0) [Firestore]: Write failed at ratings/48MZwRY66G13g8T0Nl8j: Status{code=PERMISSION_DENIED, description=Missing or insufficient permissions., cause=null}
E/flutter (30727): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: PlatformException(Error performing setData, PERMISSION_DENIED: Missing or insufficient permissions., null)
E/flutter (30727): #0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:564:7)
E/flutter (30727): #1 MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:316:33)
E/flutter (30727): <asynchronous suspension>
E/flutter (30727): #2 DocumentReference.setData (package:cloud_firestore/src/document_reference.dart:51:30)
E/flutter (30727): #3 CollectionReference.add (package:cloud_firestore/src/collection_reference.dart:58:23)
E/flutter (30727): <asynchronous suspension>
E/flutter (30727): #4 MyApp.submitRating (package:MyApp/screens/myscreen.dart:128:16)
E/flutter (30727): #5 MyApp._buildMain.<anonymous closure> (package:MyApp/screens/myscreen.dart:93:24)
E/flutter (30727): #6 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:635:14)
E/flutter (30727): #7 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:711:32)
E/flutter (30727): #8 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:182:24)
E/flutter (30727): #9 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:365:11)
E/flutter (30727): #10 TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:275:7)
E/flutter (30727): #11 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:455:9)
E/flutter (30727): #12 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:75:13)
E/flutter (30727): #13 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:102:11)
E/flutter (30727): #14 _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:218:19)
E/flutter (30727): #15 _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:198:22)
E/flutter (30727): #16 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:156:7)
E/flutter (30727): #17 _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:102:7)
E/flutter (30727): #18 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:86:7)
E/flutter (30727): #19 _rootRunUnary (dart:async/zone.dart:1136:13)
E/flutter (30727): #20 _CustomZone.runUnary (dart:async/zone.dart:1029:19)
E/flutter (30727): #21 _CustomZone.runUnaryGuarded (dart:async/zone.dart:931:7)
E/flutter (30727): #22 _invoke1 (dart:ui/hooks.dart:250:10)
E/flutter (30727): #23 _dispatchPointerDataPacket (dart:ui/hooks.dart:159:5)
and per request, here is the code:
var collection = Firestore.instance.collection('ratings');
collection.add({
"puzzle": "/sample/" + ID,
"user": "/users/" + appState.user.uid,
"rating": rating,
});
And a bit more debug info. This request on the firestore website works, e.g. return "Simulated write allowed".
{"__name__":"/databases/(default)/documents/ratings/test","id":"test","data":{"user":"/users/PCAE2"}}
Authentication Payload:
{
"uid": "PCAE2",
"token": {
"sub": "PCAE2",
"aud": "myApp-1",
"email": "",
"email_verified": false,
"phone_number": "",
"name": "",
"firebase": {
"sign_in_provider": "google.com"
}
}
}
I cut out most of the user ID for anonymity, but otherwise it is a copy-paste. And in my local log I see the following message:
W/BiChannelGoogleApi(30727): [FirebaseAuth: ] getGoogleApiForMethod() returned Gms: com.google.firebase.auth.api.internal.zzaq#9304ffb
D/FirebaseAuth(30727): Notifying id token listeners about user ( PCAE2 ).
I/flutter (30727): Logged in
So two questions:
1) What is the issue here?
2) How do I debug this sort of errors? I tried to find some Firestore log files, but couldn't find any. I can see that I can write unit tests, but the test on the website doesn't help because it passes.
Thank you for your help!
I solved my particular problem, but I still don't know how to debug this in general. So if you know, please let me know.
The issue here was another rule:
match /users/{userId}/{anyUserFile=**} {
allow read, write, delete: if request.auth.uid == userId
}
My mistake, that I did not include that in the question, but I assumed it would not have been a problem because the simulation works. Anyway, removing this line and allowing read & write for everybody in the world to the /users/ table fixes the problem.
This opens up a list of new questions though:
Why did the simulation work, but not my flutter App request?
How can I protect the /users/ table?
How do I debug things like this in the future, if the simulator differs from the app behavior?
Thanks!
Firebase security rules cannot be debugged. But, surely you can validate the rules via a simulator
Example
I'm trying to access to a Cloud Firestore with this piece of code :
void _submit(BuildContext context) async {
final DocumentReference postRef = Firestore.instance.document(dbPath);
Firestore.instance.runTransaction((transaction) async {
DocumentSnapshot freshSnap = await transaction.get(postRef);
await transaction.update(freshSnap.reference, {
'value': freshSnap['value'] + 1
});
});
}
If wifi or mobile data are on, everything works fine. (as expected)
If wifi and mobile data are off, it does not work. (as expected). But when I wait until the timeout (after calling the method) and only then, turn mobile data and wifi on, it does not work anymore and I get the following errors :
E/flutter ( 7041): [ERROR:topaz/lib/tonic/logging/dart_error.cc(16)] Unhandled exception:
E/flutter ( 7041): PlatformException(Error performing transaction, Timed out waiting for Task, null)
E/flutter ( 7041): #0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:547:7)
E/flutter ( 7041): #1 MethodChannel.invokeMethod (package:flutter/src/services/platform_channel.dart:279:18)
E/flutter ( 7041): <asynchronous suspension>
E/flutter ( 7041): #2 Firestore.runTransaction (file:///C:/{myPath}/flutter/.pub-cache/hosted/pub.dartlang.org/cloud_firestore-0.7.3/lib/src/firestore.dart:115:10)
E/flutter ( 7041): <asynchronous suspension>
E/flutter ( 7041): #3 _FeedbackPageState._submitFeedback (package:appli_salon_data/view/program/FeedbackPage.dart:74:26)
E/flutter ( 7041): <asynchronous suspension>
E/flutter ( 7041): #4 _FeedbackPageState.build.<anonymous closure> (package:appli_salon_data/view/program/FeedbackPage.dart:60:26)
E/flutter ( 7041): #5 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:494:14)
E/flutter ( 7041): #6 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:549:30)
E/flutter ( 7041): #7 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:102:24)
E/flutter ( 7041): #8 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:161:9)
E/flutter ( 7041): #9 TapGestureRecognizer.acceptGesture (package:flutter/src/gestures/tap.dart:123:7)
E/flutter ( 7041): #10 GestureArenaManager.sweep (package:flutter/src/gestures/arena.dart:156:27)
E/flutter ( 7041): #11 _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:147:20)
E/flutter ( 7041): #12 _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:121:22)
E/flutter ( 7041): #13 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:101:7)
E/flutter ( 7041): #14 _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:64:7)
E/flutter ( 7041): #15 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:48:7)
E/flutter ( 7041): #16 _invoke1 (dart:ui/hooks.dart:134:13)
E/flutter ( 7041): #17 _dispatchPointerDataPacket (dart:ui/hooks.dart:91:5)
(not expected)
The method won't work again until I relaunch the app.
If anyone has some explanation about this behaviour, feel free to answer :)
UPDATE : I tried this :
Switch off Wifi
Try to run the transaction - results in expected failure
Switch on Wifi
Try to run the transaction
Here is the interesting part : at step 4, the transaction is "immediately" run twice, both times getting the error :
PlatformException(Error performing Transaction#get, UNAVAILABLE: Unable to resolve host firestore.googleapis.com, null)
when calling transaction.get(postRef).
Could it mean that Firestore somehow loses all access to the host after losing Internet connection briefly once ? How can I fix that ?
Have you tried enabling local persistence? Not sure if that'll catch the issue, but it might be worth a try. I believe this is done using the persistenceEnabled parameter in the settings method:
Firestore.instance.settings(persistenceEnabled: true)
Keep in mind that this should only be done once, so it should go somewhere in your code that won't get called every time you access any Firestore data.