Building a Car Rental App with Kotlin and Firebase

In this tutorial, we will be building a car rental app using Kotlin and Firebase. Kotlin is a modern programming language that is fully interoperable with Java and has gained popularity among Android developers for its concise syntax and powerful features. Firebase is a backend platform that provides a variety of tools and services to help developers build high-quality apps quickly and easily. By combining these two technologies, we can create a robust and scalable car rental app with real-time data updates and user authentication.

building car rental app kotlin firebase

Introduction

What is Kotlin?

Kotlin is a statically typed programming language developed by JetBrains. It is designed to be fully interoperable with Java, which means that Kotlin code can be mixed with Java code in the same project without any issues. Kotlin offers many advantages over Java, including null safety, concise syntax, improved readability, and enhanced support for functional programming. It has gained popularity among Android developers and is now officially supported by Google for Android app development.

What is Firebase?

Firebase is a mobile and web application development platform that provides a variety of tools and services to help developers build high-quality apps quickly and easily. It offers features such as real-time database, cloud storage, cloud messaging, authentication, and hosting. Firebase takes care of the server-side infrastructure, allowing developers to focus on building their apps without worrying about managing servers or writing complex backend code.

Why use Kotlin and Firebase for building a car rental app?

Kotlin and Firebase are a great combination for building a car rental app. Kotlin provides a modern and expressive language for writing Android apps, while Firebase offers a powerful backend platform that simplifies the development process. With Firebase, we can easily store and retrieve car data in real-time, implement user authentication, send push notifications to users, and more. The integration between Kotlin and Firebase is seamless, making it a perfect choice for developing a car rental app.

Setting Up the Project

Creating a new Kotlin project

To start building our car rental app, we first need to create a new Kotlin project in Android Studio. Follow these steps to create a new Kotlin project:

  1. Open Android Studio and click on "Start a new Android Studio project".
  2. Choose "Empty Activity" as the template for our project.
  3. Enter the project name, package name, and choose the target API level.
  4. Select "Kotlin" as the language for our project.
  5. Click on "Finish" to create the project.

Adding Firebase to the project

Next, we need to add Firebase to our project. Follow these steps to add Firebase to our Kotlin project:

  1. Open the Firebase console in your web browser and sign in with your Google account.
  2. Click on "Add project" to create a new project.
  3. Enter the project name and choose your country/region.
  4. Click on "Create project" to create the project.
  5. Once the project is created, click on "Add Firebase to your Android app".
  6. Enter the package name of your project and click on "Register app".
  7. Download the google-services.json file and place it in the app module of your project.
  8. Open the build.gradle file of your project and add the following dependencies:
// Top-level build.gradle file
buildscript {
    dependencies {
        // Add the Firebase plugin
        classpath 'com.google.firebase:firebase-crashlytics-gradle:2.6.0'
    }
}

// App-level build.gradle file
apply plugin: 'com.google.gms.google-services'

dependencies {
    // Add the Firebase SDK
    implementation 'com.google.firebase:firebase-analytics:17.6.0'
    implementation 'com.google.firebase:firebase-auth:19.4.0'
    implementation 'com.google.firebase:firebase-database:19.4.0'
    implementation 'com.google.firebase:firebase-messaging:20.2.4'
}

Configuring Firebase Authentication

To enable Firebase Authentication in our car rental app, we need to configure it in the Firebase console. Follow these steps to configure Firebase Authentication:

  1. Open the Firebase console and select your project.
  2. Click on "Authentication" in the left-hand menu.
  3. Click on the "Sign-in method" tab.
  4. Enable the "Email/Password" sign-in provider.
  5. Enable any other sign-in providers you want to support, such as Google or Facebook.
  6. Click on "Save" to save the changes.

Designing the User Interface

Creating the login screen

Now that we have set up our project and added Firebase, let's start designing the user interface of our car rental app. The first screen we will create is the login screen. Follow these steps to create the login screen:

  1. Open the activity_main.xml layout file in the res/layout directory.
  2. Replace the existing code with the following XML code:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center">

    <EditText
        android:id="@+id/emailEditText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Email"
        android:inputType="textEmailAddress"/>

    <EditText
        android:id="@+id/passwordEditText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Password"
        android:inputType="textPassword"/>

    <Button
        android:id="@+id/loginButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Login"/>

    <TextView
        android:id="@+id/registerTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Don't have an account? Register here."/>

</LinearLayout>
  1. Open the MainActivity.kt file and add the following code:
class MainActivity : AppCompatActivity() {

    private lateinit var emailEditText: EditText
    private lateinit var passwordEditText: EditText
    private lateinit var loginButton: Button
    private lateinit var registerTextView: TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        emailEditText = findViewById(R.id.emailEditText)
        passwordEditText = findViewById(R.id.passwordEditText)
        loginButton = findViewById(R.id.loginButton)
        registerTextView = findViewById(R.id.registerTextView)

