How to implement Firebase Firestore in Kotlin Multiplatform Mobile (KMM) with Compose-Multiplatform

Carlos Ugaz
10 min readSep 22, 2023

A simple solution to use shared Kotlin code to develop an app for iOS and Android simultaneously, using compose-multiplatform.

What made me share this post was that when I was learning Kotlin Multiplatform I found a problem. Firebase doesn’t have a library that supports Kotlin native, so after searching Firebase Kotlin Multiplatform on Google I found a library from GitLive called firebase-kotlin-sdk that was a library that is a wrapper of the Firebase libraries which I can use in Kotlin Multiplatform. So hands-on work.

What will we do in this example?

  • Create an example using Android Studio that works for Android and iOS using Kotlin multiplatform and compose-multiplatform
  • Integrate Firebase Firestore to the project
  • Obtain some user data from Firestore and display it in the UI.

Requirements

  • To have some experience with Compose which is used currently in Android and Kotlin Multiplatform.
  • Have some experience in Kotlin.
  • Have some experience in Kotlin Coroutines

Step-by-step guide

Step 0 — Configure the environment for Kotlin Multiplatform

Step 1 — Create the project

A quick way to create the project is going to the JetBrains template for Kotlin Multiplatform for Android & iOS.

Click “use this template” → “create a new repository”

After that, you will see this next screen where you need to put a name for the repository and you need to click “Create repository”. In my case, I put “Firestore-example-kmm” as my repository name. This action will create a repository in your GitHub account using the template.

Step 2 — Compile the project

Open Android Studio and click “Get from VCS

The next screen will show where you need to put the URL of the repository created before. Also, if you like, you can modify in which directory you want to create the project on your computer. Finally, click “Clone”.

You will see this screen with the opened project but you will need to wait for Android Studio to finish the build from the project for some minutes depending on your computer.

Step 3 — Create the Firebase project

Go to the Firebase console and click “Add project

Write a name for your Firebase project and click “Continue”. In my case, I wrote “Firestore-example-kmm” as my project name.

The next step is to have Google Analytics for the project, which depends on you. Click “Create project”.

In my case, I disabled the toggle because it’s an example.

Now wait for the creation of your Firebase project.

After some time, you will see this screen and click “Continue”.

Step 4 — Add Firebase to the project

In this case, first, we need to change the application ID (Android) and the Bundle_ID (iOS). Go to Android Studio and type (command + shift + F) on Mac or (ctrl + shift + F) on Windows or Linux to open the “Find in files” screen and search “com.myapplication.MyApplication” as you see in the image.

Now, change the two results with a unique package name you want to use. In my case, I will use “com.carlosgub.firestore.kmm.example” as you can see in the image.

Step 5 — Add configuration for Android

1.Go to the project overview of your Firebase project and click on the Android icon that is shown in the image.

2. You will see the next screen where you need to put your Android package name.

In my case, I put “com.carlosgub.firestore.kmm.example” that was shown steps before in this tutorial. This next step is optional, I placed an app nickname which was “Firestore Example”. Finally, click “register app”.

3. Download the google-services.json

4. Go to Android Studio and in the project view, select the Project as you see in the arrow with the number one, and paste the google-services.json in the folder “androidApp” where the arrow with the number two is pointing.

6. Open the build.gradle. It’s located inside the “androidApp” folder and you will need to add these lines.

plugins {
kotlin("multiplatform")
id("com.android.application")
id("org.jetbrains.compose")
id("com.google.gms.google-services") // This line to add the google-services
}

kotlin {
androidTarget()
sourceSets {
val androidMain by getting {
dependencies {
implementation(platform("com.google.firebase:firebase-bom:30.0.1")) // This line to add the firebase bom
implementation(project(":shared"))
}
}
}
}
// This Lines to add firebase-common
dependencies {
implementation("com.google.firebase:firebase-common-ktx:20.3.3")
}

7. Open the AndroidManifest.xml located inside the “androidApp” folder and you will need to add these two lines to add the internet permission.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<uses-permission android:name="android.permission.INTERNET"/> <!--This line-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <!--This line-->

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
<activity
android:exported="true"
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden|mnc|colorMode|density|fontScale|fontWeightAdjustment|keyboard|layoutDirection|locale|mcc|navigation|smallestScreenSize|touchscreen|uiMode"
android:name=".MainActivity"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>

8. Open the MainActivity.kt located inside the “androidApp” folder and you will need to add these lines to initialize Firebase.

class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

Firebase.initialize(this) // This line
setContent {
MainView()
}
}
}

Step 6 — Add configuration for iOS (only if you have a Mac)

1.Go to the project overview of your Firebase project and click the “Add app” button that is shown in the first screen image. Next, click the “iOS” button shown in the second screen image.

