Cloud Firestore Android Codelab

1. Genel Bakış

Gol sayısı

Bu codelab'de, Cloud Firestore tarafından desteklenen Android'de bir restoran öneri uygulaması oluşturacaksınız. Aşağıdakileri nasıl yapacağınızı öğreneceksiniz:

  • Android uygulamasından Firestore'a veri okuma ve yazma
  • Firestore verilerindeki değişiklikleri anlık olarak dinleme
  • Firestore verilerinin güvenliğini sağlamak için Firebase Authentication ve güvenlik kurallarını kullanma
  • Karmaşık Firestore sorguları yazma

Ön koşullar

Bu kod laboratuvarını başlatmadan önce şunların bulunduğundan emin olun:

  • Android Studio Flamingo veya daha yeni bir sürüm
  • API 19 veya sonraki sürümleri çalıştıran bir Android emülatörü
  • Node.js 16 veya sonraki sürümler
  • Java 17 veya sonraki sürümler

2. Firebase projesi oluşturma

  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, "Arkadaşça Yemek") ve Devam'ı tıklayın.

9d2f625aebcab6af.png

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

3. Örnek projeyi oluşturma

Kodu indirme

Bu kod alanının örnek kodunu klonlamak için aşağıdaki komutu çalıştırın. Bu işlem, makinenizde friendlyeats-android adlı bir klasör oluşturur:

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

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

Firebase yapılandırması ekleme

  1. Firebase konsolunda, sol gezinme menüsünden Projeye Genel Bakış'ı seçin. Platformu seçmek için Android düğmesini tıklayın. Paket adı istendiğinde com.google.firebase.example.fireeats

73d151ed16016421.png

  1. Uygulamayı Kaydet'i tıklayın ve talimatları uygulayarak google-services.json dosyasını indirin ve yeni indirdiğiniz kodun app/ klasörüne taşıyın. Ardından Sonraki'yi tıklayın.

Projeyi içe aktarma

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

4. Firebase Emulators'ı ayarlama

Bu codelab'de, 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 yükleme

Öncelikle Firebase CLI'yi yüklemeniz gerekir. 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 dosyayı almak veya npm üzerinden yüklemek için yükleme talimatlarını okuyun.

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

$ firebase --version
9.0.0

Giriş

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

Yerel projenizi Firebase projenize bağlamak için friendlyeats-android klasöründen firebase use --add'ı çalıştırın. Daha önce oluşturduğunuz projeyi seçmek için talimatları uygulayın ve takma ad seçmeniz istenirse default yazın.

5. Uygulamayı çalıştırma

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

Emülatörleri çalıştırma

Firebase Emulators'ı başlatmak için terminalinizde friendlyeats-android dizininden firebase emulators:start komutunu çalıştırın. Aşağıdaki gibi günlükler görürsünüz:

$ 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. Bu komutu, kodlab'ın geri kalanı için çalıştırmaya devam edin. Android uygulamanızın emülatörlere bağlanması gerekir.

Uygulamayı emülatörlere bağlama

Android Studio'da util/FirestoreInitializer.kt ve util/AuthInitializer.kt dosyalarını açın. Bu dosyalar, uygulama başlatıldıktan sonra Firebase SDK'larını makinenizde çalışan yerel emülatörlere bağlayan mantığı 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 emülatörlere bağlandığımızdan emin olmak için BuildConfig kullanıyoruz. Uygulamayı release modunda derlediğimizde bu koşul yanlış olur.

Firebase SDK'sını yerel Firestore emülatörüne bağlamak için useEmulator(host, port) yönteminin kullanıldığını görüyoruz. Uygulama genelinde, FirebaseFirestore örneğine erişmek için FirebaseUtil.getFirestore() kullanacağız. Böylece, debug modunda çalışırken her zaman Firestore emülatörüne bağlanacağımızdan emin oluruz.

Uygulamayı çalıştırma

google-services.json dosyasını doğru şekilde eklediyseniz proje derlenir. Android Studio'da Derle > Projeyi Yeniden Derle'yi tıklayın ve kalan hata olmadığından emin olun.

Android Studio'da uygulamayı Android emülatörünüzde Çalıştırın. İlk olarak "Oturum aç" ekranı gösterilir. Uygulamada oturum açmak için herhangi bir e-posta ve şifre kullanabilirsiniz. Bu oturum açma işlemi Firebase Authentication emülatörüne bağlandığından gerçek kimlik bilgileri aktarılmaz.

