Step by step examples to teach you FCM Push Notification.
1. layonmartins/SendPushNotificationFCM
An Android App Util of how to push a notification using Firebase Cloud Messaging.
- Kotlin
- Push Notification
- Firebase Cloud Messaging - FCM
- Send notification from Firebase console FCM
- To find the server key, go to the Firebase console:
Here is the code;
Step 1. Dependencies
We need to add some dependencies in our app/build.gradle
file as shown below:
(a). build.gradle
Our app-level
build.gradle
.
We will enable Java8 so that we can utilize a myriad of Java8 features.
We then declare our app dependencies under the dependencies
closure, using the implementation
statement. We will need the following 10 dependencies:
Core-ktx
- With this we can target the latest platform features and APIs while also supporting older devices.Appcompat
- Allows us access to new APIs on older API versions of the platform (many using Material Design).Material
- Collection of Modular and customizable Material Design UI components for Android.Constraintlayout
- This allows us to Position and size widgets in a flexible way with relative positioning.- Our
Firebase-messaging-ktx
library. - Our
Kotlinx-coroutines-core
Kotlin library. - Our
Kotlinx-coroutines-android
Kotlin library. - Our
Retrofit
library. - Our
Converter-gson
library. - Our
Logging-interceptor
library.
Here is our full app/build.gradle
:
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'com.google.gms.google-services'
}
android {
compileSdk 31
defaultConfig {
applicationId "com.layon.sendpushnotificationfcm"
minSdk 28
targetSdk 31
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
viewBinding {
enabled = true
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
//FCM
implementation 'com.google.firebase:firebase-messaging-ktx:23.0.0'
// Coroutines
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.5'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.5'
// Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.6.2'
implementation 'com.squareup.retrofit2:converter-gson:2.6.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.8.0'
}
Step 2. Our Android Manifest
We will need to look at our AndroidManifest.xml
.
(a). AndroidManifest.xml
Our
AndroidManifest
file.
This project will have 2 Activities
. For them to be accessible we have to register them. We do that below. We will be creating a single Service
so we have to register it as well. We will be defining 2 meta-data
tags as shown below. Here we will add the following permission:
- Our
INTERNET
permission.
Here is the full Android Manifest file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.layon.sendpushnotificationfcm">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="com.google.android.c2dm.permission.SEND" />
<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.SendPushNotificationFCM">
<activity
android:name=".ResultActivity"
android:exported="false" />
<activity
android:name=".MainActivity"
android:exported="true"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".service.FirebaseMessagingService"
android:exported="false"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.SEND" />
</intent-filter>
</service>
<!--
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_baseline_sentiment_very_dissatisfied_24" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="@string/high_notification_channel_id" />
</application>
</manifest>
Step 3. Design Layouts
For this project let's create the following layouts:
(a). activity_result.xml
Our
activity_result
layout.
This layout will represent our Result Activity's layout. Specify androidx.constraintlayout.widget.ConstraintLayout
as it's root element then inside it place the following widgets:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ResultActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Result Activity"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
(b). activity_main.xml
Our
activity_main
layout.
This layout will represent our Main Activity's layout. Specify androidx.constraintlayout.widget.ConstraintLayout
as it's root element then inside it place the following widgets:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textViewTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="Title:"
app:layout_constraintBottom_toBottomOf="@+id/editTextTitle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/editTextTitle" />
<EditText
android:id="@+id/editTextTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:ems="12"
android:inputType="text"
android:text="Title of notification"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/textViewBody"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/textViewBody"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="Body:"
app:layout_constraintBottom_toBottomOf="@+id/editTextBody"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/editTextBody" />
<EditText
android:id="@+id/editTextBody"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:ems="12"
android:inputType="text"
android:text="Body of notification"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/textViewBody"
app:layout_constraintTop_toBottomOf="@+id/editTextTitle" />
<TextView
android:id="@+id/textViewData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="Data:"
app:layout_constraintBottom_toBottomOf="@+id/editTextData"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/editTextData" />
<EditText
android:id="@+id/editTextData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:ems="12"
android:inputType="text"
android:text="any data string"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/textViewBody"
app:layout_constraintTop_toBottomOf="@+id/editTextBody" />
<TextView
android:id="@+id/textViewShowPopUp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="Data:"
app:layout_constraintBottom_toBottomOf="@+id/checkBoxShowPopUp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/checkBoxShowPopUp" />
<CheckBox
android:id="@+id/checkBoxShowPopUp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="show the notification in popUp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/textViewBody"
app:layout_constraintTop_toBottomOf="@+id/editTextData" />
<TextView
android:id="@+id/textViewSendToken"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="SendTo Token:"
app:layout_constraintBottom_toBottomOf="@+id/editTextSendToken"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/editTextSendToken" />
<EditText
android:id="@+id/editTextSendToken"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="0dp"
android:ems="12"
android:inputType="text"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/textViewBody"
app:layout_constraintTop_toBottomOf="@+id/checkBoxShowPopUp" />
<TextView
android:id="@+id/textViewServerKey"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="Server Key:"
app:layout_constraintBottom_toBottomOf="@+id/editTextServerKey"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/editTextServerKey" />
<EditText
android:id="@+id/editTextServerKey"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="8dp"
android:ems="12"
android:inputType="text"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/textViewBody"
app:layout_constraintTop_toBottomOf="@+id/editTextSendToken" />
<TextView
android:id="@+id/textViewMyFCMTokenLabel"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="12dp"
android:text="My FCM Token:"
app:layout_constraintBottom_toTopOf="@+id/textViewMyFCMToken"
app:layout_constraintStart_toStartOf="@+id/textViewMyFCMToken" />
<ImageView
android:id="@+id/copyImageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="5dp"
app:layout_constraintEnd_toEndOf="@+id/textViewMyFCMToken"
app:layout_constraintTop_toTopOf="@+id/textViewMyFCMToken"
app:srcCompat="@drawable/ic_baseline_content_copy_24" />
<TextView
android:id="@+id/textViewMyFCMToken"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="12dp"
app:layout_constraintHeight_min="80dp"
android:background="@drawable/border"
android:padding="25dp"
app:layout_constraintBottom_toTopOf="@+id/button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="Send Push Notification"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Step 4. Write Code
Finally we need to write our code as follows:
(a). Notification.kt
Our
Notification
class.
Create a Kotlin file named Notification.kt
.
Here is the full code:
package replace_with_your_package_name
//This data class will be received in FirebaseMessagingService::class#onMessageReceived() from RemoteMessage.notification object
data class Notification(
val title: String,
val body: String
)
(b). NotificationData.kt
Our
NotificationData
class.
Create a Kotlin file named NotificationData.kt
.
Here is the full code:
package replace_with_your_package_name
//This data class will be received in FirebaseMessagingService::class#onMessageReceived() from RemoteMessage.data object
data class NotificationData(
//to add new notification create new fields here
val data: String,
val showPopUp: Boolean = true
)
(c). PushNotification.kt
Our
PushNotification
class.
Create a Kotlin file named PushNotification.kt
.
Here is the full code:
package replace_with_your_package_name
data class PushNotification(
val notification: Notification,
val data : NotificationData,
val to : String //fcm token of who will receive the push notification
)
(d). Constants.kt
Our
Constants
class.
Create a Kotlin file named Constants.kt
.
Here is the full code:
package replace_with_your_package_name
class Constants {
companion object {
const val BASE_URL = "https://fcm.googleapis.com"
const val CONTENT_TYPE = "application/json"
}
}
(e). NotificationUtil.kt
Our
NotificationUtil
class.
Create a Kotlin file named NotificationUtil.kt
and add the necessary imports. Here are some of the imports we will be using:
Intent
from theandroid.content
package.Color
from theandroid.graphics
package.Log
from theandroid.util
package.NotificationCompat
from theandroidx.core.app
package.ContextCompat
from theandroidx.core.content
package.
Then we will be creating the following functions:
createNotification(context: Context, title: String, body: String, data: Map<String, String>? = null)
.createChannels(parameter)
- Let's pass aContext
object as a parameter.createNotificationHighPriorityChannel(parameter)
- We pass aContext
object as a parameter.createNotificationDefaultPriorityChannel(parameter)
- We pass aContext
object as a parameter.
(a). Our createNotificationDefaultPriorityChannel()
function
Write the createNotificationDefaultPriorityChannel()
function as follows:
private fun createNotificationDefaultPriorityChannel(context: Context) {
val channelName = context.getString(R.string.default_notification_channel_name)
val channelId = context.getString(R.string.default_notification_channel_id)
val channel = NotificationChannel(
channelId, channelName,
NotificationManager.IMPORTANCE_DEFAULT
).apply {
description =
"This channel the notification does not makes a sound and does not appears as a heads-up notification"
enableLights(false)
lightColor = Color.GREEN
}
val notificationManager = ContextCompat.getSystemService(
context,
NotificationManager::class.java
) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
(b). Our createNotification()
function
Write the createNotification()
function as follows:
fun createNotification(context: Context, title: String, body: String, data: Map<String, String>? = null) {
val intent = Intent(context, MainActivity::class.java)
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val notificationID = Random.nextInt()
Log.d("layon.f", "createNotification: title $title body: $body notificationID: $notificationID")
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_ONE_SHOT)
val channel = if (data?.get("showPopUp") == "true") {
context.getString(R.string.high_notification_channel_id)
} else {
context.getString(R.string.default_notification_channel_id)
}
val notification =
NotificationCompat.Builder(context, channel)
.setContentTitle(title)
.setContentText(body)
.setSmallIcon(R.drawable.ic_baseline_add_reaction_24)
.setAutoCancel(true)
.setContentIntent(pendingIntent)
.build()
notificationManager.notify(notificationID, notification)
}
(c). Our createChannels()
function
Write the createChannels()
function as follows:
fun createChannels(context: Context) {
createNotificationHighPriorityChannel(context)
createNotificationDefaultPriorityChannel(context)
}
(d). Our createNotificationHighPriorityChannel()
function
Write the createNotificationHighPriorityChannel()
function as follows:
private fun createNotificationHighPriorityChannel(context: Context) {
val channelName = context.getString(R.string.high_notification_channel_name)
val channelId = context.getString(R.string.high_notification_channel_id)
val channel = NotificationChannel(
channelId, channelName,
NotificationManager.IMPORTANCE_HIGH
).apply {
description =
"This channel the notification makes a sound and appears as a heads-up notification"
enableLights(true)
lightColor = Color.GREEN
}
val notificationManager = ContextCompat.getSystemService(
context,
NotificationManager::class.java
) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
Here is the full code:
package replace_with_your_package_name
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import com.layon.sendpushnotificationfcm.MainActivity
import com.layon.sendpushnotificationfcm.R
import kotlin.random.Random
class NotificationUtil {
companion object {
fun createNotification(context: Context, title: String, body: String, data: Map<String, String>? = null) {
val intent = Intent(context, MainActivity::class.java)
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val notificationID = Random.nextInt()
Log.d("layon.f", "createNotification: title $title body: $body notificationID: $notificationID")
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_ONE_SHOT)
val channel = if (data?.get("showPopUp") == "true") {
context.getString(R.string.high_notification_channel_id)
} else {
context.getString(R.string.default_notification_channel_id)
}
val notification =
NotificationCompat.Builder(context, channel)
.setContentTitle(title)
.setContentText(body)
.setSmallIcon(R.drawable.ic_baseline_add_reaction_24)
.setAutoCancel(true)
.setContentIntent(pendingIntent)
.build()
notificationManager.notify(notificationID, notification)
}
fun createChannels(context: Context) {
createNotificationHighPriorityChannel(context)
createNotificationDefaultPriorityChannel(context)
}
private fun createNotificationHighPriorityChannel(context: Context) {
val channelName = context.getString(R.string.high_notification_channel_name)
val channelId = context.getString(R.string.high_notification_channel_id)
val channel = NotificationChannel(
channelId, channelName,
NotificationManager.IMPORTANCE_HIGH
).apply {
description =
"This channel the notification makes a sound and appears as a heads-up notification"
enableLights(true)
lightColor = Color.GREEN
}
val notificationManager = ContextCompat.getSystemService(
context,
NotificationManager::class.java
) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
private fun createNotificationDefaultPriorityChannel(context: Context) {
val channelName = context.getString(R.string.default_notification_channel_name)
val channelId = context.getString(R.string.default_notification_channel_id)
val channel = NotificationChannel(
channelId, channelName,
NotificationManager.IMPORTANCE_DEFAULT
).apply {
description =
"This channel the notification does not makes a sound and does not appears as a heads-up notification"
enableLights(false)
lightColor = Color.GREEN
}
val notificationManager = ContextCompat.getSystemService(
context,
NotificationManager::class.java
) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
}
}
(f). FirebaseMessagingService.kt
Our
FirebaseMessagingService
class.
Create a Kotlin file named FirebaseMessagingService.kt
and add the necessary imports. Here are some of the imports we will be using:
Intent
from theandroid.content
package.Log
from theandroid.util
package.
Then extend the FirebaseMessagingService
and add its contents as follows:
First override these callbacks:
onMessageReceived(remoteMessage: RemoteMessage)
.onNewToken(newToken: String)
.
Here is the full code:
package replace_with_your_package_name
import android.content.Intent
import android.util.Log
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import com.layon.sendpushnotificationfcm.ResultActivity
import com.layon.sendpushnotificationfcm.utils.NotificationUtil
class FirebaseMessagingService : FirebaseMessagingService() {
override fun onMessageReceived(remoteMessage: RemoteMessage) {
super.onMessageReceived(remoteMessage)
Log.d("layon.f", "message: $remoteMessage")
Log.d("layon.f", "message.from: ${remoteMessage.from}")
Log.d("layon.f", "message.data: ${remoteMessage.data}")
Log.d(
"layon.f",
"message.notification: ${remoteMessage.notification?.title} ${remoteMessage.notification?.body}"
)
remoteMessage.data?.let {
Log.d("layon.f", "message.data.getdata: ${remoteMessage.data.get("data")}")
if (it.get("data").toString() == "open result") {
Log.d("layon.f", "it.contains("data").toString() ${it.contains("data").toString()}")
val intent = Intent(this, ResultActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
}
}
remoteMessage.notification?.let { notification ->
NotificationUtil.createNotification(
context = this,
title = notification.title.toString(),
body = notification.body.toString(),
data = remoteMessage.data
)
}
}
override fun onNewToken(newToken: String) {
super.onNewToken(newToken)
Log.d("layon.f", "onNewToken : $newToken")
}
}
(g). NotificationAPI.kt
Our
NotificationAPI
class.
Create a Kotlin file named NotificationAPI.kt
.
Then we will be creating the following functions:
Here is the full code:
package replace_with_your_package_name
import com.layon.sendpushnotificationfcm.model.PushNotification
import okhttp3.ResponseBody
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.Header
import retrofit2.http.POST
interface NotificationAPI {
@POST("fcm/send")
suspend fun postNotification(
@Body notification: PushNotification,
@Header("Authorization") serverKey: String,
@Header("Content-Type") contentType: String,
) : Response<ResponseBody>
}
(h). RetrofitInstance.kt
Our
RetrofitInstance
class.
Create a Kotlin file named RetrofitInstance.kt
.
Then we will be creating the following functions:
setupLog(): OkHttpClient
.
(a). Our setupLog()
function
Write the setupLog()
function as follows:
fun setupLog(): OkHttpClient {
val logging = HttpLoggingInterceptor()
logging.setLevel(HttpLoggingInterceptor.Level.BODY)
val httpClient = OkHttpClient.Builder()
httpClient.addInterceptor(logging)
return httpClient.build()
}
Here is the full code:
package replace_with_your_package_name
import com.layon.sendpushnotificationfcm.utils.Constants.Companion.BASE_URL
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
class RetrofitInstance {
companion object {
fun setupLog(): OkHttpClient {
val logging = HttpLoggingInterceptor()
logging.setLevel(HttpLoggingInterceptor.Level.BODY)
val httpClient = OkHttpClient.Builder()
httpClient.addInterceptor(logging)
return httpClient.build()
}
private val retrofit by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.client(setupLog())
.addConverterFactory(GsonConverterFactory.create())
.build()
}
val api by lazy {
retrofit.create(NotificationAPI::class.java)
}
}
}
(i). ResultActivity.kt
Our
ResultActivity
class.
Create a Kotlin file named ResultActivity.kt
and add the necessary imports. Here are some of the imports we will be using:
AppCompatActivity
from theandroidx.appcompat.app
package.Bundle
from theandroid.os
package.
Then extend the AppCompatActivity
and add its contents as follows:
First override these callbacks:
onCreate(savedInstanceState: Bundle?)
.
Here is the full code:
package replace_with_your_package_name
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class ResultActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_result)
}
}
(j). MainActivity.kt
Our
MainActivity
class.
Create a Kotlin file named MainActivity.kt
and add the necessary imports. Here are some of the imports we will be using:
Log
from theandroid.util
package.Toast
from theandroid.widget
package.CoroutineScope
from thekotlinx.coroutines
package.Dispatchers
from thekotlinx.coroutines
package.launch
from thekotlinx.coroutines
package.
Then extend the AppCompatActivity
and add its contents as follows:
First override these callbacks:
onCreate(savedInstanceState: Bundle?)
.
Then we will be creating the following functions:
copy(parameter)
- We pass aString
object as a parameter.showToast(parameter)
- Our function will take aString
object as a parameter.
(a). Our copy()
function
Write the copy()
function as follows:
private fun copy(text: String){
val clipboard: ClipboardManager =
getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("copy", text)
clipboard.setPrimaryClip(clip)
}
(b). Our showToast()
function
Write the showToast()
function as follows:
private fun showToast(text: String){
Toast.makeText(this, text, Toast.LENGTH_LONG).show()
}
Here is the full code:
package replace_with_your_package_name
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import com.google.android.gms.tasks.OnCompleteListener
import com.google.firebase.messaging.FirebaseMessaging
import com.google.gson.Gson
import com.layon.sendpushnotificationfcm.utils.Constants.Companion.CONTENT_TYPE
import com.layon.sendpushnotificationfcm.databinding.ActivityMainBinding
import com.layon.sendpushnotificationfcm.model.Notification
import com.layon.sendpushnotificationfcm.model.NotificationData
import com.layon.sendpushnotificationfcm.model.PushNotification
import com.layon.sendpushnotificationfcm.repository.RetrofitInstance
import com.layon.sendpushnotificationfcm.utils.NotificationUtil
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
const val TAG = "layon.f"
const val TOPIC = "sendpushnotificationfcmtopic"
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private var serverKey : String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
//get the actual FCM token
FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task ->
if (!task.isSuccessful) {
Log.w(TAG, "Fetching FCM registration token failed", task.exception)
return@OnCompleteListener
}
val token = task.result
binding.textViewMyFCMToken.text = "$token"
})
FirebaseMessaging.getInstance().subscribeToTopic(TOPIC)
binding.button.setOnClickListener {
val title = binding.editTextTitle.text.toString()
val message = binding.editTextBody.text.toString()
val data = binding.editTextData.text.toString()
val showPopUp = binding.checkBoxShowPopUp.isChecked
val recipientToken = binding.editTextSendToken.text.toString()
serverKey = binding.editTextServerKey.text.toString()
if(title.isNotEmpty() && message.isNotEmpty()) {
if(serverKey.isNullOrBlank()) {
showToast("You was supposed to input the server_key")
}
if(recipientToken.isBlank()){
showToast("You was supposed to input the fcm token recipient")
}
PushNotification(
notification = Notification(title = title, body = message),
data = NotificationData(data = data, showPopUp = showPopUp),
to = recipientToken
).also {
sendNotification(it)
showToast("notification sent")
}
}
}
binding.copyImageView.setOnClickListener {
copy(binding.textViewMyFCMToken.text.toString())
showToast("fcm token copied")
}
//create the notification channel if not exists
NotificationUtil.createChannels(this)
}
private fun sendNotification(notification: PushNotification) =
CoroutineScope(Dispatchers.IO).launch {
try {
val response = RetrofitInstance.api.postNotification(
notification = notification,
serverKey = "key=$serverKey",
contentType = CONTENT_TYPE
)
if (response.isSuccessful) {
Log.d(TAG, "Response: ${Gson().toJson(response)}")
} else {
Log.e(TAG, response.errorBody().toString())
}
} catch (e: Exception) {
Log.e(TAG, e.toString())
}
}
private fun copy(text: String){
val clipboard: ClipboardManager =
getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
val clip = ClipData.newPlainText("copy", text)
clipboard.setPrimaryClip(clip)
}
private fun showToast(text: String){
Toast.makeText(this, text, Toast.LENGTH_LONG).show()
}
}
Reference
Download the code below:
No. | Link |
---|---|
1. | Download Full Code |
2. | Read more here. |
3. | Follow code author here. |
More
Here are some more examples related to FCM Push Notification.