Bulut Firestore Android Codelab

1. Genel Bakış

Hedefler

Bu kod laboratuvarında, Android'de Cloud Firestore tarafından desteklenen bir restoran tavsiyesi uygulaması oluşturacaksınız. Şunları nasıl yapacağınızı öğreneceksiniz:

  • Bir Android uygulamasından Firestore'a veri okuma ve yazma
  • Firestore verilerindeki değişiklikleri gerçek zamanlı olarak dinleyin
  • Firestore verilerinin güvenliğini sağlamak için Firebase Kimlik Doğrulaması ve güvenlik kurallarını kullanın
  • Karmaşık Firestore sorguları yazın

Önkoşullar

Bu kod laboratuvarına başlamadan önce şunlara sahip olduğunuzdan emin olun:

  • Android Studio Flamingo veya daha yenisi
  • API 19 veya üzeri bir Android emülatörü
  • Node.js sürüm 16 veya üzeri
  • Java sürüm 17 veya üzeri

2. Bir Firebase projesi oluşturun

  1. Google hesabınızla Firebase konsolunda oturum açın.
  2. Firebase konsolunda Proje ekle'yi tıklayın.
  3. Aşağıdaki ekran görüntüsünde gösterildiği gibi, Firebase projeniz için bir ad girin (örneğin, "Friendly Eats") ve Devam'ı tıklayın.

9d2f625aebcab6af.png

  1. Google Analytics'i etkinleştirmeniz istenebilir, bu kod laboratuvarının amaçları açısından seçiminiz önemli değildir.
  2. Yaklaşık bir dakika sonra Firebase projeniz hazır olacaktır. Devam'ı tıklayın.

3. Örnek projeyi kurun

kodu indir

Bu codelab için örnek kodu klonlamak üzere aşağıdaki komutu çalıştırın. Bu, makinenizde friendlyeats-android adlı bir klasör oluşturacaktır:

$ git clone https://github.com/firebase/friendlyeats-android

Makinenizde git yoksa, kodu doğrudan GitHub'dan da indirebilirsiniz.

Firebase yapılandırması ekle

  1. Firebase konsolunda , sol gezinme bölmesinde Projeye Genel Bakış'ı seçin. Platformu seçmek için Android düğmesine tıklayın. Bir paket adı istendiğinde com.google.firebase.example.fireeats kullanın

73d151ed16016421.png

  1. Uygulamayı Kaydet'e tıklayın ve google-services.json dosyasını indirmek için talimatları izleyin ve az önce indirdiğiniz kodun app/ klasörüne taşıyın. Ardından İleri'yi tıklayın.

projeyi içe aktar

Android Studio'yu açın. Dosya > Yeni > Projeyi İçe Aktar'a tıklayın ve friendlyeats-android klasörünü seçin.

4. Firebase Emülatörlerini kurun

Bu kod laboratuvarında, Cloud Firestore ve diğer Firebase hizmetlerini yerel olarak taklit etmek için Firebase Emulator Suite'i kullanacaksınız. Bu, uygulamanızı oluşturmak için güvenli, hızlı ve ücretsiz bir yerel geliştirme ortamı sağlar.

Firebase CLI'yi kurun

Öncelikle Firebase CLI'yi kurmanız gerekecek. macOS veya Linux kullanıyorsanız, aşağıdaki cURL komutunu çalıştırabilirsiniz:

curl -sL https://firebase.tools | bash

Windows kullanıyorsanız, bağımsız bir ikili dosya edinmek veya npm yoluyla yüklemek için kurulum talimatlarını okuyun.

CLI'yi yükledikten sonra, firebase --version çalıştırıldığında 9.0.0 veya daha yüksek bir sürüm bildirilmelidir:

$ firebase --version
9.0.0

Giriş yapmak

CLI'yi Google hesabınıza bağlamak için firebase login çalıştırın. Bu, oturum açma işlemini tamamlamak için yeni bir tarayıcı penceresi açacaktır. Daha önce Firebase projenizi oluştururken kullandığınız hesabı seçtiğinizden emin olun.