Ardından, web tarayıcınızda http://localhost:4000 adresine giderek Emülatör kullanıcı arayüzünü açın. Ardından Kimlik Doğrulaması sekmesini tıklayın. Yeni oluşturduğunuz hesabı görürsünüz:

Firebase Auth Emulator

Oturum açma işlemini tamamladığınızda uygulamanın ana ekranını görürsünüz:

de06424023ffb4b9.png

Yakında ana ekranı dolduracak bazı veriler ekleyeceğiz.

6. Firestore'a veri yazma

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

Uygulamamızdaki ana model nesnesi bir restorandır (model/Restaurant.kt bölümüne bakın). Firestore verileri dokümanlara, koleksiyonlara ve alt koleksiyonlara ayrılır. Her restoranı "restaurants" adlı üst düzey bir koleksiyonda doküman olarak depolarız. Firestore veri modeli hakkında daha fazla bilgi edinmek için dokümanlar bölümündeki dokümanlar ve koleksiyonlar hakkındaki makaleyi okuyun.

Demo amacıyla, uygulamaya, taşma menüsündeki "Rastgele Öğe Ekle" düğmesini tıkladığımızda on rastgele restoran oluşturacak bir işlev ekleyeceğiz. MainFragment.kt dosyasını açın ve onAddItemsClicked() yöntemindeki içeriği şu şekilde 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 kodla ilgili dikkat edilmesi gereken birkaç önemli nokta vardır:

  • "restaurants" koleksiyonuna referans alarak başladık. Koleksiyonlar, doküman eklendiğinde dolaylı olarak oluşturulur. Bu nedenle, verileri yazmadan önce koleksiyonu oluşturmanız gerekmez.
  • Her restoran dokümanı oluşturmak için kullandığımız Kotlin veri sınıfları kullanılarak dokümanlar oluşturulabilir.
  • add() yöntemi, otomatik olarak oluşturulan bir kimliğe sahip bir koleksiyona doküman ekler. Bu nedenle, her restoran için benzersiz bir kimlik belirtmemiz gerekmedi.

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

95691e9b71ba55e3.png

Ardından, web tarayıcınızda http://localhost:4000 adresine giderek Emülatör kullanıcı arayüzünü açın. Ardından Firestore sekmesini tıklayın. Yeni eklediğiniz verileri görürsünüz:

Firebase Auth Emulator

Bu veriler makinenizde% 100 yereldir. Gerçek projenizde henüz bir Firestore veritabanı bile yok. Bu, bu verileri değiştirmenin ve silmenin herhangi bir olumsuz etkisi olmayacağı anlamına gelir.

Tebrikler, Firestore'a veri yazdınız. Sonraki adımda bu verileri uygulamada nasıl göstereceğinizi öğreneceksiniz.

7. Firestore'daki verileri görüntüleme

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

        // Firestore
        firestore = Firebase.firestore

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

Eşleşen tüm dokümanları almak ve gelecekteki güncellemelerden anında haberdar olmak için sorguyu dinlemek istiyoruz. Nihai hedefimiz bu verileri bir RecyclerView'ye bağlamak olduğundan, verileri dinlemek için bir RecyclerView.Adapter sınıfı oluşturmamız gerekir.

Kısmen uygulanmış olan FirestoreAdapter sınıfını açın. Öncelikle, bağdaştırıcının EventListener işlevini uygulayabilmesini ve onEvent işlevini bir Firestore sorgusunda güncelleme alabilmesini sağlayalı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 doküman için bir ADDED etkinliği alır. Sorgunun sonuç kümesi zaman içinde değiştikçe dinleyici, değişiklikleri içeren daha fazla etkinlik alır. Şimdi dinleyiciyi uygulamayı tamamlayalım. Öncelikle üç 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 adresinden aşağıdaki 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 okuyacak şekilde tamamen yapılandırılmıştır. Uygulamayı tekrar çalıştırın. Bir önceki adımda eklediğiniz restoranları görürsünüz:

9e45f40faefce5d0.png

Ardından, tarayıcınızdaki Emülatör kullanıcı arayüzüne geri dönün ve restoran adlarından birini düzenleyin. Bu değişikliği uygulamada neredeyse anında görebilirsiniz.

8. Verileri sıralama ve filtreleme

