Skip to main content
Supported on: Android SDK 1.0.33+
The AppDNA SDK provides a complete push notification module for registering device tokens via Firebase Cloud Messaging (FCM), handling notification delivery, and tracking user interactions.

Prerequisites

Before using push notifications, configure FCM for your app:
  1. Add google-services-appdna.json (or your project’s google-services.json) to your app/src/main/assets/ directory.
  2. Apply the com.google.gms.google-services Gradle plugin in your app module.
  3. Enable Firebase Cloud Messaging in the Firebase Console.
  4. Upload your FCM service account credentials (or legacy server key) to the AppDNA Console under Settings > Push > Android Configuration.
Push notifications will not be delivered to your users without google-services-appdna.json in your project AND FCM credentials uploaded to the AppDNA Console.

Request Permission

On Android 13+ (API 33), push notifications require the POST_NOTIFICATIONS runtime permission. Request it from a coroutine — requestPermission is a suspend function that uses the Activity Result API internally and returns a Boolean once the user responds:
import androidx.lifecycle.lifecycleScope

class MainActivity : androidx.activity.ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        lifecycleScope.launch {
            val granted = AppDNA.push.requestPermission(activity = this@MainActivity)
            Log.d("Push", "Permission granted: $granted")
        }
    }
}
The SDK handles the runtime prompt and updates internal permission state automatically — you do not need to override onRequestPermissionsResult or call setPushPermission afterwards. On API < 33 the call is a no-op and returns true.
The activity parameter must be a ComponentActivity (or subclass like AppCompatActivity / FragmentActivity). The Activity Result API the SDK uses requires ComponentActivity.
Java-friendly variant: AppDNA.push.requestPermissionFuture(activity): CompletableFuture<Boolean>.

Set Token Manually

Register the device push token when it is received from FCM. This is typically done in your FirebaseMessagingService:
import ai.appdna.sdk.AppDNA
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage

class MyFirebaseMessagingService : FirebaseMessagingService() {

    override fun onNewToken(token: String) {
        super.onNewToken(token)
        AppDNA.setPushToken(token)
    }

    override fun onMessageReceived(message: RemoteMessage) {
        super.onMessageReceived(message)
        // Handle message
    }
}
You can also use the alternative method name:
AppDNA.onNewPushToken(token)
Both setPushToken and onNewPushToken perform the same operation. The token registration payload sent to the backend includes: token, platform="android", device_id, app_version, sdk_version, and os_version.

Set Permission Status

Manually update the SDK with the current push permission status:
AppDNA.setPushPermission(granted = true)
On Android 13+ (API 33), push notifications require the POST_NOTIFICATIONS runtime permission. Call setPushPermission after the user responds to the permission request.

Track Delivery and Taps

Track when a push notification is delivered to the device:
AppDNA.trackPushDelivered(pushId = "push-123")
Track when a user taps on a push notification:
AppDNA.trackPushTapped(pushId = "push-123", action = "open_workout")
The action parameter is optional. Pass null if no specific action is associated with the tap.

Push Module

Access the push module directly for advanced usage:
val pushModule = AppDNA.push

PushModule Methods

Method / PropertySignatureDescription
tokentoken: String?The currently registered FCM device token
getTokengetToken(): String?Returns the current device token
setTokensetToken(token: String)Registers the push token with AppDNA backend
requestPermissionsuspend fun requestPermission(activity: Activity? = null): BooleanRequest POST_NOTIFICATIONS (Android 13+) via Activity Result API. Returns true once granted (or on API < 33). Requires a ComponentActivity to host the launcher.
requestPermissionFuturerequestPermissionFuture(activity: Activity?): CompletableFuture<Boolean>Java-friendly variant of requestPermission
trackDeliveredtrackDelivered(pushId: String)Track push delivery
trackTappedtrackTapped(pushId: String, action: String?)Track push tap with optional action
setDelegatesetDelegate(delegate: AppDNAPushDelegate?)Set a delegate for push lifecycle callbacks

AppDNAPushDelegate

All 3 methods on this delegate fire from the SDK’s push pipeline:
  • onPushTokenRegistered(token) — fires whenever the SDK registers a new FCM token (or detects a change). Token registration with the AppDNA backend continues regardless of whether you implement this method.
  • onPushReceived(notification, inForeground) — fires when a push arrives.
  • onPushTapped(notification, actionId) — fires when the user taps a notification or one of its action buttons.
Implement the AppDNAPushDelegate interface to receive push notification lifecycle callbacks:
interface AppDNAPushDelegate {
    fun onPushTokenRegistered(token: String)
    fun onPushReceived(notification: PushPayload, inForeground: Boolean)
    fun onPushTapped(notification: PushPayload, actionId: String?)
}

Example Implementation

import ai.appdna.sdk.AppDNAPushDelegate
import ai.appdna.sdk.PushPayload

class MyPushDelegate : AppDNAPushDelegate {

    override fun onPushTokenRegistered(token: String) {
        Log.d("Push", "Token registered: $token")
    }

    override fun onPushReceived(notification: PushPayload, inForeground: Boolean) {
        if (inForeground) {
            // Show in-app notification banner
            showBanner(title = notification.title, body = notification.body)
        }
    }

    override fun onPushTapped(notification: PushPayload, actionId: String?) {
        val action = notification.action
        if (action != null) {
            // Handle deep link or custom action
            handleAction(action)
        }
    }

    private fun showBanner(title: String, body: String) { /* ... */ }
    private fun handleAction(action: Any) { /* ... */ }
}

// Register the delegate
AppDNA.push.setDelegate(MyPushDelegate())

PushPayload

The PushPayload data class contains the notification content:
PropertyTypeDescription
pushIdStringUnique identifier for the notification
titleStringNotification title
bodyStringNotification body text
imageUrlString?URL to a rich notification image
dataMap<String, Any>?Custom data payload
actionPushAction?Action to perform when tapped

PushAction

The PushAction data class defines the action associated with a notification tap:
PropertyTypeDescription
typeStringAction type (e.g., "deep_link", "url", "screen")
valueStringAction value (e.g., a URL or screen identifier)

Auto-Tracked Events

The SDK automatically tracks the following push-related events:
EventTriggered When
push_token_registeredDevice token is successfully registered
push_permission_grantedUser grants push permission
push_permission_deniedUser denies push permission
push_deliveredA push notification is delivered
push_tappedUser taps on a push notification
Auto-tracked events are sent alongside any manually tracked events. You do not need to track these events yourself.

Full Example

import android.app.Application
import ai.appdna.sdk.AppDNA
import ai.appdna.sdk.Environment

class MyApplication : Application() {

    private val pushHandler = MyPushDelegate()

    override fun onCreate() {
        super.onCreate()
        AppDNA.configure(
            context = applicationContext,
            apiKey = "adn_live_xxx",
            environment = Environment.PRODUCTION,
        )

        AppDNA.push.setDelegate(pushHandler)
    }
}

// In MainActivity.onCreate(...):
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // Request POST_NOTIFICATIONS on Android 13+
    lifecycleScope.launch {
        AppDNA.push.requestPermission(activity = this@MainActivity)
    }
}
The SDK automatically handles token refresh. When FCM issues a new token via FirebaseMessagingService.onNewToken, call AppDNA.setPushToken(token) (or AppDNA.onNewPushToken(token)) to update registration with the AppDNA backend.

Next Steps