friendlyeats-android klasörünün içinden, yerel projenizi Firebase projenize bağlamak için firebase use --add komutunu çalıştırın. Daha önce oluşturduğunuz projeyi seçmek için istemleri izleyin ve bir takma ad seçmeniz istenirse default değerini girin.

5. Uygulamayı çalıştırın

Şimdi Firebase Emulator Suite'i ve FriendlyEats Android uygulamasını ilk kez çalıştırmanın zamanı geldi.

Öykünücüleri çalıştırın

Terminalinizde, friendlyeats-android dizini içinden firebase emulators:start ve Firebase Emulators'ı başlatın. Bunun gibi günlükleri görmelisiniz:

$ firebase emulators:start
i  emulators: Starting emulators: auth, firestore
i  firestore: Firestore Emulator logging to firestore-debug.log
i  ui: Emulator UI logging to ui-debug.log

┌─────────────────────────────────────────────────────────────┐
│ ✔  All emulators ready! It is now safe to connect your app. │
│ i  View Emulator UI at http://localhost:4000                │
└─────────────────────────────────────────────────────────────┘

┌────────────────┬────────────────┬─────────────────────────────────┐
│ Emulator       │ Host:Port      │ View in Emulator UI             │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Authentication │ localhost:9099 │ http://localhost:4000/auth      │
├────────────────┼────────────────┼─────────────────────────────────┤
│ Firestore      │ localhost:8080 │ http://localhost:4000/firestore │
└────────────────┴────────────────┴─────────────────────────────────┘
  Emulator Hub running at localhost:4400
  Other reserved ports: 4500

Issues? Report them at https://github.com/firebase/firebase-tools/issues and attach the *-debug.log files.

Artık makinenizde çalışan eksiksiz bir yerel geliştirme ortamına sahipsiniz! Codelab'in geri kalanı için bu komutu çalışır durumda bıraktığınızdan emin olun, Android uygulamanızın öykünücülere bağlanması gerekir.

Uygulamayı Emülatörlere bağlayın

Android Studio'da util/FirestoreInitializer.kt ve util/AuthInitializer.kt dosyalarını açın. Bu dosyalar, uygulama başlatıldığında Firebase SDK'larını makinenizde çalışan yerel öykünücülere bağlama mantığını içerir.

FirestoreInitializer sınıfının create() yönteminde şu kod parçasını inceleyin:

    // Use emulators only in debug builds
    if (BuildConfig.DEBUG) {
        firestore.useEmulator(FIRESTORE_EMULATOR_HOST, FIRESTORE_EMULATOR_PORT)
    }

Yalnızca uygulamamız debug modunda çalışırken öykünücülere bağlandığımızdan emin olmak için BuildConfig kullanıyoruz. Uygulamayı release modunda derlediğimizde bu koşul yanlış olacaktır.

Firebase SDK'sını yerel Firestore öykünücüsüne bağlamak için useEmulator(host, port) yöntemini kullandığını görebiliriz. Uygulama boyunca FirebaseFirestore bu örneğine erişmek için FirebaseUtil.getFirestore() kullanacağız, böylece debug modunda çalışırken her zaman Firestore öykünücüsüne bağlandığımızdan eminiz.

Uygulamayı çalıştırın

google-services.json dosyasını düzgün bir şekilde eklediyseniz, proje şimdi derlenmelidir. Android Studio'da Build > Rebuild Project'i tıklayın ve kalan hata olmadığından emin olun.

Android Studio'da Uygulamayı Android öykünücünüzde çalıştırın . İlk başta size bir "Giriş yap" ekranı sunulacaktır. Uygulamada oturum açmak için herhangi bir e-posta ve şifre kullanabilirsiniz. Bu oturum açma işlemi, Firebase Kimlik Doğrulama öykünücüsüne bağlanıyor, bu nedenle hiçbir gerçek kimlik bilgisi aktarılmıyor.

Şimdi web tarayıcınızda http://localhost:4000 adresine giderek Emulators kullanıcı arayüzünü açın. Ardından, Kimlik Doğrulama sekmesine tıklayın ve az önce oluşturduğunuz hesabı görmelisiniz:

Firebase Kimlik Doğrulama Emülatörü

Oturum açma işlemini tamamladıktan sonra uygulama ana ekranını görmelisiniz:

de06424023ffb4b9.png

Yakında ana ekranı doldurmak için bazı veriler ekleyeceğiz.

6. Firestore'a veri yazın

Bu bölümde, şu anda boş olan ana ekranı doldurabilmemiz için Firestore'a bazı veriler yazacağız.

Uygulamamızdaki ana model nesnesi bir restorandır (bkz. model/Restaurant.kt ). Firestore verileri belgelere, koleksiyonlara ve alt koleksiyonlara bölünmüştür. Her restoranı "restaurants" adı verilen üst düzey bir koleksiyonda bir belge olarak saklayacağız. Firestore veri modeli hakkında daha fazla bilgi edinmek için belgelerdeki belgeler ve koleksiyonlar hakkında okuyun.

Tanıtım amacıyla, taşma menüsünde "Rastgele Öğeler Ekle" düğmesini tıkladığımızda, uygulamaya on rastgele restoran oluşturma işlevi ekleyeceğiz. MainFragment.kt dosyasını açın ve onAddItemsClicked() yöntemindeki içeriği şununla değiştirin:

    private fun onAddItemsClicked() {
        val restaurantsRef = firestore.collection("restaurants")
        for (i in 0..9) {
            // Create random restaurant / ratings
            val randomRestaurant = RestaurantUtil.getRandom(requireContext())

            // Add restaurant
            restaurantsRef.add(randomRestaurant)
        }
    }

Yukarıdaki kod hakkında dikkat edilmesi gereken birkaç önemli nokta vardır:

  • "restaurants" koleksiyonuna referans alarak başladık. Koleksiyonlar, belgeler eklendiğinde dolaylı olarak oluşturulur, bu nedenle verileri yazmadan önce koleksiyon oluşturmaya gerek yoktur.
  • Belgeler, her Restoran belgesini oluşturmak için kullandığımız Kotlin veri sınıfları kullanılarak oluşturulabilir.
  • add() yöntemi, otomatik oluşturulmuş kimliği olan bir koleksiyona bir belge ekler, bu nedenle her Restoran için benzersiz bir kimlik belirtmemiz gerekmez.

Şimdi uygulamayı tekrar çalıştırın ve az önce yazdığınız kodu çağırmak için taşma menüsünde (sağ üst köşede) "Rastgele Öğeler Ekle" düğmesini tıklayın:

95691e9b71ba55e3.png

Şimdi web tarayıcınızda http://localhost:4000 adresine giderek Emulators kullanıcı arayüzünü açın. Ardından Firestore sekmesine tıklayın ve az önce eklediğiniz verileri görmelisiniz:

Firebase Kimlik Doğrulama Emülatörü

Bu veriler makineniz için %100 yereldir. Aslında, gerçek projeniz henüz bir Firestore veritabanı bile içermiyor! Bu, sonuç olmadan bu verileri değiştirmeyi ve silmeyi denemenin güvenli olduğu anlamına gelir.

Tebrikler, Firestore'a veri yazdınız! Bir sonraki adımda, bu verileri uygulamada nasıl görüntüleyeceğimizi öğreneceğiz.

7. Firestore'dan verileri görüntüleyin

Bu adımda, Firestore'dan nasıl veri alınacağını ve uygulamamızda nasıl gösterileceğini öğreneceğiz. Firestore'dan veri okumanın ilk adımı, bir Query oluşturmaktır. MainFragment.kt dosyasını açın ve aşağıdaki kodu onViewCreated() yönteminin başına ekleyin:

        // Firestore
        firestore = Firebase.firestore

        // Get the 50 highest rated restaurants
        query = firestore.collection("restaurants")
            .orderBy("avgRating", Query.Direction.DESCENDING)
            .limit(LIMIT.toLong())

Şimdi sorguyu dinlemek istiyoruz, böylece eşleşen tüm belgeleri alabilir ve gelecekteki güncellemelerden gerçek zamanlı olarak haberdar olabiliriz. Nihai hedefimiz bu verileri bir RecyclerView bağlamak olduğundan, verileri dinlemek için bir RecyclerView.Adapter sınıfı oluşturmamız gerekiyor.