First screen
Second screen
Second screen

2. You will see the next screen where you need to put your Android package name.

In my case, I placed it as “com.carlosgub.firestore.kmm.example” which was shown in the previous steps of this tutorial. After that, you can write some optional app nickname. Finally, click on “register app”.

3. Download the GoogleService-Info.plist, and click “Next”.

4. Open Xcode and click on “Open a project or file”

5. In Finder, go to your project location in your computer as you see in number one, click on the iosApp folder as you see in number two, and select iosApp.xcodeproj as you see with number three and then click “Open”.

6. Drag the GoogleService-Info.plist to the iosApp folder that is selected with an arrow.

7. You will see the next screen and click on the “Finish” button.

8. In Xcode, go to file → Add packages…

9. In the search bar, search “https://github.com/firebase/firebase-ios-sdk” and you will see 1 result, click on the “firebase-ios-sdk” result and click on the “Add Package” button.

10. After some time, you will see a list of package products for firebase-ios-sdk. For this example only select “FirebaseFirestore” and click “Add Package”.

11. Now, open the iOSApp file from your project in Xcode. And add these lines to the file to initialize Firebase.

import SwiftUI
import Firebase // Add this line

@main
struct iOSApp: App {
// Add this init with the FirebaseApp.configure()
init(){
FirebaseApp.configure()
}

var body: some Scene {
WindowGroup {
ContentView()
}
}
}

Step 7 — Configure the shared files

1.Open the build.gradle.kts located in the root of your project and add these lines.

plugins {
kotlin("multiplatform").apply(false)
id("com.android.application").apply(false)
id("com.android.library").apply(false)
id("org.jetbrains.compose").apply(false)
id("com.google.gms.google-services").version("4.3.14").apply(false) // This line
}

2. Open the build.gradle.kts located inside the shared folder in your project. Add these two lines inside the common Main variable to add the library Firebase Firestore and the kotlin serializable library used to transform the data from firestore.

plugins {
kotlin("multiplatform")
id("com.android.library")
id("org.jetbrains.compose")
kotlin("plugin.serialization") version "1.9.0" // This lines
}
// .....
kotlin{
// .....
val commonMain by getting {
dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
@OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class)
implementation(compose.components.resources)
implementation("dev.gitlive:firebase-firestore:1.8.1") // This line
implementation("dev.gitlive:firebase-common:1.8.1")// This line
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1") // This line
}
}
// .....
}
// .....

5. Compile to see if everything works.

Step 8 — Add data to the firestore to later show in the UI

1.In the console of Cloud Firestore, click on “+ Start collection”

2. Create a Collection with the ID with name “USERS”

3. Create a new document, and click on the “Auto-ID” button.

4. Add a new field with the name “name”, select “string” as type, and in the value write your name. In my case is “Carlos Ugaz”. And another field with the name “age”, select “number” as type and write your current age. In my case is “27”. Finally, click on the “Save” button.

5. You will see something like this:

Step 9 — Add the logic in the App to get the list of users.

1.Create a new kotlin file called User.kt inside the kotlin folder that is highlighted with the arrow and type the next lines. This data class will be used to transform the data from Firebase to a class that can be used in the project.

import kotlinx.serialization.Serializable

@Serializable
data class User(
val name: String,
val age: Int
)

2.Open the App.kt file, create a new function called getUsers and paste these next lines.

suspend fun getUsers(): List<User> {
val firebaseFirestore = Firebase.firestore
try {
val userResponse =
firebaseFirestore.collection("USERS").get()
return userResponse.documents.map {
it.data()
}
} catch (e: Exception) {
throw e
}
}

This code first creates a variable called firebaseFirestore which initializes firestore. Next, using Kotlin-coroutines, we obtain the collection “USERS” in the variable userResponse. Later, we transform the response of userResponse using the .map operator to return a list of the “User” class that we created before.

3.Create a composable function called UserItem that we will use to show the list of users in the App.

@Composable
fun UserItem(user: User) {
Column {
Text(
text = user.name
)
Text(
text = user.age.toString()
)
}
}

4.In the existing function App, remove all the code inside and replace it with this code.

@Composable
fun App() {
MaterialTheme {
Column(Modifier.fillMaxWidth()) {
var list by remember { mutableStateOf(listOf<User>()) }
LaunchedEffect(Unit) {
list = getUsers()
}
LazyColumn {
items(list) {
UserItem(it)
}
}
}
}
}

5.Compile

Congrats! You have already implemented Firebase Firestore for a Kotlin Multiplatform project. Now you have implemented dependency injection using Koin or a design pattern like MVVM or MVI to improve the code.

If you want to give a clap in this a star to my repo I would appreciate it.

--

--