Uygulama şu anda koleksiyondaki en yüksek puan alan restoranları gösteriyor ancak gerçek bir restoran uygulamasında kullanıcı verilerini sıralamak ve filtrelemek ister. Örneğin, uygulama "Philadelphia'daki en iyi deniz ürünleri restoranları" veya "En ucuz pizza" gibi arama terimlerini gösterebilmelidir.

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

67898572a35672a5.png

MainFragment.kt öğesinin onFilter() yöntemini düzenleyelim. Bu yöntem, filtreler iletişim kutusunun çıktısını yakalamak için oluşturduğumuz yardımcı bir nesne olan Filters nesnesini kabul eder. Bu yöntemi, filtrelerden sorgu oluşturacak şekilde 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 snippet'te, belirtilen filtrelerle eşleşecek şekilde where ve orderBy yan tümceleri 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öreceksiniz:

a670188398c3c59.png

Bu makalenin sonuna kadar geldiyseniz Firestore'da tamamen işlevsel bir restoran önerisi görüntüleme uygulaması oluşturdunuz demektir. Artık restoranları anlık olarak sıralayabilir ve filtreleyebilirsiniz. Sonraki birkaç bölümde restoranlara yorumlar ve uygulamaya güvenlik kuralları ekleyeceğiz.

9. Verileri alt koleksiyonlarda düzenleme

Bu bölümde, kullanıcıların en sevdikleri (veya en sevmedikleri) restoranları yorumlayabilmesi için uygulamaya puanlar ekleyeceğiz.

Koleksiyonlar ve alt koleksiyonlar

Şimdiye kadar tüm restoran verilerini "restaurants" adlı üst düzey bir koleksiyonda depoladık. Kullanıcı bir restoranı değerlendirdiğinde restoranlara yeni bir Rating nesnesi eklemek istiyoruz. Bu görev için bir alt koleksiyon kullanacağız. Alt koleksiyonları, bir dokümana eklenmiş koleksiyonlar olarak düşünebilirsiniz. Bu nedenle, her restoran belgesinde derecelendirme dokümanlarıyla dolu bir derecelendirme alt koleksiyonu bulunur. Alt koleksiyonlar, belgelerimizi şişirmeden veya karmaşık sorgular gerektirmeden verileri düzenlemenize yardımcı olur.

Bir alt koleksiyona erişmek için üst dokümanda .collection() işlevini çağırın:

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

Alt koleksiyonlara, üst düzey koleksiyonlara erişip sorgu oluşturabilirsiniz. Boyut sınırlaması veya performans değişikliği yoktur. Firestore veri modeli hakkında daha fazla bilgiyi burada bulabilirsiniz.

İşlemde veri yazma

Uygun alt koleksiyona Rating eklemek için yalnızca .add() çağrısı yapılması gerekir ancak Restaurant nesnesinin ortalama derecelendirmesini ve derecelendirme sayısını yeni verileri yansıtacak şekilde güncellememiz de gerekir. Bu iki değişikliği yapmak için ayrı işlemler kullanırsak eski veya yanlış verilerle sonuçlanabilecek bir dizi yarış koşulu vardır.

Puanların doğru şekilde eklenmesini sağlamak için bir restorana puan eklemek üzere bir işlem kullanırız. Bu işlem birkaç işlem gerçekleştirir:

  • Restoranın mevcut puanını okuyup yeni puanı hesaplayın
  • Puanı alt koleksiyona ekleme
  • Restoranın ortalama puanını ve puan sayısını güncelleme

RestaurantDetailFragment.kt dosyasını açıp 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, işlemin tamamını temsil eden bir Task döndürür. onRating() işlevinde, işlem sonucuna yanıt vermek için göreve dinleyiciler eklenir.

Şimdi uygulamayı tekrar Çalıştırın ve restoranlardan birini tıklayın. Restoran ayrıntıları ekranı açılır. Yorum eklemeye başlamak için + düğmesini tıklayın. Yıldız sayısını seçip metin girerek yorum ekleyin.

78fa16cdf8ef435a.png

Gönder'e basarak işlemi başlatabilirsiniz. İşlem tamamlandığında, yorumunuzun aşağıda gösterildiğini ve restoranın yorum sayısında güncelleme yapıldığını görürsünüz:

f9e670f40bd615b0.png