Halihazırda kısmen uygulanmış olan FirestoreAdapter sınıfını açın. Öncelikle bağdaştırıcının EventListener uygulamasını sağlayalım ve bir Firestore sorgusuna ilişkin güncellemeleri alabilmesi için onEvent işlevini tanımlayalım:

abstract class FirestoreAdapter<VH : RecyclerView.ViewHolder>(private var query: Query?) :
        RecyclerView.Adapter<VH>(),
        EventListener<QuerySnapshot> { // Add this implements
    
    // ...

    // Add this method
    override fun onEvent(documentSnapshots: QuerySnapshot?, e: FirebaseFirestoreException?) {
        
        // Handle errors
        if (e != null) {
            Log.w(TAG, "onEvent:error", e)
            return
        }

        // Dispatch the event
        if (documentSnapshots != null) {
            for (change in documentSnapshots.documentChanges) {
                // snapshot of the changed document
                when (change.type) {
                    DocumentChange.Type.ADDED -> {
                        // TODO: handle document added
                    }
                    DocumentChange.Type.MODIFIED -> {
                        // TODO: handle document changed
                    }
                    DocumentChange.Type.REMOVED -> {
                        // TODO: handle document removed
                    }
                }
            }
        }

        onDataChanged()
    }
    
    // ...
}

İlk yüklemede, dinleyici her yeni belge için bir ADDED olayı alacaktır. Sorgunun sonuç kümesi zamanla değiştikçe, dinleyici değişiklikleri içeren daha fazla olay alacaktır. Şimdi dinleyiciyi uygulamayı bitirelim. Önce üç yeni yöntem ekleyin: onDocumentAdded , onDocumentModified ve onDocumentRemoved :

    private fun onDocumentAdded(change: DocumentChange) {
        snapshots.add(change.newIndex, change.document)
        notifyItemInserted(change.newIndex)
    }

    private fun onDocumentModified(change: DocumentChange) {
        if (change.oldIndex == change.newIndex) {
            // Item changed but remained in same position
            snapshots[change.oldIndex] = change.document
            notifyItemChanged(change.oldIndex)
        } else {
            // Item changed and changed position
            snapshots.removeAt(change.oldIndex)
            snapshots.add(change.newIndex, change.document)
            notifyItemMoved(change.oldIndex, change.newIndex)
        }
    }

    private fun onDocumentRemoved(change: DocumentChange) {
        snapshots.removeAt(change.oldIndex)
        notifyItemRemoved(change.oldIndex)
    }

Ardından onEvent şu yeni yöntemleri çağırın:

    override fun onEvent(documentSnapshots: QuerySnapshot?, e: FirebaseFirestoreException?) {

        // Handle errors
        if (e != null) {
            Log.w(TAG, "onEvent:error", e)
            return
        }

        // Dispatch the event
        if (documentSnapshots != null) {
            for (change in documentSnapshots.documentChanges) {
                // snapshot of the changed document
                when (change.type) {
                    DocumentChange.Type.ADDED -> {
                        onDocumentAdded(change) // Add this line
                    }
                    DocumentChange.Type.MODIFIED -> {
                        onDocumentModified(change) // Add this line
                    }
                    DocumentChange.Type.REMOVED -> {
                        onDocumentRemoved(change) // Add this line
                    }
                }
            }
        }

        onDataChanged()
    }

Son olarak, dinleyiciyi eklemek için startListening() yöntemini uygulayın:

    fun startListening() {
        if (registration == null) {
            registration = query.addSnapshotListener(this)
        }
    }

Artık uygulama, Firestore'dan veri okumak için tamamen yapılandırılmıştır. Uygulamayı tekrar çalıştırın ve bir önceki adımda eklediğiniz restoranları görmelisiniz:

9e45f40faefce5d0.png

Şimdi tarayıcınızda Emulator kullanıcı arayüzüne geri dönün ve restoran adlarından birini düzenleyin. Uygulamada neredeyse anında değiştiğini görmelisiniz!

8. Verileri sıralayın ve filtreleyin