        loginButton.setOnClickListener {
            val email = emailEditText.text.toString()
            val password = passwordEditText.text.toString()

            // TODO: Implement login logic using Firebase Authentication
        }

        registerTextView.setOnClickListener {
            // TODO: Open the registration screen
        }
    }
}
  1. Run the app on an emulator or a physical device to see the login screen.

Implementing user registration

Next, let's implement user registration in our car rental app. Follow these steps to implement user registration:

  1. Create a new Kotlin file called RegistrationActivity.kt.
  2. Add the following code to the RegistrationActivity.kt file:
class RegistrationActivity : AppCompatActivity() {

    private lateinit var emailEditText: EditText
    private lateinit var passwordEditText: EditText
    private lateinit var registerButton: Button

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_registration)

        emailEditText = findViewById(R.id.emailEditText)
        passwordEditText = findViewById(R.id.passwordEditText)
        registerButton = findViewById(R.id.registerButton)

        registerButton.setOnClickListener {
            val email = emailEditText.text.toString()
            val password = passwordEditText.text.toString()

            // TODO: Implement registration logic using Firebase Authentication
        }
    }
}
  1. Create a new XML layout file called activity_registration.xml.
  2. Add the following XML code to the activity_registration.xml file:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center">

    <EditText
        android:id="@+id/emailEditText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Email"
        android:inputType="textEmailAddress"/>

    <EditText
        android:id="@+id/passwordEditText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Password"
        android:inputType="textPassword"/>

    <Button
        android:id="@+id/registerButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Register"/>

</LinearLayout>
  1. Open the MainActivity.kt file and add the following code to the registerTextView.setOnClickListener block:
registerTextView.setOnClickListener {
    val intent = Intent(this, RegistrationActivity::class.java)
    startActivity(intent)
}
  1. Run the app and test the user registration functionality.

Building the car listing screen

Now that we have implemented the login and registration screens, let's move on to building the car listing screen. This screen will display a list of available cars to the user. Follow these steps to build the car listing screen:

  1. Create a new Kotlin file called CarListingActivity.kt.
  2. Add the following code to the CarListingActivity.kt file:
class CarListingActivity : AppCompatActivity() {

    private lateinit var carRecyclerView: RecyclerView
    private lateinit var carAdapter: CarAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_car_listing)

        carRecyclerView = findViewById(R.id.carRecyclerView)
        carAdapter = CarAdapter()

        // TODO: Initialize the RecyclerView and set the adapter
    }
}
  1. Create a new Kotlin file called CarAdapter.kt.
  2. Add the following code to the CarAdapter.kt file:
class CarAdapter : RecyclerView.Adapter<CarAdapter.CarViewHolder>() {

    private val carList: List<Car> = listOf(
        Car("Car 1", "Red", "ABC 123", true),
        Car("Car 2", "Blue", "DEF 456", false),
        Car("Car 3", "Green", "GHI 789", true)
    )

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CarViewHolder {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_car, parent, false)
        return CarViewHolder(view)
    }

    override fun onBindViewHolder(holder: CarViewHolder, position: Int) {
        val car = carList[position]
        holder.bind(car)
    }

    override fun getItemCount(): Int {
        return carList.size
    }

    inner class CarViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

        private val nameTextView: TextView = itemView.findViewById(R.id.nameTextView)
        private val colorTextView: TextView = itemView.findViewById(R.id.colorTextView)
        private val licensePlateTextView: TextView = itemView.findViewById(R.id.licensePlateTextView)
        private val availabilityTextView: TextView = itemView.findViewById(R.id.availabilityTextView)

        fun bind(car: Car) {
            nameTextView.text = car.name
            colorTextView.text = car.color
            licensePlateTextView.text = car.licensePlate

            if (car.isAvailable) {
                availabilityTextView.text = "Available"
            } else {
                availabilityTextView.text = "Not available"
            }
        }
    }

    data class Car(
        val name: String,
        val color: String,
        val licensePlate: String,
        val isAvailable: Boolean
    )
}
  1. Create a new XML layout file called activity_car_listing.xml.
  2. Add the following XML code to the activity_car_listing.xml file:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/carRecyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>
  1. Create a new XML layout file called item_car.xml.
  2. Add the following XML code to the item_car.xml file:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/nameTextView"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:textSize="16sp"
        android:textStyle="bold"/>

    <TextView
        android:id="@+id/colorTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:textSize="14sp"/>

    <TextView
        android:id="@+id/licensePlateTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:textSize="14sp"/>

    <TextView
        android:id="@+id/availabilityTextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:textSize="14sp"/>

</LinearLayout>
  1. Open the MainActivity.kt file and add the following code to the loginButton.setOnClickListener block:
