How to debug Firestore security rules in Flutter - firebase

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

Related

Flutter Firestore Error performing updateData, No Document found to update

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 unable to Sign in using phone verification on Firebase using Flutter and fuurebase_auth plugin

I keep getting this error below:
The method 'signInWithCredential' was called on null.
[ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: NoSuchMethodError: The method 'signInWithCredential' was called on null.
E/flutter (29053): Receiver: null
E/flutter (29053): Tried calling: signInWithCredential(Instance of 'AuthCredential')
E/flutter (29053): #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:50:5)
E/flutter (29053): #1 _LoginScreenState._signInWithPhoneNumber (package:jollycab_flutter/screens/login_screen.dart:74:43)
E/flutter (29053): <asynchronous suspension>
E/flutter (29053): #2 _LoginScreenState.build.<anonymous closure> (package:jollycab_flutter/screens/login_screen.dart:384:23)
E/flutter (29053): <asynchronous suspension>
E/flutter (29053): #3 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:511:14)
E/flutter (29053): #4 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:566:30)
E/flutter (29053): #5 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:166:24)
E/flutter (29053): #6 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:240:9)
E/flutter (29053): #7 TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:177:9)
I am using the code example from the flutter team here:
https://github.com/flutter/plugins/blob/master/packages/firebase_auth/example/lib/signin_page.dart
The Code starts from line 508. For some reason, signInWithCredential does not seem to be getting what it wants or is not working
if you used the example, then somewhere in the code you have _auth.signInWithCredential and _auth is null, you missing the initialization of it. or you are initializing it with invalid value (null?)

Permission denied when reading from database

I have a problem reading data from a firebase database.
The code below belongs to a function attached to a [FlatButton]:
void newEntry(){
print(_database.reference().child('todo').equalTo('Dan').once().then((value){
print(value.key);
}));
}
Whenever I run this piece of code I get this error:
I/flutter (29847): Instance of 'Future<dynamic>'
D/NetworkSecurityConfig(29847): No Network Security Config specified, using platform default
W/SyncTree(29847): Listen at /todo failed: DatabaseError: Permission denied
E/flutter (29847): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: Instance of 'DatabaseError'
E/flutter (29847): #0 Query.once (package:firebase_database/src/query.dart:90:41)
E/flutter (29847): <asynchronous suspension>
E/flutter (29847): #1 _MyAppState.newEntry (package:database_project/main.dart:94:62)
E/flutter (29847): #2 _MyAppState._buildButton.<anonymous closure> (package:database_project/main.dart:88:9)
E/flutter (29847): #3 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:511:14)
E/flutter (29847): #4 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:566:30)
E/flutter (29847): #5 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:166:24)
E/flutter (29847): #6 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:240:9)
E/flutter (29847): #7 TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:177:9)
E/flutter (29847): #8 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:436:9)
E/flutter (29847): #9 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:73:12)
E/flutter (29847): #10 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:101:11)
E/flutter (29847): #11 _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:221:19)
E/flutter (29847): #12 _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:199:22)chEvent (package:flutter/src/gestures/binding.dart:199:22) ePointerEvent (package:flutter/src/gestures/binding.dart:156:7)
E/flutter (29847): #13 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlPointerEventQueue (package:flutter/src/gestures/binding.dart:102:7)ePointerEvent (package:flutter/src/gestures/binding.dart:156:7) ePointerDataPacket (package:flutter/src/gestures/binding.dart:86:7)
E/flutter (29847): #14 _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:102:7)
E/flutter (29847): #15 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:86:7)
E/flutter (29847): #16 _rootRunUnary (dart:async/zone.dart:1136:13)
E/flutter (29847): #17 _CustomZone.runUnary (dart:async/zone.dart:1029:19)
E/flutter (29847): #18 _CustomZone.runUnaryGuarded (dart:async/zone.dart:931:7) ity]
E/flutter (29847): #19 _invoke1 (dart:ui/hooks.dart:233:10)
E/flutter (29847): #20 _dispatchPointerDataPacket (dart:ui/hooks.dart:154:5) w{8084b2a VFE...... .F...... 0,0-1440,2872} of ViewRootImpl#b8c6359[MainActivity]
E/flutter (29847): t/com.example.database_project.MainActivity#8084b2a#0[29847])/#0xeeafd1b io.flutter.view.FlutterView{8084b2a VFE.D/ViewRootImpl#b8c6359[MainActivity](29847): MSG_WINDOW_FOCUS_CHANGED 0 1
D/InputMethodManager(29847): prepareNavigationBarInfo() DecorView#48d0f7a[MainActivew{8084b2a VFE...... .F...... 0,0-1440,2872}ity]
D/InputMethodManager(29847): getNavigationBarColor() -855310D/SurfaceView(29847): onWindowVisibilityChanged(8) false io.flutter.view.FlutterView{8084b2a VFE...... .F...... 0,0-1440,2872} of ViewRootImpl#b8c6359[MainActivity]D/SurfaceView(29847): show() Surface(name=SurfaceView - com.example.database_project/com.example.database_project.MainActivity#8084b2a#0[29847])/#0xeeafd1b io.flutter.view.FlutterView{8084b2a VFE...... .F...... 0,0-1440,2872}D/SurfaceView(29847): surfaceDestroyed callback.size 1 #2 io.flutter.view.FlutterView{8084b2a VFE...... .F...... 0,0-1440,2872}W/libEGL (29847): EGLNativeWindowType 0x7af3edd010 disconnect failed
D/SurfaceView(29847): destroy() Surface(name=SurfaceView - com.example.database_project/com.example.database_project.MainActivity#8084b2a#0[29847])/#0xeeafd1b io.flutter.view.FlutterView{8084b2a VFE...... .F...... 0,0-1440,2872}W/libEGL (29847): EGLNativeWindowType 0x7b02e2a010 disconnect failedD/OpenGLRenderer(29847): eglDestroySurface = 0x7af3f13680, 0x7b02e2a000D/ViewRootImpl#b8c6359[MainActivity](29847): Relayout returned: old=[0,0][1440,3040] new=[0,0][1440,3040] result=0x5 surface={valid=false 0} changed=trueD/ViewRootImpl#b8c6359[MainActivity](29847): setWindowStopped(true) old=false
D/SurfaceView(29847): windowStopped(true) false io.flutter.view.FlutterView{8084b2a VFE...... .F...... 0,0-1440,2872} of ViewRootImpl#b8c6359[MainActivity]
D/ViewRootImpl#b8c6359[MainActivity](29847): Surface release. android.view.WindowManagerGlobal.setStoppedState:669 android.app.Activity.performStop:7647 android.app.ActivityThread.callActivityOnStop:4372 android.app.ActivityThread.performStopActivityInner:4350 android.app.ActivityThread.handleStopActivity:4425 android.app.servertransaction.StopActivityItem.execute:41 android.app.servertransaction.TransactionExecutor.executeLifecycleState:145 android.app.servertransaction.TransactionExecutor.execute:70
D/InputTransport(29847): Input channel destroyed: fd=100
I/FirebaseAuth(29847): [FirebaseAuth:] Loading module via FirebaseOptions.I/FirebaseAuth(29847): [FirebaseAuth:] Preparing to create service connection to gms implementation
As for the path of the database is todo/userId/Dan Database.
EDIT: Forgot to mention that I updated my security rules as following:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}
EDIT
As per #Andrey Ilyunin comment I've authenticated my application to an user and applied the same security rules. I still get the same exception, i.e:
D/NetworkSecurityConfig( 4123): No Network Security Config specified, using platform default
W/SyncTree( 4123): Listen at /todo failed: DatabaseError: Permission denied
E/flutter ( 4123): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: Instance of 'DatabaseError'
E/flutter ( 4123): null
E/flutter ( 4123): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: Instance of 'DatabaseError'
E/flutter ( 4123): null

Flutter built value Deserialization 'failed due to: Tried to build class but nested builder for field threw: Tried to construct class with null field

I am using built value for my PODO class
Following is my code
library mobile_login_model;
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
part 'mobile_login_model.g.dart';
abstract class MobileLoginModel implements Built<MobileLoginModel, MobileLoginModelBuilder> {
MobileLoginModel._();
factory MobileLoginModel([updates(MobileLoginModelBuilder b)]) = _$MobileLoginModel;
#BuiltValueField(wireName: 'status')
int get status;
#BuiltValueField(wireName: 'msg')
String get msg;
#BuiltValueField(wireName: 'data')
MobileLoginData get data;
static Serializer<MobileLoginModel> get serializer => _$mobileLoginModelSerializer;
}
abstract class MobileLoginData implements Built<MobileLoginData, MobileLoginDataBuilder> {
MobileLoginData._();
factory MobileLoginData([updates(MobileLoginDataBuilder b)]) = _$MobileLoginData;
#BuiltValueField(wireName: 'userid')
String get userId;
#BuiltValueField(wireName: 'mobile')
String get mobile;
static Serializer<MobileLoginData> get serializer => _$mobileLoginDataSerializer;
}
Following is my http code when i click on submit button
Future<MobileLoginModel> submitMobileNumber(String mobile) async {
final response = await http.post(LOGIN_MOBILE_NUMBER_URL,body: {
"mobile": mobile
});
MobileLoginModel mobileLoginModel = standardSerializers.deserializeWith(MobileLoginModel.serializer, json.decode(response.body));
return mobileLoginModel;
}
The http request is fired whenever i enter a mobile number and click on submit button. If i enter a correct number then everything works fine
but suppose i enter a wrong number i get following error in my console
E/flutter (19934): [ERROR:flutter/shell/common/shell.cc(184)] Dart Error: Unhandled exception:
E/flutter (19934): Deserializing '[status, 0, msg, Invalid Mobile Number.]' to 'MobileLoginModel' failed due to: Tried to build class "MobileLoginModel" but nested builder for field "data" threw: Tried to construct class "MobileLoginData" with null field "userId". This is forbidden; to allow it, mark "userId" with #nullable.
E/flutter (19934): #0 BuiltJsonSerializers._deserialize (package:built_value/src/built_json_serializers.dart:154:11)
E/flutter (19934): #1 BuiltJsonSerializers.deserialize (package:built_value/src/built_json_serializers.dart:105:18)
E/flutter (19934): #2 BuiltJsonSerializers.deserializeWith (package:built_value/src/built_json_serializers.dart:35:12)
E/flutter (19934): #3 MobileLoginApiProvider.submitMobileNumber (package:dice_clutter/resources/mobile_login/mobile_login_api_provider.dart:18:61)
E/flutter (19934): <asynchronous suspension>
E/flutter (19934): #4 MobileLoginRepository.submitMobileNumber (package:dice_clutter/resources/mobile_login/mobile_login_repository.dart:16:35)
E/flutter (19934): <asynchronous suspension>
E/flutter (19934): #5 MobileLoginBloc.submitMobileNumber (package:dice_clutter/bloc/mobile_login/mobile_login_bloc.dart:22:41)
E/flutter (19934): <asynchronous suspension>
E/flutter (19934): #6 _SubmitMobileNumberState.submitMobileNumber.<anonymous closure> (package:dice_clutter/screens/mobile_login/mobile_login.dart:177:25)
E/flutter (19934): #7 _RootZone.runUnary (dart:async/zone.dart:1379:54)
E/flutter (19934): #8 _FutureListener.handleValue (dart:async/future_impl.dart:129:18)
E/flutter (19934): #9 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:642:45)
E/flutter (19934): #10 Future._propagateToListeners (dart:async/future_impl.dart:671:32)
E/flutter (19934): #11 Future._complete (dart:async/future_impl.dart:476:7)
E/flutter (19934): #12 _SyncCompleter.complete (dart:async/future_impl.dart:51:12)
E/flutter (19934): #13 _AsyncAwaitCompleter.complete (dart:async/runtime/libasync_patch.dart:28:18)
E/flutter (19934): #14 _completeOnAsyncReturn (dart:async/runtime/libasync_patch.dart:295:13)
E/flutter (19934): #15 checkInternetConnection (package:dice_clutter/helpers/internet_connection.dart)
E/flutter (19934): <asynchronous suspension>
E/flutter (19934): #16 _SubmitMobileNumberState.submitMobileNumber (package:dice_clutter/screens/mobile_login/mobile_login.dart:174:5)
E/flutter (19934): #17 _SubmitMobileNumberState.build.<anonymous closure>.<anonymous closure> (package:dice_clutter/screens/mobile_login/mobile_login.dart:151:31)
E/flutter (19934): #18 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:507:14)
E/flutter (19934): #19 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:562:30)
E/flutter (19934): #20 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:102:24)
E/flutter (19934): #21 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:242:9)
E/flutter (19934): #22 TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:175:7)
E/flutter (19934): #23 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:315:9)
E/flutter (19934): #24 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:73:12)
E/flutter (19934): #25 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:101:11)
E/flutter (19934): #26 _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:180:19)
E/flutter (19934): #27 _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:158:22)
E/flutter (19934): #28 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:138:7)
E/flutter (19934): #29 _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:101:7)
E/flutter (19934): #30 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:85:7)
E/flutter (19934): #31 _invoke1 (dart:ui/hooks.dart:168:13)
E/flutter (19934): #32 _dispatchPointerDataPacket (dart:ui/hooks.dart:122:5)
Because the data property is missing in the received JSON {"status": 0, "msg": "Invalid Mobile Number."} it needs to be nullable. By default all properties are non-nullable.
#nullable
#BuiltValueField(wireName: 'data')
MobileLoginData get data;
https://pub.dartlang.org/documentation/built_value/latest/built_value/nullable-constant.html

Firestore access broken after an offline attempt

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.

Resources