Uygulama şu anda koleksiyonun tamamında en çok puan alan restoranları gösteriyor, ancak gerçek bir restoran uygulamasında kullanıcı verileri sıralamak ve filtrelemek isteyecektir. Örneğin, uygulama "Philadelphia'daki en iyi deniz ürünleri restoranlarını" veya "En ucuz pizzayı" gösterebilmelidir.

Uygulamanın üst kısmındaki beyaz çubuğa tıklandığında bir filtreler iletişim kutusu açılır. Bu bölümde, bu iletişim kutusunun çalışması için Firestore sorgularını kullanacağız:

67898572a35672a5.png

MainFragment.kt onFilter() yöntemini düzenleyelim. Bu yöntem, filtreler iletişim kutusunun çıktısını yakalamak için oluşturduğumuz bir yardımcı nesne olan Filters nesnesini kabul eder. Filtrelerden bir sorgu oluşturmak için bu yöntemi değiştireceğiz:

    override fun onFilter(filters: Filters) {
        // Construct query basic query
        var query: Query = firestore.collection("restaurants")

        // Category (equality filter)
        if (filters.hasCategory()) {
            query = query.whereEqualTo(Restaurant.FIELD_CATEGORY, filters.category)
        }

        // City (equality filter)
        if (filters.hasCity()) {
            query = query.whereEqualTo(Restaurant.FIELD_CITY, filters.city)
        }

        // Price (equality filter)
        if (filters.hasPrice()) {
            query = query.whereEqualTo(Restaurant.FIELD_PRICE, filters.price)
        }

        // Sort by (orderBy with direction)
        if (filters.hasSortBy()) {
            query = query.orderBy(filters.sortBy.toString(), filters.sortDirection)
        }

        // Limit items
        query = query.limit(LIMIT.toLong())

        // Update the query
        adapter.setQuery(query)

        // Set header
        binding.textCurrentSearch.text = HtmlCompat.fromHtml(
            filters.getSearchDescription(requireContext()),
            HtmlCompat.FROM_HTML_MODE_LEGACY
        )
        binding.textCurrentSortBy.text = filters.getOrderDescription(requireContext())

        // Save filters
        viewModel.filters = filters
    }

Yukarıdaki parçada, verilen filtrelerle eşleşmesi için where ve orderBy yan tümcelerini ekleyerek bir Query nesnesi oluşturuyoruz.

Uygulamayı tekrar çalıştırın ve en popüler düşük fiyatlı restoranları göstermek için aşağıdaki filtreyi seçin:

7a67a8a400c80c50.png

Artık yalnızca düşük fiyatlı seçenekler içeren filtrelenmiş bir restoran listesi görmelisiniz:

a670188398c3c59.png

Buraya kadar geldiyseniz, artık Firestore'da tam işlevli bir restoran tavsiyesi görüntüleme uygulaması oluşturdunuz! Artık restoranları gerçek zamanlı olarak sıralayabilir ve filtreleyebilirsiniz. Sonraki birkaç bölümde restoranlara incelemeler ekleyeceğiz ve uygulamaya güvenlik kuralları ekleyeceğiz.

9. Verileri alt koleksiyonlarda düzenleyin

Bu bölümde, kullanıcıların en sevdikleri (veya en az sevdikleri) restoranları gözden geçirebilmeleri için uygulamaya puanlar ekleyeceğiz.

Koleksiyonlar ve alt koleksiyonlar

Şimdiye kadar tüm restoran verilerini "restoranlar" adı verilen üst düzey bir koleksiyonda sakladık. Bir kullanıcı bir restoranı değerlendirdiğinde, restoranlara yeni bir Rating nesnesi eklemek istiyoruz. Bu görev için bir alt koleksiyon kullanacağız. Bir alt koleksiyonu bir belgeye iliştirilmiş bir koleksiyon olarak düşünebilirsiniz. Bu nedenle, her restoran belgesinin, derecelendirme belgeleriyle dolu bir derecelendirme alt koleksiyonu olacaktır. Alt koleksiyonlar, belgelerimizi şişirmeden veya karmaşık sorgular gerektirmeden verilerin düzenlenmesine yardımcı olur.

Bir alt koleksiyona erişmek için üst belgede .collection() öğesini arayın:

val subRef = firestore.collection("restaurants")
        .document("abc123")
        .collection("ratings")

