Estamos creando una aplicación de chat en tiempo real con Firestore. Necesitamos manejar una situación en la que no hay conexión a Internet. El código básico de envío de mensajes se ve así
let newMsgRef = database.document(“/users/\(userId)/messages/\(docId)“) newMsgRef.setData(payload) { err in if let error = err { // handle error } else { // handle OK } }Cuando el dispositivo está conectado, todo funciona bien. Cuando el dispositivo no está conectado, no se llama a la devolución de llamada y no obtenemos el estado de error.
Cuando el dispositivo vuelve a estar en línea, el registro aparece en la base de datos y se activa la devolución de llamada, sin embargo, esta solución no es aceptable para nosotros porque, mientras tanto, la aplicación podría haberse cerrado y nunca recibiremos la devolución de llamada y podremos establecer el estado de el mensaje como enviado.
Pensamos que deshabilitar la persistencia fuera de línea (que está activada de manera predeterminada) haría que se desencadenara la devolución de llamada fallida de inmediato, pero inesperadamente, no es así.
También intentamos agregar un tiempo de espera después del cual la operación de envío se consideraría fallida, pero no hay forma de cancelar la entrega del mensaje cuando el dispositivo vuelve a estar en línea, ya que Firestore usa su cola y eso genera más confusión porque el mensaje se entrega en el receptor. lado, mientras que no puedo manejar eso en el lado del remitente.
Si pudiéramos reducir el tiempo de espera, podría ser una buena solución, obtendríamos rápidamente un estado de éxito/fracaso, pero Firebase no proporciona esa configuración.
Una memoria caché sin conexión incorporada podría ser otra opción, podría tratar todas las escrituras como exitosas y confiar en el mecanismo de sincronización de Firestore, pero si la aplicación se canceló durante la desconexión, el mensaje no se entrega.
En última instancia, necesitamos un mecanismo de retroalimentación consistente que active una devolución de llamada, o proporcione una forma de monitorear el mensaje en la cola, etc., para que sepamos con certeza si el mensaje se envió o no, y cuándo sucedió.
Las devoluciones de llamada de finalización para Firestore solo se llaman cuando los datos se han escrito (o rechazado) en el servidor. No hay devolución de llamada cuando no hay conexión de red, ya que se considera una condición normal para Firestore SDK.
Su mejor opción es detectar si hay una conexión de red de otra manera y luego actualizar su interfaz de usuario en consecuencia. Algunos resultados de búsqueda relevantes:
Como alternativa, puede verificar el uso de los metadatos integrados de Firestore para determinar si se han entregado los mensajes. Como se muestra en la documentación sobre eventos para cambios locales :
Los documentos recuperados tienen una propiedad
metadata.hasPendingWritesque indica si el documento tiene cambios locales que aún no se han escrito en el backend. Puede usar esta propiedad para determinar el origen de los eventos recibidos por su escucha de instantáneas:db.collection("cities").document("SF") .addSnapshotListener { documentSnapshot, error in guard let document = documentSnapshot else { print("Error fetching document: \(error!)") return } let source = document.metadata.hasPendingWrites ? "Local" : "Server" print("\(source) data: \(document.data() ?? [:])") }
Con esto también puede mostrar el mensaje correctamente en la interfaz de usuario