flutter_markdown with Firestore image crash - firebase

I'm using flutter_markdown: ^0.2.0 and I want to display an image saved on firebase firestorage.
If I try to display the markdown in my flutter widget:
class LessonScreen extends StatelessWidget {
const LessonScreen({this.lesson});
final Lesson lesson;
#override
Widget build(BuildContext context) {
return Scaffold(
body:
MarkdownBody(data: lesson.content));
}
}
My app crash.
I/flutter (25385): ══╡ EXCEPTION CAUGHT BY IMAGE RESOURCE SERVICE ╞════════════════════════════════════════════════════
I/flutter (25385): The following _Exception was thrown resolving an image codec:
I/flutter (25385): Exception: HTTP request failed, statusCode: 403,
I/flutter (25385): https://firebasestorage.googleapis.com/v0/b/appname-db7de.appspot.com/o/image1.PNG?alt=media&token=xxxx
I don't have this problem with other images, but I have it only with the images saved on firestorage.
SOLVED
I have seen that the url that doesn't work is:
alt=media&token=xxxx
instead of
alt=media&token=xxxx
this is the link to flutter_markown repository issue.
I hope this fix will be available sooner or later

HTTP request failed, statusCode: 403 it means auth error.
You should check more detail about firebase store.
It's not about markdown stuff.

I had the same issue the problem was with the permission in the Firebase Storage so I change my Firebase Storage permission.
From
allow read, write: if request.auth != null;
To this
allow read, write;

Related

Firebase unable to reconnect after exiting Doze Mode