Bir üst düzey koleksiyonda olduğu gibi bir alt koleksiyona erişebilir ve sorgulayabilirsiniz, boyut sınırlaması veya performans değişikliği yoktur. Firestore veri modeli hakkında daha fazla bilgiyi buradan edinebilirsiniz.

Bir işlemde veri yazma

Uygun alt koleksiyona Rating eklemek yalnızca .add() öğesinin çağrılmasını gerektirir, ancak yeni verileri yansıtmak için Restaurant nesnesinin ortalama puanını ve puan sayısını da güncellememiz gerekir. Bu iki değişikliği yapmak için ayrı işlemler kullanırsak, verilerin eskimesine veya yanlış olmasına neden olabilecek bir dizi yarış durumu vardır.

Puanların düzgün bir şekilde eklendiğinden emin olmak için, bir restorana puan eklemek için bir işlem kullanacağız. Bu işlem birkaç eylem gerçekleştirecek:

  • Restoranın mevcut puanını okuyun ve yenisini hesaplayın
  • Derecelendirmeyi alt koleksiyona ekle
  • Restoranın ortalama puanını ve puan sayısını güncelleyin

RestaurantDetailFragment.kt dosyasını açın ve addRating işlevini uygulayın:

    private fun addRating(restaurantRef: DocumentReference, rating: Rating): Task<Void> {
        // Create reference for new rating, for use inside the transaction
        val ratingRef = restaurantRef.collection("ratings").document()

        // In a transaction, add the new rating and update the aggregate totals
        return firestore.runTransaction { transaction ->
            val restaurant = transaction.get(restaurantRef).toObject<Restaurant>()
                ?: throw Exception("Restaurant not found at ${restaurantRef.path}")

            // Compute new number of ratings
            val newNumRatings = restaurant.numRatings + 1

            // Compute new average rating
            val oldRatingTotal = restaurant.avgRating * restaurant.numRatings
            val newAvgRating = (oldRatingTotal + rating.rating) / newNumRatings

            // Set new restaurant info
            restaurant.numRatings = newNumRatings
            restaurant.avgRating = newAvgRating

            // Commit to Firestore
            transaction.set(restaurantRef, restaurant)
            transaction.set(ratingRef, rating)

            null
        }
    }

addRating() işlevi, tüm işlemi temsil eden bir Task döndürür. onRating() işlevinde, işlemin sonucuna yanıt vermek için göreve dinleyiciler eklenir.

Şimdi uygulamayı tekrar çalıştırın ve restoran detay ekranını getirmesi gereken restoranlardan birine tıklayın. İnceleme eklemeye başlamak için + düğmesini tıklayın. Bir dizi yıldız seçip biraz metin girerek bir inceleme ekleyin.

78fa16cdf8ef435a.png

Gönder'e basmak işlemi başlatır. İşlem tamamlandığında, yorumunuzun aşağıda gösterildiğini ve restoranın yorum sayısında bir güncelleme göreceksiniz:

f9e670f40bd615b0.png

Tebrikler! Artık Cloud Firestore üzerinde oluşturulmuş bir sosyal, yerel, mobil restoran inceleme uygulamanız var. Bu aralar çok popüler olduklarını duydum.

10. Verilerinizi güvenceye alın

Şimdiye kadar bu uygulamanın güvenliğini dikkate almadık. Kullanıcıların yalnızca kendi doğru verilerini okuyup yazabildiklerini nasıl bilebiliriz? Firestore veritabanlarının güvenliği, Güvenlik Kuralları adlı bir yapılandırma dosyasıyla sağlanır.

firestore.rules dosyasını açın, aşağıdakileri görmelisiniz:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      //
      // WARNING: These rules are insecure! We will replace them with
      // more secure rules later in the codelab
      //
      allow read, write: if request.auth != null;
    }
  }
}

