Implement actionable push notification for Android APP in Kotlin. Use Google Firebase for pushing notifications.

To create actionable notification in Android, server must send firebase notifications using Data messages type.

Create a receiver class

Handle actions in a BroadcastReceiver class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class NotificationActionReceiver : BroadcastReceiver() {

override fun onReceive(context: Context, intent: Intent) {

val notificationId = intent.getIntExtra("notificationId", 0)
val action = intent.getStringExtra("action")

if (action == "Action1"){
// Handle action1

}else if (action == "Action2"){
// Handle action2
}
val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
manager.cancel(notificationId)
}
}

Add the receiver class to the manifest

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.maochun.pushnotificationtest">
...
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<application
...>
...
<receiver android:name=".NotificationActionReceiver"></receiver>
</application>
</manifest>

Define actionable notification in FCM service class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
class FCMService : FirebaseMessagingService() {

override fun onMessageReceived(remoteMessage: RemoteMessage) {

// TODO(developer): Handle FCM messages here.
var type = 0
if (remoteMessage.data.isNotEmpty()) {
Log.d("TAG", "Message data payload: " + remoteMessage.data)
if (remoteMessage.data["type"] != null){
type = remoteMessage.data["type"]?.toInt() ?: 0
}
if (type == 3) {
val title = remoteMessage.data["title"] ?: "Test Action Notification"
val body = remoteMessage.data["body"] ?: ""

sendActionNotification(title, body)
}
}
...
}

private fun sendActionNotification(title: String, body: String) {
val notifID = System.currentTimeMillis().hashCode()

val button1Intent = Intent(this, NotificationActionReceiver::class.java)
button1Intent.putExtra("notificationId", notifID)
button1Intent.putExtra("action", "Action1")
val btn1PendingIntent = PendingIntent.getBroadcast(
this,
notifID,
button1Intent,
PendingIntent.FLAG_UPDATE_CURRENT
)

val button2Intent = Intent(this, NotificationActionReceiver::class.java)
button2Intent.putExtra("notificationId", notifID)
button2Intent.putExtra("action", "Action2")
val btn2PendingIntent = PendingIntent.getBroadcast(
this,
notifID,
button2Intent,
PendingIntent.FLAG_UPDATE_CURRENT
)

val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val notificationBuilder = NotificationCompat.Builder(this, "default")
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(title)
.setContentText(body)
.setSound(defaultSoundUri)
.addAction(R.drawable.common_alert_button, "Action1", btn1PendingIntent)
.addAction(R.drawable.common_alert_button, "Action2", btn2PendingIntent)
.setOngoing(true)

val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channelID = "pushnotificationtest";
val channel = this.createNotificationChannel(
notificationManager,
channelID,
channelID,
NotificationManager.IMPORTANCE_HIGH
)

channel.setShowBadge(false)
notificationManager?.createNotificationChannel(channel)
notificationBuilder.setChannelId(channelID)
}

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

@TargetApi(26)
private fun createNotificationChannel(
notificationManager: NotificationManager,
id: String,
name: String,
importance: Int
): NotificationChannel {
return if (notificationManager.getNotificationChannel(id) != null) {
notificationManager.getNotificationChannel(id)
} else {
val notificationChannel = NotificationChannel(id, name, importance)
notificationChannel.enableVibration(true)
notificationChannel.enableLights(true)
notificationChannel
}
}
}