Geliştirdiğiniz uygulamanın türüne bağlı olarak, hangi kullanıcılarınızın veya cihazlarınızın etkin bir şekilde çevrimiçi olduğunu tespit etmeyi (diğer adıyla "mevcudiyet" tespiti) faydalı bulabilirsiniz.
Örneğin, sosyal ağ gibi bir uygulama geliştiriyorsanız veya IoT cihaz filosu dağıtıyorsanız bu bilgileri kullanarak çevrimiçi ve sohbete uygun arkadaşların listesini görüntüleyebilir ya da IoT cihazlarınızı "son görülme"ye göre sıralayabilirsiniz.
Cloud Firestore, varlık durumunu yerel olarak desteklemez ancak varlık durumu sistemi oluşturmak için diğer Firebase ürünlerinden yararlanabilirsiniz.
Çözüm: Realtime Database ile Cloud Functions
Cloud Firestore uygulamasını Firebase Realtime Database'in yerel durum özelliğine bağlamak için Cloud Functions'ı kullanın.
Bağlantı durumunu bildirmek için Realtime Database'i, ardından bu verileri Cloud Firestore içine yansıtmak için Cloud Functions'ı kullanın.
Realtime Database'de varlık durumunu kullanma
Öncelikle, geleneksel bir durum sisteminin Realtime Database'de nasıl çalıştığını düşünün.
Web
// Fetch the current user's ID from Firebase Authentication. var uid = firebase.auth().currentUser.uid; // Create a reference to this user's specific status node. // This is where we will store data about being online/offline. var userStatusDatabaseRef = firebase.database().ref('/status/' + uid); // We'll create two constants which we will write to // the Realtime database when this device is offline // or online. var isOfflineForDatabase = { state: 'offline', last_changed: firebase.database.ServerValue.TIMESTAMP, }; var isOnlineForDatabase = { state: 'online', last_changed: firebase.database.ServerValue.TIMESTAMP, }; // Create a reference to the special '.info/connected' path in // Realtime Database. This path returns `true` when connected // and `false` when disconnected. firebase.database().ref('.info/connected').on('value', function(snapshot) { // If we're not currently connected, don't do anything. if (snapshot.val() == false) { return; }; // If we are currently connected, then use the 'onDisconnect()' // method to add a set which will only trigger once this // client has disconnected by closing the app, // losing internet, or any other means. userStatusDatabaseRef.onDisconnect().set(isOfflineForDatabase).then(function() { // The promise returned from .onDisconnect().set() will // resolve as soon as the server acknowledges the onDisconnect() // request, NOT once we've actually disconnected: // https://firebase.google.com/docs/reference/js/firebase.database.OnDisconnect // We can now safely set ourselves as 'online' knowing that the // server will mark us as offline once we lose connection. userStatusDatabaseRef.set(isOnlineForDatabase); }); });
Bu örnek, eksiksiz bir Realtime Database durum sistemidir. Bağlantı kopmaları, kilitlenmeler gibi sorunları çözer.
Cloud Firestore cihazına bağlanıyor
Cloud Firestore üzerinde benzer bir çözüm uygulamak için aynı Realtime Database kodunu kullanın, ardından Realtime Database ile Cloud Firestore arasında senkronizasyonu sağlamak için Cloud Functions'ı kullanın.
Henüz yapmadıysanız projenize Realtime Database'i ekleyin ve yukarıdaki iletişim durumu çözümünü dahil edin.
Ardından, aşağıdaki yöntemleri kullanarak evde olma durumunu Cloud Firestore ile senkronize edersiniz:
- Yerel olarak, çevrimdışı cihazın Cloud Firestore önbelleğine kaydedilir. Böylece uygulama, çevrimdışı olduğunu bilir.
- Cloud Firestore hizmetine erişen diğer tüm cihazların bu cihazın çevrimdışı olduğunu bilmesi için Cloud Functions işlevi kullanılarak genel olarak.
Bu eğitimde önerilen işlevler istemci uygulamasında çalıştırılamaz. Bu işlevlerin Cloud Functions for Firebase'e dağıtılması gerekir ve Firebase Admin SDK'sından sunucu tarafı mantığı gerektirir. Ayrıntılı bilgi için Cloud Functions belgelerine bakın.
Cloud Firestore kullanıcısının yerel önbelleği güncelleniyor
İlk sorunu çözmek için gereken değişikliklere göz atalım: Cloud Firestore uygulamasının yerel önbelleğini güncelleme.
Web
// ... var userStatusFirestoreRef = firebase.firestore().doc('/status/' + uid); // Firestore uses a different server timestamp value, so we'll // create two more constants for Firestore state. var isOfflineForFirestore = { state: 'offline', last_changed: firebase.firestore.FieldValue.serverTimestamp(), }; var isOnlineForFirestore = { state: 'online', last_changed: firebase.firestore.FieldValue.serverTimestamp(), }; firebase.database().ref('.info/connected').on('value', function(snapshot) { if (snapshot.val() == false) { // Instead of simply returning, we'll also set Firestore's state // to 'offline'. This ensures that our Firestore cache is aware // of the switch to 'offline.' userStatusFirestoreRef.set(isOfflineForFirestore); return; }; userStatusDatabaseRef.onDisconnect().set(isOfflineForDatabase).then(function() { userStatusDatabaseRef.set(isOnlineForDatabase); // We'll also add Firestore set here for when we come online. userStatusFirestoreRef.set(isOnlineForFirestore); }); });
Bu değişikliklerle, yerel Cloud Firestore durumun her zaman cihazın online/çevrimdışı durumunu yansıtmasını sağladık. Bu sayede /status/{uid} dokümanını dinleyebilir ve verileri kullanarak kullanıcı arayüzünüzü bağlantı durumunu yansıtacak şekilde değiştirebilirsiniz.
Web
userStatusFirestoreRef.onSnapshot(function(doc) { var isOnline = doc.data().state == 'online'; // ... use isOnline });
Cloud Firestore dünya genelinde güncelleniyor
Uygulamamız, internetteki varlığını kendisine doğru şekilde bildirse de "çevrimdışı" durum yazma işlemimiz yalnızca yerel olduğundan ve bağlantı yeniden kurulduğunda senkronize edilmeyeceğinden bu durum diğer Cloud Firestore uygulamalarında henüz doğru olmayacaktır. Bunu önlemek için Realtime Database'deki status/{uid} yolunu izleyen bir Cloud Functions işlevi kullanacağız. Realtime Database değeri değiştiğinde, tüm kullanıcıların durumlarının doğru olması için değer Cloud Firestore ile senkronize edilir.
Node.js
const functions = require('firebase-functions/v1'); const { initializeApp } = require('firebase-admin/app'); const { getFirestore } = require('firebase-admin/firestore'); initializeApp(); // Since this code will be running in the Cloud Functions environment // we call initialize Firestore without any arguments because it // detects authentication from the environment. const firestore = getFirestore(); // Create a new function which is triggered on changes to /status/{uid} // Note: This is a Realtime Database trigger, *not* Firestore. exports.onUserStatusChanged = functions.database.ref('/status/{uid}').onUpdate( async (change, context) => { // Get the data written to Realtime Database const eventStatus = change.after.val(); // Then use other event data to create a reference to the // corresponding Firestore document. const userStatusFirestoreRef = firestore.doc(`status/${context.params.uid}`); // It is likely that the Realtime Database change that triggered // this event has already been overwritten by a fast change in // online / offline status, so we'll re-read the current data // and compare the timestamps. const statusSnapshot = await change.after.ref.once('value'); const status = statusSnapshot.val(); functions.logger.log(status, eventStatus); // If the current timestamp for this data is newer than // the data that triggered this event, we exit this function. if (status.last_changed > eventStatus.last_changed) { return null; } // Otherwise, we convert the last_changed field to a Date eventStatus.last_changed = new Date(eventStatus.last_changed); // ... and write it to Firestore. return userStatusFirestoreRef.set(eventStatus); });
Bu işlevi dağıttıktan sonra Cloud Firestore ile çalışan eksiksiz bir iletişim durumu sisteminiz olur. Aşağıda, where() sorgusu kullanarak çevrimiçi veya çevrimdışı olan kullanıcıları izlemeyle ilgili bir örnek verilmiştir.
Web
firebase.firestore().collection('status') .where('state', '==', 'online') .onSnapshot(function(snapshot) { snapshot.docChanges().forEach(function(change) { if (change.type === 'added') { var msg = 'User ' + change.doc.id + ' is online.'; console.log(msg); // ... } if (change.type === 'removed') { var msg = 'User ' + change.doc.id + ' is offline.'; console.log(msg); // ... } }); });
Sınırlamalar
Cloud Firestore uygulamanıza varlık eklemek için Realtime Database'i kullanmak ölçeklenebilir ve etkili bir yöntemdir ancak bazı sınırlamaları vardır:
- Sıçrama önleme: Cloud Firestore içinde gerçek zamanlı değişiklikleri dinlerken bu çözümün birden fazla değişikliği tetiklemesi olasıdır. Bu değişiklikler istediğinizden daha fazla etkinlik tetiklerse Cloud Firestore etkinliklerini manuel olarak azaltın.
- Bağlantı: Bu uygulama, Cloud Firestore'ye değil Realtime Database'e olan bağlantıyı ölçer. Her bir veritabanına bağlantı durumu aynı değilse bu çözüm yanlış bir varlık durumu bildirebilir.
- Android: Android'de Realtime Database, 60 saniye boyunca işlem yapılmadığında arka uçla bağlantıyı keser. Etkin olmama, açık dinleyici veya bekleyen işlem olmadığı anlamına gelir. Bağlantıyı açık tutmak için
.info/connecteddışında bir yola değer etkinlik işleyici eklemenizi öneririz. Örneğin her oturumun başındaFirebaseDatabase.getInstance().getReference((new Date()).toString()).keepSynced()yapabilirsiniz. Daha fazla bilgi için Bağlantı Durumunu Algılama başlıklı makaleyi inceleyin.