İstenmeyen veri erişimlerini veya değişikliklerini önlemek için bu kuralları değiştirelim, firestore.rules dosyasını açalım ve içeriği aşağıdaki ile değiştirelim:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Determine if the value of the field "key" is the same
    // before and after the request.
    function isUnchanged(key) {
      return (key in resource.data)
        && (key in request.resource.data)
        && (resource.data[key] == request.resource.data[key]);
    }

    // Restaurants
    match /restaurants/{restaurantId} {
      // Any signed-in user can read
      allow read: if request.auth != null;

      // Any signed-in user can create
      // WARNING: this rule is for demo purposes only!
      allow create: if request.auth != null;

      // Updates are allowed if no fields are added and name is unchanged
      allow update: if request.auth != null
                    && (request.resource.data.keys() == resource.data.keys())
                    && isUnchanged("name");

      // Deletes are not allowed.
      // Note: this is the default, there is no need to explicitly state this.
      allow delete: if false;

      // Ratings
      match /ratings/{ratingId} {
        // Any signed-in user can read
        allow read: if request.auth != null;

        // Any signed-in user can create if their uid matches the document
        allow create: if request.auth != null
                      && request.resource.data.userId == request.auth.uid;

        // Deletes and updates are not allowed (default)
        allow update, delete: if false;
      }
    }
  }
}

Bu kurallar, istemcilerin yalnızca güvenli değişiklikler yapmasını sağlamak için erişimi kısıtlar. Örneğin, bir restoran belgesindeki güncellemeler yalnızca derecelendirmeleri değiştirebilir, adı veya diğer değişmez verileri değiştiremez. Derecelendirmeler, yalnızca kullanıcı kimliği oturum açmış kullanıcıyla eşleşirse oluşturulabilir, bu da kimlik sahtekarlığını önler.

Güvenlik Kuralları hakkında daha fazla bilgi edinmek için belgeleri ziyaret edin.

11. Sonuç

Artık Firestore üzerinde tam özellikli bir uygulama oluşturdunuz. Aşağıdakiler dahil olmak üzere en önemli Firestore özelliklerini öğrendiniz:

  • Belgeler ve koleksiyonlar
  • Veri okuma ve yazma
  • Sorgularla sıralama ve filtreleme
  • Alt koleksiyonlar
  • İşlemler

Daha fazla bilgi edin

Firestore hakkında bilgi edinmeye devam etmek için, başlamak için bazı iyi yerler şunlardır:

Bu kod laboratuvarındaki restoran uygulaması, "Friendly Eats" örnek uygulamasını temel almıştır. Söz konusu uygulamanın kaynak koduna buradan göz atabilirsiniz.

İsteğe bağlı: Üretime dağıtın

Şimdiye kadar bu uygulama yalnızca Firebase Emulator Suite'i kullandı. Bu uygulamayı gerçek bir Firebase projesine nasıl dağıtacağınızı öğrenmek istiyorsanız bir sonraki adıma geçin.

12. (İsteğe bağlı) Uygulamanızı dağıtın

Şimdiye kadar bu uygulama tamamen yereldi, tüm veriler Firebase Emulator Suite'te bulunuyor. Bu bölümde, Firebase projenizi, bu uygulamanın üretimde çalışması için nasıl yapılandıracağınızı öğreneceksiniz.

Firebase Kimlik Doğrulaması

Firebase konsolunda Kimlik Doğrulama bölümüne gidin ve Başlayın'ı tıklayın. Oturum açma yöntemi sekmesine gidin ve Yerel sağlayıcılar arasından E-posta/Parola seçeneğini belirleyin.

E-posta/Parola oturum açma yöntemini etkinleştirin ve Kaydet'i tıklayın.

oturum açma sağlayıcıları.png

yangın deposu

Veritabanı yarat

Konsolun Firestore Veritabanı bölümüne gidin ve Veritabanı Oluştur'a tıklayın:

  1. Üretim Modunda başlamayı seçen Güvenlik Kuralları sorulduğunda, bu kuralları yakında güncelleyeceğiz.
  2. Uygulamanız için kullanmak istediğiniz veritabanı konumunu seçin. Bir veritabanı konumu seçmenin kalıcı bir karar olduğunu ve bunu değiştirmek için yeni bir proje oluşturmanız gerekeceğini unutmayın. Bir proje yeri seçme hakkında daha fazla bilgi için belgelere bakın.

Kuralları Dağıt

Daha önce yazdığınız Güvenlik Kurallarını dağıtmak için codelab dizininde aşağıdaki komutu çalıştırın:

