Android Firebase for beginers

Android Firebase for beginers

Firebase

I. What is Firebase

Google Firebase is a Google-backed application development software that enables developers to develop iOS, Android and Web apps. Firebase provides tools for tracking analytics, reporting and fixing app crashes, creating marketing and product experiment. Firebase has many services and today I’m going to introduce to in-app messaging, cloud messages and real-time databases.

II. Add Firebase to your app

Before you integrate Firebase into your Android app, you need to create a Firebase project to connect to your Android app. log in to Firebase console in this link https://console.firebase.google.com/?hl=en
Step 1: After you signed-in to Firebase, click on “Create a project“.

Step 2: There are steps to take to create a new Firebase project. Click on Android icon.

Step 3: Enter your “Android package name” the same as package name in AndroidManifest

 

Step 4:  Download “google-services.json” and add to the project.

  • Click on Project to switch view, you will see the root directory of the project . Put the “google-services.json” file into  “Project/~/app” folder.

Step 5: Add Firebase SDK.

1. Inbuild.gradle” (Project):

2. Inbuild.gradle” (app):

Step 6: Run and wait Firebase verify the app, you will see message when success, click on “Continue to console”.

III. In-App Message

1. Introduction

Firebase In-App Messaging helps you engage your app’s active users by sending them targeted, contextual messages that encourage them to use key app features. For example, you could send an in-app message to get users to subscribe, watch a video, complete a level, or buy an item. You can customize messages as cards, banners, modals, or images, and set up triggers so that they appear exactly when they’d benefit your users most.

2. Get start

Step 1Add “implementation ‘com.google.firebase:firebase-inappmessaging-display:19.0.3’ into “build.gradle” (app) and Click “Sync Now“.

Step 2: Get Firebase instance ID (this id’s used to test in-app message on Firebase).

private fun createInstanceId() {
    FirebaseInstanceId.getInstance().instanceId.addOnCompleteListener { task ->
        if (!task.isSuccessful) {
            Log.w(TAG, "getInstanceId failed", task.exception)
            return@addOnCompleteListener
        }

        //create new instance id Token
        val msg = task.result?.id
        Log.d(TAG, "token: $msg")
    }
}

Step 3: Run the app and open “Logcat” tool, we will see the ID token.

Step 4: Copy the ID token, open Firebase console -> “In-App Messaging“, click “Create your first campaign”.

