Reputation: 755
I am trying to fetch records from the Firestore database and show it in the Flutter app.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Hello'),
actions: <Widget>[
IconButton(icon: Icon(Icons.list), onPressed: _pushSaved)
]),
drawer: _buildDrawer(),
body: _buildCarpoolsList(),
);
}
Widget _buildCarpoolsList() {
return StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection("carpools").snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return CircularProgressIndicator();
} else {
var _carpools = snapshot.data.documents;
return ListView(
padding: const EdgeInsets.all(16.0),
children: _deserializeCarpools(_carpools));
}
});
}
In the _buildCarpoolsList()
function the snapshot.ConnectionState
is always ConnectionState.waiting
, and the function returns CircularProgressBar()
.
I have got a collection carpools
in the FireStore database with a few records in it.
I have set the firestore database rules to allow all.
rules_version = '2';
service cloud.firestore {
match /** {
allow read, write: if true;
}
}
Edit: My Firebase authentication works. (If that helps)
What could be missing here?
Upvotes: 11
Views: 3735
Reputation: 503
If you reviewed the Cloud Firestore on FlutterFire, and there was no issue with the security rules, check whether you use .map()
or .forEach()
correctly.
For example, the following is working well:
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
List<String> urls = [];
if (snapshot.hasError) {
return ...
}
if (snapshot.connectionState == ConnectionState.waiting) {
return ...
}
**snapshot.data.docs.forEach((QueryDocumentSnapshot document) {
print(document);
urls.add(...);
});**
return Container(
child: GridView.count(
crossAxisCount: ...,
childAspectRatio: (...),
children: List.generate(urls.length, (index) {
However, the below example does nothing, if your widget was supposed to show some images using an item in the urls
:
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
List<String> urls = [];
if (snapshot.hasError) {
return ...
}
if (snapshot.connectionState == ConnectionState.waiting) {
return ...
}
**snapshot.data.docs.map((QueryDocumentSnapshot document) {
print(document);
urls.add(...);
});**
return Container(
child: GridView.count(
crossAxisCount: ...,
childAspectRatio: (...),
children: List.generate(urls.length, (index) {
While document
is printed in both examples, it does not mean that they do the same thing. It is also worth noting that the condition snapshot.connectionState == ConnectionState.waiting
is satisfied at least one time during the loading, and it makes you think that you are waiting permanently.
Upvotes: 0
Reputation: 7718
I also had the same issue, I was following the guides from Flutter In focus. The state was always connecting and no data was returned and also no error. This was in iOS and then I ran the app in Android and fortunately in the LogCat, I saw a message permission to listen to query was denied
by default the security rules seem to deny everything, you. have to allow it as @MSaudi mentioned. I added this and it worked
match /{collectionName}/{documentId} {
allow read, write : if collectionName == "products";
}
To play with security rules, the below link will help
Upvotes: 0
Reputation: 127
I came across the same situation. Using cloud_firestore plugin and StreamBuilder :
class DealerWorkPage extends StatelessWidget {
final String wheelId;
DealerWorkPage(this.wheelId);
@override
Widget build(BuildContext context) {
return StreamBuilder(
stream: Firestore.instance.collection('wheels').document(this.wheelId).snapshots(),
builder: (context, asyncSnapshot) {
if(asyncSnapshot.hasError) return Text('Error: ${asyncSnapshot.error}');
switch (asyncSnapshot.connectionState) {
case ConnectionState.none: return Center(child: Text('No data'));
case ConnectionState.waiting: return Center(child: CircularProgressIndicator());
case ConnectionState.active:
return Center(child: Text(asyncSnapshot["description"]))
break;
}
return null;
});
}
}
This code runs with no error, but only showing CircularProgressIndicator() forever!
I tried another flutter project that has an add clause like :
await _firestore.collection('messages').add({
'text': messageController.text,
'from': widget.user.email,
'date': DateTime.now().toIso8601String().toString(),
});
And it throws : PlatformException(Error performing setData, PERMISSION_DENIED: Missing or insufficient permission
Now, just like @MSaudi said, this error has something todo with firebase security rules. I then check the database security rules in Firebase Console. Yes I forget to 'extend' the date for database access :
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
// This rule allows anyone on the internet to view, edit, and delete
// all data in your Firestore database. It is useful for getting
// started, but it is configured to expire after 30 days because it
// leaves your app open to attackers. At that time, all client
// requests to your Firestore database will be denied.
//
// Make sure to write security rules for your app before that time, or else
// your app will lose access to your Firestore database
match /{document=**} {
allow read, write: if request.time < timestamp.date(2020, 1, 27);
}
}
}
AFTER changing the request.time timestamp.date(2020, 1, 27) to later date, VOILA! my StreamBuilder behaves as expected!. No more waiting forever! I hope this information helps.
Upvotes: 0
Reputation: 4652
You may revise security settings in Firebase
console.
If you created the database in production mode (not testing), it comes with security rules that might block any connection until you allow so.
Open the Rules
tab in the database screen, (JUST TO TEST -> Make allow read, write; as below )
If it works, just consider reading about the security rules and set it appropriately as per your needs.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write;
}
}
}
Upvotes: 1
Reputation: 524
Did you add GoogleService-Info.plist
in your Runner.xcworkspace
, you must open it with Xcode. I always forget to add it in new project :
Upvotes: 0