Overview
I'm using Flutter with Firebase. After the phone/app enters Doze Mode, Firebase needs a few minutes (too long!) to reconnect. It took me weeks to find how to reproduce this issue.
Steps to reproduce:
Open a Flutter app and select a screen where you can call Firebase with a click of a button
Enter Androids' Doze Mode (Lock the screen, run adb shell dumpsys battery unplug, and then run adb shell dumpsys deviceidle force-idle)
After a few seconds/minutes, under the "Run" tab, the following will appear:
Stream closed with status: Status{code=UNAVAILABLE, description=Keepalive failed. The connection is likely gone, cause=null}.
and
[{0}] Failed to resolve name. status={1}
Now, unlock your phone and try to make a Firebase query
For me, the following error appears 8 out of 10 times. The connection will re-establish after hitting the "Retry" button, but only after a few minutes which is, of course, too late.
W/XXX.XXXXXXX(14214): Accessing
hidden method Lsun/misc/Unsafe;->getLong(Ljava/lang/Object;J)J
(greylist,core-platform-api, linking, allowed)
W/XXX.XXXXXXX(14214): Accessing hidden method
Lsun/misc/Unsafe;->putObject(Ljava/lang/Object;JLjava/lang/Object;)V
(greylist, linking, allowed) W/Firestore(14214): (22.0.1)
[WatchStream]: (72436f2) Stream closed with status:
Status{code=UNAVAILABLE, description=Unable to resolve host
firestore.googleapis.com, cause=java.lang.RuntimeException:
java.net.UnknownHostException: Unable to resolve host
"firestore.googleapis.com": No address associated with hostname
W/Firestore(14214): at
io.grpc.internal.DnsNameResolver.resolveAll(DnsNameResolver.java:436)
W/Firestore(14214): at
io.grpc.internal.DnsNameResolver$Resolve.resolveInternal(DnsNameResolver.java:272)
W/Firestore(14214): at
io.grpc.internal.DnsNameResolver$Resolve.run(DnsNameResolver.java:228)
W/Firestore(14214): at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
W/Firestore(14214): at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
W/Firestore(14214): at java.lang.Thread.run(Thread.java:919)
W/Firestore(14214): Caused by: java.net.UnknownHostException: Unable
to resolve host "firestore.googleapis.com": No address associated with
hostname W/Firestore(14214): at
java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:156)
W/Firestore(14214): at
java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:103)
W/Firestore(14214): at
java.net.InetAddress.getAllByName(InetAddress.java:1152)
W/Firestore(14214): at
io.grpc.internal.DnsNameResolver$JdkAddressResolver.resolveAddress(DnsNameResolver.java:646)
W/Firestore(14214): at
io.grpc.internal.DnsNameResolver.resolveAll(DnsNameResolver.java:404)
W/Firestore(14214): ... 5 more W/Firestore(14214): Caused by:
android.system.GaiException: android_getaddrinfo failed: EAI_NODATA
(No address associated with hostname) W/Firestore(14214): at
libcore.io.Linux.android_getaddrinfo(Native Method)
W/Firestore(14214): at
libcore.io.ForwardingOs.android_getaddrinfo(ForwardingOs.java:74)
W/Firestore(14214): at
libcore.io.BlockGuardOs.android_getaddrinfo(BlockGuardOs.java:200)
W/Firestore(14214): at
libcore.io.ForwardingOs.android_getaddrinfo(ForwardingOs.java:74)
W/Firestore(14214): at
java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:135)
W/Firestore(14214): ... 9 more W/Firestore(14214): }.
W/XXX.XXXXXXX(14214): Accessing hidden method
Lsun/misc/Unsafe;->getLong(Ljava/lang/Object;J)J
(greylist,core-platform-api, linking, allowed) I/flutter (14214):
MyDatabase | getDatabaselData |
[cloud_firestore/unavailable] The service is currently unavailable.
This is a most likely a transient condition and may be corrected by
retrying with a backoff.
The caught exception is: MyDatabase | getDatabaselData | [cloud_firestore/unavailable] The service is currently unavailable.
Pubspec.yaml
cloud_firestore: ^0.14.1+3
firebase_storage: ^4.0.1
firebase_core: ^0.5.0+1
firebase_auth: ^0.18.3
Edit 2: At the moment of writing this edit, there is a commit pending on FlutterFire git (but not yet published). So the solution will be to update to the latest Firebase_Core. It is also possible to fix it manually in Firebase_Core package > gradle.properties > change FirebaseSDKVersion=28.0.1 to FirebaseSDKVersion=28.1.0.
Edit: The issue still persists if the phone enters the state naturally (6 hours of complete inactivity). It seems this issue must be fixed inside FirebaseSDK and so far it hasn't been: https://github.com/FirebaseExtended/flutterfire/issues/4305
Old answer:
I see many people strugling with this, and I have finally found the solution.
It seems Firebase is mostly wasting time on the previous (dis)connection rather than the new connection. So what I did, is disconnecting Firebase whenever the app goes to the background, and reconnecting it upon resuming. In this case, a new connection is established within seconds.
Here is the code; create a life cycle manager class (observer) and wrap it around your MaterialApp. Try-Catch is probably not necessary, but I will be pushing to production tomorrow so it's just a precaution.
lifecycle_manager.dart
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class LifecycleManager extends StatefulWidget {
final Widget child;
LifecycleManager({Key key, this.child}) : super(key: key);
#override
_LifecycleManagerState createState() => _LifecycleManagerState();
}
class _LifecycleManagerState extends State<LifecycleManager> with WidgetsBindingObserver {
#override
Widget build(BuildContext context) {
return widget.child;
}
#override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
#override
void dispose() {
super.dispose();
WidgetsBinding.instance.removeObserver(this);
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
try {
if (state != AppLifecycleState.resumed) FirebaseFirestore.instance.disableNetwork();
else FirebaseFirestore.instance.enableNetwork();
} catch (error) {
print('LifecycleManager | didChangeAppLifecycleState | ' + error.toString());
}
}
}
main.dart
import 'lifecycle_manager.dart';
LifecycleManager(child: MaterialApp());
(I have also updated all my dependencies, but that didn't solve the problem)
Delete the application from the emulator.
Install the application.
Delete collection from firebase.
Run the code again.
This solved my problem without any changes to my versions.
Pubspec.yaml
version: 1.0.0+1
environment:
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
get_it: ^1.0.3+2
provider: ^5.0.0
cloud_firestore: ^0.12.9+4
firebase_auth: 0.14.0+5
Usage
class MainPage extends StatefulWidget {
const MainPage({Key key}) : super(key: key);
#override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
final Firestore _firestore = Firestore.instance;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("First Page"),
),
body: Center(
child: Column(
children: [
RaisedButton(
child: Text("Add Data"),
color: Colors.deepPurple,
onPressed: _addData,
)
],
),
),
);
}
void _addData() {
Map<String, dynamic> addUser = Map();
addUser["name"] = "name1";
addUser["surname"] = "surname1";
_firestore
.collection("users")
.document("nameandsurname")
.setData(addUser)
.then((value) => debugPrint("user added"));
}
}