Step 5: Enter “Message title” (ex: Hello I’m FireBase), “Body” (optional), “Images” (ex: https://cdn.pixabay.com/photo/2015/10/12/14/54/coffee-983955_960_720.jpg)

Add “Button text“.

Step 6: Click “Test on Device”, and paste the ID token into “Add an instance ID” field.

Firebase In-App Messaging sends the test message as soon as you click “Test“. To see it, move the app to background, then re-open the app on your testing device.

Result:

Step 7: After test successfully, click “Next” to continue.

Click “Review” to publish your message.

When click “Publish” message will send to the app.

Result:

IV. Cloud Message

1. Introduction

Firebase Cloud Messaging (FCM) is a cross-platform messaging solution that lets you reliably send messages at no cost. Using FCM, you can notify a client app that new email or other data is available to sync. You can send notification messages to drive user re-engagement and retention. For use cases such as instant messaging, a message can transfer a payload of up to 4KB to a client app.

2. Get start

Step 1: Add “implementation ‘com.google.firebase:firebase-messaging:20.1.0’ “into “build.gradle” (app) and Click “Sync Now“.

Step 2 : Add filter to AndroidManifest file.

<service
    android:name=".java.MyFirebaseMessagingService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

MyFirebaseMessagingService is a service that extends FirebaseMessagingService. This is required when you want to do any message handling beyond receiving notifications on apps in the background. To receive notifications in foreground apps, to receive data payload, to send upstream messages, and so on, you must use this service.

Now you will see an error at line 23. This is occurred because we don’t have MyFirebaseMessagingService file in project so let create it.

Change package name from .java.MyFirebaseMessagingService to <package>.MyFirebaseMessagingService.

Step 3 (optional): Set a default icon and color, you can skip this step if you do not want icon and color in your notification.

<!-- Set custom default icon. This is used when no icon is set for incoming notification messages.
     See README(https://goo.gl/l4GJaQ) for more. -->
<meta-data
    android:name="com.google.firebase.messaging.default_notification_icon"
    android:resource="@drawable/ic_stat_ic_notification" />
<!-- Set color used with incoming notification messages. This is used when no color is set for the incoming
     notification message. See README(https://goo.gl/6BKBk7) for more. -->
<meta-data
    android:name="com.google.firebase.messaging.default_notification_color"
    android:resource="@color/colorAccent" />

Step 4 (Optional): From Android 8.0 (API level 26) and higher, notification channels are supported and recommended. FCM provides a default notification channel with basic settings. If you prefer to create and use your own default channel, set default_notification_channel_id to the ID of your notification channel object as shown; FCM will use this value whenever incoming messages do not explicitly set a notification channel. To learn more, see Manage notification channels.

  • Goto res/values/strings.xml and add this line.
<string name="default_notification_channel_id">1</string>

  • Open AndroidManifest file and add this code.
<meta-data
    android:name="com.google.firebase.messaging.default_notification_channel_id"
    android:value="@string/default_notification_channel_id" />

 Step 5: Open MainActivity to retrieve the current registration token, add this function

private fun createInstanceId() {
    FirebaseInstanceId.getInstance().instanceId.addOnCompleteListener { task ->
        if (!task.isSuccessful) {
            Log.w(TAG, "getInstanceId failed", task.exception)
            return@addOnCompleteListener
        }

        //get id Token
        // Get new Instance ID token
        val token = task.result?.token

        // Log and toast
        Log.d(TAG, "token: $token")
        Toast.makeText(baseContext, "token: $token", Toast.LENGTH_SHORT).show()
    }
}

  • Run the app, to get Firebase instance ID.

Step 6: Add the code below into the MyFirebaseMessagingService class.

class MyFirebaseMessagingService : FirebaseMessagingService() {
    companion object {
        private val TAG = this::class.java.simpleName
    }

    override fun onNewToken(token: String) {
        Log.d(TAG, "Refreshed token: $token")
        super.onNewToken(token)
    }

    override fun onMessageReceived(remoteMessage: RemoteMessage) {
        super.onMessageReceived(remoteMessage)
        Log.d(TAG, "From: ${remoteMessage.from}")

        remoteMessage.data.isNotEmpty().let {
        }

        remoteMessage.notification?.let {
            Log.d(TAG, "Message Notification Body: ${it.body}")
            it.body?.let { body ->
                sendNotification(body)
            }
        }
    }

    private fun sendNotification(messageBody: String) {
        val intent = Intent(this, CloudMessageActivity::class.java)
        intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
        val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT)

        val channelId = getString(R.string.default_notification_channel_id)
        val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
        val notificationBuilder = NotificationCompat.Builder(this, channelId)
            .setSmallIcon(R.drawable.ic_notifications)
            .setContentTitle("Mess Title")
            .setContentText(messageBody)
            .setAutoCancel(true)
            .setSound(defaultSoundUri)
            .setContentIntent(pendingIntent)

        val notificationManager =
            getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                channelId, "Channel human readable title",
                NotificationManager.IMPORTANCE_DEFAULT
            )
            notificationManager.createNotificationChannel(channel)
        }

        notificationManager.notify(1, notificationBuilder.build())
    }
}

Step 7: Test Cloud Messaging.

Enter Notification Title, text and image (optional) ex: https://cdn.pixabay.com/photo/2017/07/07/02/05/symbol-2480161_960_720.png and send test message.

  • Add the token we got from Logcat (step 5)

  • Result:

Step 7: Create and send message.

After test successfully, click “Next” to continue.

  • Click “Publish” to send a message.

Result:

V. Realtime Database

1. Introduction

The Firebase Realtime Database is a cloud-hosted database. Data is stored as JSON and synchronized in realtime to every connected client. When you build cross-platform apps with our iOS, Android, and JavaScript SDKs, all of your clients share one Realtime Database instance and automatically receive updates with the newest data.

2. Get start

