Skip to main content

Notification Delegates

In Android 10 (API level 29), it is possible for an application to post notifications for another application. This is called using notification delegate.

Basic Usage​

Let's say we have 2 Android applications:

  1. App 1: com.hanmajid.app1
  2. App 2: com.hanmajid.app2

App 1 will set its notification delegate to App 2. This means that App 2 can post notifications through App 1's notification channel.

Setting Up App 2​

To do this, let's setup App 2 first. The first thing we want to do is add App 1's package name in <queries> tag inside AndroidManifest.xml file:

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

<application>
</application>

<queries>
<package android:name="com.hanmajid.app1" />
</queries>

</manifest>

This will allow App 2 to be aware of App 1's existence in user device.

The next thing to do is for App 2 to call canNotifyAsPackage() and notifyAsPackage() methods:

  1. canNotifyAsPackage() method will check whether App 2 is allowed to post notification to App 1.
  2. notifyAsPackage() method will post the actual notification to App 1.

Here, I have prepared a simple utility object to wrap the 2 methods:

NotificationDelegateUtil.kt
package com.hanmajid.app2

import android.app.NotificationManager
import android.content.Context
import android.os.Build
import android.util.Log
import androidx.core.app.NotificationCompat

/**
* Notification delegate-related utility object
*/
object NotificationDelegateUtil {

/**
* Post a dummy notification as [packageName] through [channelId].
*
* When an error occurred, it will log the exception to Logcat.
*/
fun postNotificationAsPackage(
context: Context,
packageName: String,
channelId: String,
): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val notificationManager = context.getSystemService(NotificationManager::class.java)
val canNotify = notificationManager.canNotifyAsPackage(packageName)
if (canNotify) {
try {
notificationManager.notifyAsPackage(
packageName,
null,
1,
NotificationCompat.Builder(context, channelId)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle("Ready for Upside Down Cake?")
.setContentText("Tap here to learn more about Android 14")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.build()
)
return true
} catch (e: Exception) {
Log.e("TAG", e.message, e)
return false
}
} else {
Log.e("TAG", "canNotify == false")
return false
}
} else {
Log.e("TAG", "API level < 29")
return false
}
}
}

Then we only need to call the method above somewhere. In this example, let's call this method in a button click callback:

package com.hanmajid.app2

import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.ui.Modifier
import com.hanmajid.app2.ui.theme.App2Theme

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
App2Theme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Column {
Text(text = "This is App 2!")
Button(onClick = {
val isSuccess = NotificationDelegateUtil.postNotificationAsPackage(
this@MainActivity,
"com.hanmajid.app1",
"channel-for-app2"
)
if (!isSuccess) {
Toast.makeText(
this@MainActivity,
"Failed to post notification. Read error in log",
Toast.LENGTH_LONG,
).show()
}
}) {
Text(text = "Notify to App 1")
}
}
}
}
}
}
}

Here's what App 2 should look like now:

Make sure to run App 2 at least once so that it's installed in your device.

Setting Up App 1​

Now, we need to setup App 1. The first thing we need is to add App 2's package name in <queries> tag inside AndroidManifest.xml file:

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

<application>
</application>

<queries>
<package android:name="com.hanmajid.app2" />
</queries>

</manifest>

This will allow App 1 to be aware of App 2's existence in user device.

The next thing we need to do is create a notification channel for App 2 to post their notifications. Somewhere in App 1, create the channel like this:

import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.os.Build

// Call this somewhere in the application
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationManager = context.getSystemService(NotificationManager::class.java)
val channelId = "channel-for-app2"
val name = "Notification Channel From App 2"
val channel = NotificationChannel(
channelId,
name,
NotificationManager.IMPORTANCE_DEFAULT,
)
notificationManager.createNotificationChannel(channel)
}

Notice that we use the same notification channel id (channel-for-app2) as defined in App 2. This will allow the two apps to communicate properly.

Lastly, we need to use the setNotificationDelegate() method to set App 2 as App 1's notification delegate:

import android.app.NotificationManager
import android.content.Context
import android.os.Build

// Call this somewhere in the application
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val packageName = "com.hanmajid.app2"
val notificationManager = context.getSystemService(NotificationManager::class.java)
notificationManager.notificationDelegate = packageName

val isSuccess = notificationManager.notificationDelegate == packageName
Log.i("TAG", "isSuccess: $isSuccess")
}

Make sure that the notification delegate is properly set by checking the value returned by getNotificationDelegate() method. If everything went correctly, the value should be "com.hanmajid.app2".

Putting It All Together​

Now that we have both App 1 and App 2 installed in our device, we can test the notification delegate by running App 2 and press the "Notify to App 1" button:

References​