Tebrikler! Artık Cloud Firestore'da oluşturulmuş, sosyal, yerel, mobil bir restoran yorumu uygulamasına sahipsiniz. Bu tür ürünlerin şu anda çok popüler olduğunu duyuyoruz.

10. Verilerinizin güvenliğini sağlama

Şu ana kadar bu uygulamanın güvenliğini değerlendirmedik. Kullanıcıların yalnızca kendi verilerini doğru şekilde okuyup yazabileceğini nasıl bilebiliriz? Firestore veritabanları, Güvenlik Kuralları adlı bir yapılandırma dosyasıyla korunur.

firestore.rules dosyasını açın ve içeriği aşağıdakiyle değiştirin:

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, restoran dokümanında yapılan güncellemeler yalnızca derecelendirmeleri değiştirebilir, adı veya diğer değiştirilemez verileri değiştiremez. Derecelendirmeler yalnızca kullanıcı kimliği, oturum açmış kullanıcıyla eşleşirse oluşturulabilir. Bu, kimliğe bürünmeyi önler.

Güvenlik Kuralları hakkında daha fazla bilgi edinmek için dokümanları inceleyin.

11. Sonuç

Artık Firestore'u temel alan tam özellikli bir uygulama oluşturdunuz. Aşağıdakiler gibi en önemli Firestore özellikleri hakkında bilgi edindiniz:

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

Daha Fazla Bilgi

Firestore hakkında daha fazla bilgi edinmek için aşağıdaki kaynaklardan yararlanabilirsiniz:

Bu codelab'deki restoran uygulaması, "Friendly Eats" örnek uygulamasına dayanır. Söz konusu uygulamanın kaynak koduna buradan göz atabilirsiniz.

İsteğe bağlı: Üretime dağıtma

Bu uygulama şimdiye kadar yalnızca Firebase Emulator Suite'i kullanıyordu. 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ğıtma

Bu uygulama şu ana kadar tamamen yereldir ve tüm veriler Firebase Emulator Suite'te yer alır. Bu bölümde, Firebase projenizi bu uygulamanın üretimde çalışacağı şekilde nasıl yapılandıracağınızı öğreneceksiniz.

Firebase Authentication

Firebase konsolunda Kimlik doğrulama bölümüne gidin ve Başlayın'ı tıklayın. Giriş yöntemi sekmesine gidin ve Doğal sağlayıcılar bölümünden E-posta/Şifre seçeneğini belirleyin.

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

sign-in-providers.png

Firestore

Veritabanı oluştur

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

  1. Güvenlik kurallarıyla ilgili istem gösterildiğinde Üretim modunda başlatmayı seçin. Bu kuralları yakında güncelleyeceğiz.
  2. Uygulamanız için kullanmak istediğiniz veritabanı konumunu seçin. Veritabanı konumu seçiminin kalıcı bir karar olduğunu ve bunu değiştirmek için yeni bir proje oluşturmanız gerektiğini unutmayın. Proje konumu seçme hakkında daha fazla bilgi için dokümanlara bakın.

Kuralları Dağıtım

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 işlem, firestore.rules içeriğini projenize dağıtır. Bunu, konsoldaki Kurallar sekmesine giderek doğrulayabilirsiniz.

Dizinleri dağıtma

FriendlyEats uygulaması, bir dizi özel birleşik dizin gerektiren karmaşık bir sıralama ve filtreleme özelliğine sahiptir. Bunlar Firebase konsolunda manuel olarak oluşturulabilir ancak tanımlarını firestore.indexes.json dosyasına yazıp Firebase CLI'yi kullanarak dağıtmak daha kolaydır.

firestore.indexes.json dosyasını açarsanız gerekli dizinlerin zaten sağlandığını görürsünüz:

{
  "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şturma işleminin anında gerçekleşmediğini unutmayın. İlerleme durumunu Firebase konsolunda izleyebilirsiniz.

Uygulamayı yapılandırma

util/FirestoreInitializer.kt ve util/AuthInitializer.kt dosyalarında, Firebase SDK'sını hata ayıklama modundayken emülatörlere 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 istiyorsanız:

  1. Uygulamayı yayın modunda derleyin ve bir cihazda çalıştırın.
  2. BuildConfig.DEBUG değerini geçici olarak false ile değiştirip uygulamayı tekrar çalıştırın.

Üretime düzgün şekilde bağlanmak için uygulamada oturumu kapatıp tekrar oturum açmanız gerekebileceğini unutmayın.