Step 1Add “implementation ‘com.google.firebase:firebase-database:19.2.1’ “into “build.gradle” (app) and Click “Sync Now“.

Step 2: Configure realtime database rules for testing

About real time database rules you can read from here

Step 3: Create UserModel Class

data class UserModel(
    var id: String = "",
    var name: String = "",
    var age: Int = 0,
    var email: String = ""
) {
    override fun toString(): String {
        return "UserModel(id='$id', name='$name', age=$age, email='$email')"
    }
}

Step 4: Create layout with 3 edit (name, age and email), 4 button (insert, get, update, delete), 1 recycler view to contain User data

This is my layout.

Step 5:

Write to your database

First initialize databaseReference.

private fun initDatabase() {
    databaseReference = FirebaseDatabase.getInstance().reference
}

Next, get data from EditText and insert to database.

private fun insertUser() {
    if (edt_name.text.isNullOrEmpty() || edt_age.text.isNullOrEmpty() || edt_email.text.isNullOrEmpty()) {
        Toast.makeText(this, "Some field are missing.", Toast.LENGTH_SHORT).show()
        return
    }

    //get key
    val key = databaseReference.child("User").push().key

    //get user data from edit text
    val user = UserModel(
        name = edt_name.text.toString(),
        age = edt_age.text.toString().toInt(),
        email = edt_email.text.toString()
    )

    key?.let {
        user.id = key

        // Write a data to the database
        databaseReference.child("User").child(key).setValue(user).addOnSuccessListener {
            clearText()
            //get user data from database
            getUser()
            //scroll to new item
            recycler_user.scrollToPosition(recyclerAdapter.userList.size - 1)
        }
            .addOnFailureListener {
                Toast.makeText(this, "Upload Error", Toast.LENGTH_SHORT).show()
            }
    }
}

Add this code to insert button click event.

btn_insert.setOnClickListener {
    insertUser()
}

After clicking the “Insert” button in your app, data will be send to Firebase immediately.

Read database:

databaseReference.child("User").addValueEventListener(object : ValueEventListener {
    override fun onCancelled(dataError: DatabaseError) {
        Toast.makeText(this@DataBaseActivity, "Upload Error", Toast.LENGTH_SHORT).show()
    }

    override fun onDataChange(dataSnapshot: DataSnapshot) {
        
        //get user list from database
        val list = dataSnapshot.children.mapNotNull {
            it.getValue(UserModel::class.java)
        }
        list.forEach {
            Log.i("Users", it.toString())
        }
        //add to recycler view
        if (list.isNotEmpty()) {
            recyclerAdapter.userList.clear()
            recyclerAdapter.userList.addAll(list)
            recyclerAdapter.notifyDataSetChanged()
        }
    }
})

Update database:

private fun updateUser() {
    user?.let {
        //create new user object
        val user = UserModel(
            it.id,
            edt_name.text.toString(),
            edt_age.text.toString().toInt(),
            edt_email.text.toString()
        )
        //update user
        databaseReference.child("User/${it.id}").setValue(user)
    }
}

Delete database:

private fun deleteUser() {
    // get user id
    val query =
        databaseReference.child("User").orderByChild("id").equalTo(user?.id)

    query.addListenerForSingleValueEvent(object : ValueEventListener {
        override fun onDataChange(dataSnapshot: DataSnapshot) {
            for (user in dataSnapshot.children) {
                //remove user
                user.ref.removeValue().addOnSuccessListener {
                    clearText()
                }
            }
        }

        override fun onCancelled(databaseError: DatabaseError) {
            Log.e(
                TAG,
                "onCancelled",
                databaseError.toException()
            )
        }
    })
    getUser()
}

VI. Reference documents

https://firebase.google.com/docs/guides

https://github.com/firebase/quickstart-android/blob/995be41782f84b3c54e41d7d7e5d3a5048fe329e/messaging/app/src/main/java/com/google/firebase/quickstart/fcm/kotlin/MyFirebaseMessagingService.kt#L65-L77

https://proandroiddev.com/firebase-android-playground-realtime-database-560d4e18404a

https://www.learnhowtoprogram.com/android/data-persistence/firebase-reading-data-and-event-listeners