loginButton.setOnClickListener {
    val email = emailEditText.text.toString()
    val password = passwordEditText.text.toString()

    // TODO: Implement login logic using Firebase Authentication
    // If login is successful, open the car listing screen
    val intent = Intent(this, CarListingActivity::class.java)
    startActivity(intent)
}
  1. Run the app and test the car listing functionality.

Implementing Firebase Realtime Database

Creating the database structure

Now that we have designed the user interface, let's move on to implementing the functionality to fetch car data from the Firebase Realtime Database. Follow these steps to create the database structure:

  1. Open the Firebase console and select your project.
  2. Click on "Database" in the left-hand menu.
  3. Click on "Create database" and choose "Start in test mode".
  4. Select a location for your database and click on "Enable".
  5. Click on "Add collection" and enter "cars" as the collection ID.
  6. Click on "Add document" and enter a document ID, such as "car1".
  7. Add the following fields to the document:
  • name: "Car 1"
  • color: "Red"
  • licensePlate: "ABC 123"
  • isAvailable: true
  1. Repeat steps 6-7 to add more car documents to the collection, if desired.

Fetching car data from the database

To fetch car data from the Firebase Realtime Database, we need to create a reference to the database and listen for data changes. Follow these steps to fetch car data from the database:

  1. Open the CarListingActivity.kt file and add the following code to the onCreate method:
val database = FirebaseDatabase.getInstance()
val carRef = database.getReference("cars")

carRef.addValueEventListener(object : ValueEventListener {
    override fun onDataChange(dataSnapshot: DataSnapshot) {
        val carList = mutableListOf<Car>()

        for (snapshot in dataSnapshot.children) {
            val car = snapshot.getValue(Car::class.java)
            car?.let { carList.add(it) }
        }

        carAdapter.submitList(carList)
    }

    override fun onCancelled(databaseError: DatabaseError) {
        // Handle database error
    }
})
  1. Modify the CarAdapter class to extend ListAdapter instead of RecyclerView.Adapter:
class CarAdapter : ListAdapter<Car, CarAdapter.CarViewHolder>(DiffCallback) {
    // ...
}
  1. Add a DiffCallback object to the CarAdapter class:
private object DiffCallback : DiffUtil.ItemCallback<Car>() {
    override fun areItemsTheSame(oldItem: Car, newItem: Car): Boolean {
        return oldItem.name == newItem.name
    }

    override fun areContentsTheSame(oldItem: Car, newItem: Car): Boolean {
        return oldItem == newItem
    }
}
  1. Modify the onBindViewHolder method in the CarAdapter class to use the currentList property instead of the carList property:
override fun onBindViewHolder(holder: CarViewHolder, position: Int) {
    val car = currentList[position]
    holder.bind(car)
}
  1. Run the app and test the car data fetching from the database.

Updating car availability

To update the availability of a car in the Firebase Realtime Database, we need to create a reference to the specific car document and update its isAvailable field. Follow these steps to update car availability:

  1. Modify the CarViewHolder class in the CarAdapter file to add a click listener to the availabilityTextView:
availabilityTextView.setOnClickListener {
    val car = currentList[adapterPosition]
    val carRef = database.getReference("cars/${car.name}")

    carRef.child("isAvailable").setValue(!car.isAvailable)
}
  1. Run the app and test the car availability update functionality.

Integrating Firebase Cloud Messaging

Sending push notifications to users

Firebase Cloud Messaging (FCM) allows us to send push notifications to users of our car rental app. Follow these steps to send push notifications to users:

  1. Open the Firebase console and select your project.
  2. Click on "Cloud Messaging" in the left-hand menu.
  3. Click on "New notification" and enter the notification details, such as title and message.
  4. Choose the target audience for the notification, such as all app users or a specific user segment.
  5. Click on "Send" to send the notification.

Handling incoming notifications

To handle incoming push notifications in our car rental app, we need to implement a FirebaseMessagingService. Follow these steps to handle incoming notifications:

  1. Create a new Kotlin file called MyFirebaseMessagingService.kt.
  2. Add the following code to the MyFirebaseMessagingService.kt file:
class MyFirebaseMessagingService : FirebaseMessagingService() {

    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        super.onMessageReceived(remoteMessage)

        // TODO: Handle incoming push notification
        val title = remoteMessage.notification?.title
        val message = remoteMessage.notification?.body

        // Show the notification to the user
        val notificationBuilder = NotificationCompat.Builder(this, "channel_id")
            .setContentTitle(title)
            .setContentText(message)
            .setSmallIcon(R.drawable.ic_notification)
            .setPriority(NotificationCompat.PRIORITY_HIGH)

        val notificationManager = NotificationManagerCompat.from(this)
        notificationManager.notify(0, notificationBuilder.build())
    }
}
  1. Open the AndroidManifest.xml file and add the following code inside the <application> tag:
<service
    android:name=".MyFirebaseMessagingService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT"/>
    </intent-filter>
</service>
  1. Run the app and test the push notification functionality.

Implementing User Authentication

Implementing email/password authentication

To implement email/password authentication in our car rental app, we need to use the Firebase Authentication API. Follow these steps to implement email/password authentication:

  1. Open the MainActivity.kt file and add the following code to the loginButton.setOnClickListener block:
loginButton.setOnClickListener {
    val email = emailEditText.text.toString()
    val password = passwordEditText.text.toString()

    FirebaseAuth.getInstance().signInWithEmailAndPassword(email, password)
        .addOnCompleteListener { task ->
            if (task.isSuccessful) {
                val intent = Intent(this, CarListingActivity::class.java)
                startActivity(intent)
            } else {
                val exception = task.exception
                // Handle login error
            }
        }
}
  1. Open the RegistrationActivity.kt file and add the following code to the registerButton.setOnClickListener block:
registerButton.setOnClickListener {
    val email = emailEditText.text.toString()
    val password = passwordEditText.text.toString()

    FirebaseAuth.getInstance().createUserWithEmailAndPassword(email, password)
        .addOnCompleteListener { task ->
            if (task.isSuccessful) {
                // Registration successful, open the login screen
                val intent = Intent(this, MainActivity::class.java)
                startActivity(intent)
            } else {
                val exception = task.exception
                // Handle registration error
            }
        }
}
  1. Run the app and test the email/password authentication functionality.

Integrating social media login

To integrate social media login in our car rental app, we can use the Firebase Authentication API to authenticate users with popular social media platforms such as Google or Facebook. Follow these steps to integrate social media login:

  1. Open the Firebase console and select your project.
  2. Click on "Authentication" in the left-hand menu.
  3. Click on the social media provider you want to integrate with, such as Google or Facebook.
  4. Follow the instructions provided by Firebase to enable the social media provider and obtain the necessary credentials.
  5. Open the MainActivity.kt file and add the following code to the onCreate method:
val googleSignInButton = findViewById<SignInButton>(R.id.googleSignInButton)
googleSignInButton.setOnClickListener {
    val signInIntent = Auth.GoogleSignInApi.getSignInIntent(googleApiClient)
    startActivityForResult(signInIntent, RC_SIGN_IN)
}

val callbackManager = CallbackManager.Factory.create()
val facebookLoginButton = findViewById<LoginButton>(R.id.facebookLoginButton)
facebookLoginButton.setPermissions("email", "public_profile")
facebookLoginButton.registerCallback(callbackManager, object : FacebookCallback<LoginResult> {
    override fun onSuccess(loginResult: LoginResult) {
        val credential = FacebookAuthProvider.getCredential(loginResult.accessToken.token)
        firebaseAuthWithCredential(credential)
    }

    override fun onCancel() {
        // Handle login cancellation
    }

    override fun onError(error: FacebookException) {
        // Handle login error
    }
})
  1. Add the following code to the MainActivity.kt file:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)

    if (requestCode == RC_SIGN_IN) {
        val task = GoogleSignIn.getSignedInAccountFromIntent(data)
        val account = task.getResult(ApiException::class.java)
        val credential = GoogleAuthProvider.getCredential(account?.idToken, null)
        firebaseAuthWithCredential(credential)
    } else {
        callbackManager.onActivityResult(requestCode, resultCode, data)
    }
}

private fun firebaseAuthWithCredential(credential: AuthCredential) {
    FirebaseAuth.getInstance().signInWithCredential(credential)
        .addOnCompleteListener { task ->
            if (task.isSuccessful) {
                val intent = Intent(this, CarListingActivity::class.java)
                startActivity(intent)
            } else {
                val exception = task.exception
                // Handle login error
            }
        }
}
  1. Add the necessary dependencies to the build.gradle file:
implementation 'com.google.android.gms:play-services-auth:19.2.0'
implementation 'com.facebook.android:facebook-login:8.2.0'
  1. Run the app and test the social media login functionality.

Conclusion

In this tutorial, we have learned how to build a car rental app using Kotlin and Firebase. We started by setting up the project and integrating Firebase into our Kotlin project. Then, we designed the user interface with login, registration, and car listing screens. We implemented Firebase Realtime Database to store and retrieve car data in real-time. We also integrated Firebase Cloud Messaging to send push notifications to users. Lastly, we implemented user authentication with email/password and social media login.

Kotlin and Firebase provide a powerful combination for building robust and scalable Android apps. With Kotlin's concise syntax and powerful features, and Firebase's backend platform that handles server-side infrastructure, developers can focus on building high-quality apps without worrying about managing servers or writing complex backend code. By following the steps in this tutorial, you can create your own car rental app and explore the various features offered by Kotlin and Firebase. Happy coding!