$ firebase deploy --only firestore:rules

Bu, konsoldaki Kurallar sekmesine giderek onaylayabileceğiniz firestore.rules içeriğini projenize dağıtacaktır.

Dizinleri Dağıtın

FriendlyEats uygulaması, bir dizi özel bileşik dizin gerektiren karmaşık sıralama ve filtrelemeye sahiptir. Bunlar, Firebase konsolunda elle oluşturulabilir ancak tanımlarını firestore.indexes.json dosyasına yazmak ve Firebase CLI kullanarak dağıtmak daha kolaydır.

firestore.indexes.json dosyasını açarsanız, gerekli dizinlerin zaten sağlanmış olduğunu göreceksiniz:

{
  "indexes": [
    {
      "collectionId": "restaurants",
      "queryScope": "COLLECTION",
      "fields": [
        { "fieldPath": "city", "mode": "ASCENDING" },
        { "fieldPath": "avgRating", "mode": "DESCENDING" }
      ]
    },
    {
      "collectionId": "restaurants",
      "queryScope": "COLLECTION",
      "fields": [
        { "fieldPath": "category", "mode": "ASCENDING" },
        { "fieldPath": "avgRating", "mode": "DESCENDING" }
      ]
    },
    {
      "collectionId": "restaurants",
      "queryScope": "COLLECTION",
      "fields": [
        { "fieldPath": "price", "mode": "ASCENDING" },
        { "fieldPath": "avgRating", "mode": "DESCENDING" }
      ]
    },
    {
      "collectionId": "restaurants",
      "queryScope": "COLLECTION",
      "fields": [
        { "fieldPath": "city", "mode": "ASCENDING" },
        { "fieldPath": "numRatings", "mode": "DESCENDING" }
      ]
    },
    {
      "collectionId": "restaurants",
      "queryScope": "COLLECTION",
      "fields": [
        { "fieldPath": "category", "mode": "ASCENDING" },
        { "fieldPath": "numRatings", "mode": "DESCENDING" }
      ]
    },
    {
      "collectionId": "restaurants",
      "queryScope": "COLLECTION",
      "fields": [
        { "fieldPath": "price", "mode": "ASCENDING" },
        { "fieldPath": "numRatings", "mode": "DESCENDING" }
      ]
    },
    {
      "collectionId": "restaurants",
      "queryScope": "COLLECTION",
      "fields": [
        { "fieldPath": "city", "mode": "ASCENDING" },
        { "fieldPath": "price", "mode": "ASCENDING" }
      ]
    },
    {
      "collectionId": "restaurants",
      "fields": [
        { "fieldPath": "category", "mode": "ASCENDING" },
        { "fieldPath": "price", "mode": "ASCENDING" }
      ]
    }
  ],
  "fieldOverrides": []
}

Bu dizinleri dağıtmak için aşağıdaki komutu çalıştırın:

$ firebase deploy --only firestore:indexes

Dizin oluşturmanın anlık olmadığına dikkat edin, ilerlemeyi Firebase konsolunda izleyebilirsiniz.

Uygulamayı yapılandırın

util/FirestoreInitializer.kt ve util/AuthInitializer.kt dosyalarında, Firebase SDK'sını hata ayıklama modunda öykünücülere bağlanacak şekilde yapılandırdık:

    override fun create(context: Context): FirebaseFirestore {
        val firestore = Firebase.firestore
        // Use emulators only in debug builds
        if (BuildConfig.DEBUG) {
            firestore.useEmulator(FIRESTORE_EMULATOR_HOST, FIRESTORE_EMULATOR_PORT)
        }
        return firestore
    }

Uygulamanızı gerçek Firebase projenizle test etmek isterseniz, aşağıdakilerden birini yapabilirsiniz:

  1. Uygulamayı yayın modunda oluşturun ve bir cihazda çalıştırın.
  2. BuildConfig.DEBUG geçici olarak false ile değiştirin ve uygulamayı yeniden çalıştırın.

Üretime düzgün bir şekilde bağlanmak için uygulamada Oturumu Kapatmanız ve tekrar oturum açmanız gerekebileceğini unutmayın.