Flutter HTTP package with firebase not working for delete request, but working for post, patch and fetch?

I'm new to both Flutter and Firebase, so please bear with me.
I have a realtime database which stores (as of now) a list of products.
The addProduct, and updateProduct methods in my code are working fine. But for some reason, deleteProduct isn't. It's giving me a 404 error when I try to access the database through URL, even though the exact same URL is working for the updateProduct function.
Here is the code for updateProduct:
final _productIndex =
_items.indexWhere((element) => element.id == productId);
if (_productIndex >= 0) {
final url = Uri.parse(
"https://flutter-shop-app-f1b23-default-rtdb.firebaseio.com/products/$productId.json");
return http
.patch(url,
body: json.encode({
"title": newProduct.title,
"description": newProduct.description,
"imageUrl": newProduct.imageUrl,
"price": newProduct.price,
}))
.then((_) {
_items[_productIndex] = newProduct;
notifyListeners();
});
} else {
print("ERROR");
}
return Future(null);
}
And here is the code for deleteProduct:
Future<void> deleteProduct(String productId) {
print(productId);
final url = Uri.parse(
"https://flutter-sdhop-app-f1b23-default-rtdb.firebaseio.com/products/$productId.json");
print(url.toString());
return http.delete(url).then((response) {
print(response.statusCode);
print(response.body);
if (response.statusCode >= 400) {
throw HttpException("Could not delete!");
}
_items.removeWhere((element) => element.id == productId);
notifyListeners();
});
}
And this is the (printed) error message :
I/flutter ( 5104): 404
I/flutter ( 5104): {
I/flutter ( 5104): "error" : "404 Not Found"
I/flutter ( 5104): }
I tried opening the URL in my browser window, and got the same 404 error, which was puzzling since Flutter seems to be able to access it for updating without any issues. The firebase project was created in test mode, so I don't think authentication will be the issue here.
Please help on how to fix this.
Here are the database rules:
{
"rules": {
".read": "now < 1624300200000", // 2021-6-22
".write": "now < 1624300200000", // 2021-6-22
}
}
To be honest I would not recommend that solution for you. The REST API is made for use cases where there is no native SDK. Flutter has definitely a very good one you can use. If you continue with that approach you would have the double work because you can't reause anything you made with the REST API. And also the BEST stuff in Firebase like realtime listeners is not in the REST API. Authentication is a hustle with the REST API. It's only a Plan B solution when there is no native SDK.
In the link for deletion you have a typo:
https://flutter-sdhop-app-f1b23-default-rtdb.firebaseio.com/products/
It should be shop and not sdhp.

How to get firestore persistent with flutter fire to Cache documents [duplicate]

