Skip to main content
The AppDNA Flutter SDK provides a complete push notification module for registering device tokens, tracking delivery and taps, and handling notification interactions through delegates and streams.

Platform Setup

Before using push notifications, complete the platform-specific setup:

iOS

  1. In Xcode, enable the Push Notifications capability under your target’s Signing & Capabilities tab.
  2. Generate an APNs authentication key (.p8 file) in the Apple Developer Portal.
  3. Upload the .p8 key to the AppDNA Console under Settings > Push > iOS Configuration.

Android

  1. Set up Firebase Cloud Messaging (FCM) in your Android project.
  2. Add the google-services.json file to your android/app/ directory.
  3. Upload the FCM server key to the AppDNA Console under Settings > Push > Android Configuration.
Without the platform-specific credentials uploaded to the AppDNA Console, push notifications will not be delivered to your users.

Push Module

Access the push module through the AppDNA.push accessor, which returns an AppDNAPushModule instance:
final pushModule = AppDNA.push;

Request Permission

Request push notification permission from the user. This presents the system permission dialog and registers for remote notifications:
final granted = await AppDNA.push.requestPermission();

if (granted) {
  print("Push permission granted");
} else {
  print("Push permission denied");
}
The method returns a bool indicating whether the user granted permission.

Set Token Manually

If you handle token registration yourself (e.g., using firebase_messaging), pass the token string to the SDK:
await AppDNA.push.setToken("fcm-token-xxx");
Or via the static method:
await AppDNA.setPushToken("fcm-token-xxx");

Get Current Token

Retrieve the currently registered push token:
final token = await AppDNA.push.getToken();
if (token != null) {
  print("Current token: $token");
}
Returns String?null if no token has been registered.

Set Permission Status

Manually update the SDK with the current push permission status:
await AppDNA.push.setPermission(true);
Or via the static method:
await AppDNA.setPushPermission(true);

Track Delivery and Taps

Track when a push notification is delivered to the device:
await AppDNA.push.trackDelivered("push-123");
Track when a user taps on a push notification:
await AppDNA.push.trackTapped("push-123", action: "open_workout");
These are also available as static methods:
await AppDNA.trackPushDelivered("push-123");
await AppDNA.trackPushTapped("push-123", action: "open");

AppDNAPushDelegate

Implement the AppDNAPushDelegate abstract class to receive push notification lifecycle callbacks:
abstract class AppDNAPushDelegate {
  void onPushTokenRegistered(String token);
  void onPushReceived(Map<String, dynamic> notification, bool inForeground);
  void onPushTapped(Map<String, dynamic> notification, String? actionId);
}

Example Implementation

class MyPushHandler implements AppDNAPushDelegate {
  @override
  void onPushTokenRegistered(String token) {
    print("Token registered: $token");
  }

  @override
  void onPushReceived(Map<String, dynamic> notification, bool inForeground) {
    if (inForeground) {
      // Show in-app notification banner
      print("Received in foreground: ${notification['title']}");
    }
  }

  @override
  void onPushTapped(Map<String, dynamic> notification, String? actionId) {
    print("Push tapped, action: $actionId");
    // Handle deep link or custom action
  }
}

// Set the delegate
AppDNA.push.setDelegate(MyPushHandler());

Legacy Stream API

The SDK also provides a legacy stream-based API through the AppDNAPush class for backward compatibility:

Request Permission (Legacy)

final granted = await AppDNAPush.requestPermission();

Push Received Stream

Listen for incoming push notifications via the com.appdna.sdk/push_received EventChannel:
AppDNAPush.onPushReceived.listen((PushPayload payload) {
  print("Received: ${payload.title}");
});

Push Tapped Stream

Listen for push notification taps via the com.appdna.sdk/push_tapped EventChannel:
AppDNAPush.onPushTapped.listen((PushPayload payload) {
  print("Tapped: ${payload.pushId}");
  if (payload.actionValue != null) {
    // Navigate to the action target
  }
});

PushPayload

The PushPayload 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, dynamic>?Custom data payload
actionTypeString?Action type (e.g., “deep_link”, “url”)
actionValueString?Action value (e.g., a URL or screen ID)

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 'package:appdna_sdk/appdna_sdk.dart';

class MyPushHandler implements AppDNAPushDelegate {
  @override
  void onPushTokenRegistered(String token) {
    print("Token: $token");
  }

  @override
  void onPushReceived(Map<String, dynamic> notification, bool inForeground) {
    if (inForeground) {
      showInAppBanner(notification);
    }
  }

  @override
  void onPushTapped(Map<String, dynamic> notification, String? actionId) {
    navigateToContent(notification, actionId);
  }
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await AppDNA.configure(
    "adn_live_xxx",
    environment: AppDNAEnvironment.production,
  );

  // Set up push delegate
  AppDNA.push.setDelegate(MyPushHandler());

  // Request permission
  final granted = await AppDNA.push.requestPermission();
  print("Push permission: $granted");

  runApp(const MyApp());
}
Push notification behavior varies between iOS and Android. On iOS, the system permission dialog is shown on first request. On Android 13+, the POST_NOTIFICATIONS runtime permission is requested. The native SDKs handle these differences transparently.