As I know Firebase on Flutter will automatically read from cache first but I noticed while development that an app just play around with almost 1 stream that has 10 or 15 document I have reach reads above 4000 reads! By this way if 10 users has used my app I will pay all I have, so I have recheck every query, snapshot and put this code to know
print(itemDoc.metadata.isFromCache ? "itemDoc NOT FROM NETWORK" : "itemDoc FROM NETWORK");
Edit write the code and more explain
I noticed this issue appear in IOS when I update,add,delete a document console print all stored documents.
I have Main Stream that I get all users lists
then every list I create stream for it to listen list's items
userListsStream(uid){
Stream<QuerySnapshot> shoppingListsStream =
Firestore.instance.collection('lists').where('owner', arrayContains: uid).snapshots();
shoppingListsStream.listen(
(QuerySnapshot listsQuery) async {
List<DocumentSnapshot> listsDocs = listsQuery.documents;
if (listsDocs.length != 0) {
//? foreach on lists Documents
listsDocs.forEach(
(DocumentSnapshot listDoc) async {
print(listDoc.metadata.isFromCache ? "listDoc NOT FROM
NETWORK" : "listDoc FROM NETWORK");
listItemsStream(listDoc.documentID);
}
)
}
})
}
listItemsStream(lid){
shoppingItemsRef = Firestore.instance.collection('lists').document(lid).collection('items');
shoppingItemsRef.snapshots().listen(
(QuerySnapshot itemsQuery) async {
List<DocumentSnapshot> itemsDocs = itemsQuery.documents;
if (itemsDocs.length != 0) {
itemsDocs.forEach(
(DocumentSnapshot itemDoc) async {
print(itemDoc.metadata.isFromCache ? "itemDoc NOT FROM
NETWORK" : "itemDoc FROM NETWORK");
}
)
}
}
those two methods in Provider that I call the main function in Home.dart initState
#override
void initState() {
Provider.of<ListsProvider>(context, listen: false)
.userListsStream(uid);
}
The isFromCache flag indicates whether the document is guaranteed to be up to date with the server, or that it may be a stale result from the cache. If it's false that doesn't necessarily means the document was read from the server, but that you can be guaranteed that the document is up to date with the server.
To show what this means, I can this snippet
var snapshotsStream = Firestore.instance.collection("chat").orderBy("timestamp", descending: true).limit(3).snapshots();
snapshotsStream.listen((querySnapshot) {
print("We got a new QuerySnapshot");
querySnapshot.documents.forEach((doc) {
print(doc.documentID+": "+(doc.metadata.isFromCache ? "from CACHE " : "from SERVER "));
});
querySnapshot.documentChanges.forEach((docChange) {
print(docChange.type.toString()+(docChange.document.metadata.isFromCache ? "doc from CACHE " : "doc from SERVER "));
});
}, onError: (error) {
print(error);
});
The output I get initially is:
flutter: We got a new QuerySnapshot
flutter: 5nAr5pYgwXJ0n3pWZkLw: from SERVER
flutter: moysGY7Ea7TCf28fcEVC: from SERVER
flutter: PuNnPaiLMIE7704R9NuL: from SERVER
flutter: 5nAr5pYgwXJ0n3pWZkLw: DocumentChangeType.addeddoc from SERVER
flutter: moysGY7Ea7TCf28fcEVC: DocumentChangeType.addeddoc from SERVER
flutter: PuNnPaiLMIE7704R9NuL: DocumentChangeType.addeddoc from SERVER
Then when I make a change on the server, it prints:
flutter: We got a new QuerySnapshot
flutter: 5nAr5pYgwXJ0n3pWZkLw: from SERVER
flutter: moysGY7Ea7TCf28fcEVC: from SERVER
flutter: PuNnPaiLMIE7704R9NuL: from SERVER
flutter: 5nAr5pYgwXJ0n3pWZkLw: DocumentChangeType.modifieddoc from SERVER
So using the isFromCache property is not meant to determine whether the document was a charged read on the server, but whether the document is guaranteed to be up to date with the server.
To know what documents have changed, you can iterate over the documentChanged collection, as shown in the code above.
As to having more reads than you expected, one of the more common causes of this is keeping Firestore panel open in the Firebase console. Reads performed by the console are charged towards your project. For more on this, see:
Google Cloud Firestore console reading of all documents and charges
Firestore collection listeners enormous number of reads
Firestore - unexpected reads

Capture cloud firestore document snapshot error in Flutter

I am trying to capture the error thrown by firstore plugin in flutter when listening to document snapshots. The error is thrown in the debug logs but I cannot access it on catch error or handle error. Is this an enhancement needed for the plugin or is there a way?
Error in debug
I/System.out(16041): com.google.firebase.firestore.FirebaseFirestoreException: PERMISSION_DENIED: Missing or insufficient permissions.
Here is my code, I tried a number of ways but it didn't work
_getUserCollection.document(uid).snapshots();
_getUserCollection.document(uid).snapshots().handleError((onError) {
print(onError.toString());
});
try {
_getUserCollection.document(uid).snapshots();
} catch (e) {
print(e);
}
try {
_getUserCollection.document(uid).snapshots();
} on PlatformException catch (e) {
print(e.toString());
}
_getUserCollection.document(uid).snapshots().listen((event) {
print('here on listen');
}, onError: (e) {
print('on error $e');
});
"Missing or insufficient permissions" means that your query violated one of your security rules. You will need to examine those rules, and make sure they allow the query you intend to perform.
There is plenty of documentation for security rules, and it's necessary to understand how they work in order to work with Firestore effectively from web and mobile clients.
It's not true that you can't catch an error from a Firestore query. You can't use try/catch - you will have to pass an error handler to listen().
I was having the same issue. PERMISSION_DENIED was coming out in the logs but I wanted to catch the error myself so that I could display it to the user. I found this issue on GitHub:
Firebase - native error messages not provided issue
It states that a lot of work has been done to improve the error handling in Firebase. So I spent yesterday upgrading my app to the latest version of firebase_auth (0.18.0 at the time of writing) and I can now catch and handle the PERMISSION_DENIED error like this:
return StreamBuilder<List<DistanceDocSnapshot>>(
stream: _eventStream,
builder: (BuildContext context,
AsyncSnapshot<List<DistanceDocSnapshot>> snapshot) {
if (snapshot.hasError) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'Error retrieving events: ${snapshot.error.toString()}',
style: TextStyle(fontSize: 20.0),
textAlign: TextAlign.center,
),
);
}
if (snapshot.hasData) {
// Handle data as desired
}
}
);
This can be seen working in the following screenshot Screenshot of error on my app (I had to provide a link to the screenshot because I don't have enough rep to embed images yet)
My code is laid out differently to yours but I think yours will start working as desired if you just upgrade your firebase_auth version.

How to use ML Kit cloud text recognizer for flutter?

I am using the package 'firebase_ml_vision' in my project to do OCR. I can read Latin based languages just fine, however, I want to read Chinese characters. I know that there are on the device and cloud-based versions of the text recognizer. However, I can't find out how to 'enable' the cloud-based version in my app. I have already activated cloud-based APIs in Firebase as seen in this image:
Activated cloud apis
The code that I currently use is:
void _initializeVision() async{
final File imageFile = File(imagePath);
final FirebaseVisionImage visionImage = FirebaseVisionImage.fromFile(imageFile);
final TextRecognizer textRecognizer = FirebaseVision.instance.textRecognizer();
final VisionText visionText = await textRecognizer.processImage(visionImage);
for(TextBlock blocks in visionText.blocks){
for(TextLine line in blocks.lines){
print(line.text);
}
}}
Image I try to read
Results:
I/flutter (10432): FamilyMart Collection
I/flutter (10432): 10
I/flutter (10432): Pocket facial tissue
I/flutter (10432): Without fluorescent virgin fber from wood puip
I/flutter (10432): pampers your skin
Can anyone explain to me how to use cloud text recognizer for Flutter?
Have the same problem, don't think cloud-OCR currently works with the ML-Package. I managed to make it work via a POST request.
Here is everything you need: Make Vision API request
// Upload Image to Firebase and get
// 1. DownloadUrl or
// 2. StorageBucket or
//
// 3. Convert Image to base64 with
// String base64Image = base64Encode(File(imagePath).readAsBytesSync());
// (does not work for me, if you use this way make sure your `body` is correct)
String body = """{
'requests': [
{
'image': {
'source': {
'imageUri': '$downloadUrl'
}
},
'features': [
{
'type': 'DOCUMENT_TEXT_DETECTION'
}
]
}
]
}""";
http.Response res = await http
.post(
"https://vision.googleapis.com/v1/images:annotate?key=$API_KEY",
body: body
);
print("${res.body}");

Resources