Notification Events

Learn how to listen for push received events, notification responses, and implement background message handling.

The Airship SDK provides event streams to listen for push notifications and user interactions. These callbacks allow you to perform custom processing, navigate to specific content, or update your app’s state.

Listen for Push Received Events

The onPushReceived stream fires when a push notification is received while your app is in the foreground or background:

import 'dart:async';
import 'package:airship_flutter/airship_flutter.dart';

StreamSubscription? _pushSubscription;

@override
void initState() {
  super.initState();
  
  // Listen for push notifications
  _pushSubscription = Airship.push.onPushReceived.listen((event) {
    print('Push received:');
    print('Alert: ${event.pushPayload.alert}');
    print('Extras: ${event.pushPayload.extras}');
    
    // Handle the push notification
    // e.g., show an in-app banner, update UI, etc.
  });
}

@override
void dispose() {
  _pushSubscription?.cancel();
  super.dispose();
}
 Note

Android: The onPushReceived listener is not called when the app is terminated. For terminated app states on Android, use the background message handler instead.

Listen for Notification Responses

The onNotificationResponse stream fires when a user interacts with a notification (taps it, taps an action button, or dismisses it):

StreamSubscription? _responseSubscription;

@override
void initState() {
  super.initState();
  
  // Listen for notification interactions
  _responseSubscription = Airship.push.onNotificationResponse.listen((event) {
    print('Notification tapped:');
    print('Action ID: ${event.actionId}'); // null for default tap
    print('Alert: ${event.pushPayload.alert}');
    
    // Navigate to specific content based on the push
    if (event.pushPayload.extras['deep_link'] != null) {
      String deepLink = event.pushPayload.extras['deep_link'];
      _navigateToDeepLink(deepLink);
    }
  });
}

void _navigateToDeepLink(String deepLink) {
  // Navigate to the appropriate screen
  Navigator.pushNamed(context, deepLink);
}

@override
void dispose() {
  _responseSubscription?.cancel();
  super.dispose();
}

Listen for Notification Status Changes

Monitor changes to the notification status:

StreamSubscription? _statusSubscription;

@override
void initState() {
  super.initState();
  
  _statusSubscription = Airship.push.onNotificationStatusChanged.listen((event) {
    print('Notification status changed:');
    print('Opted in: ${event.status.isOptedIn}');
    print('System allowed: ${event.status.areNotificationsAllowed}');
  });
}

@override
void dispose() {
  _statusSubscription?.cancel();
  super.dispose();
}

Complete Example

Here’s a complete example showing how to handle both push received and notification response events:

import 'package:flutter/material.dart';
import 'package:airship_flutter/airship_flutter.dart';
import 'dart:async';

class NotificationHandler extends StatefulWidget {
  @override
  _NotificationHandlerState createState() => _NotificationHandlerState();
}

class _NotificationHandlerState extends State<NotificationHandler> {
  StreamSubscription? _pushSubscription;
  StreamSubscription? _responseSubscription;
  String _lastNotification = 'No notifications yet';

  @override
  void initState() {
    super.initState();
    _setupNotificationListeners();
  }

  void _setupNotificationListeners() {
    // Handle push received (foreground/background)
    _pushSubscription = Airship.push.onPushReceived.listen((event) {
      setState(() {
        _lastNotification = 'Received: ${event.pushPayload.alert ?? "No alert"}';
      });
      
      // Show an in-app notification
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text(event.pushPayload.alert ?? 'New notification')),
      );
    });

    // Handle notification interaction
    _responseSubscription = Airship.push.onNotificationResponse.listen((event) {
      setState(() {
        _lastNotification = 'Tapped: ${event.pushPayload.alert ?? "No alert"}';
      });

      // Handle deep links or custom actions
      Map<String, dynamic> extras = event.pushPayload.extras;
      
      if (extras.containsKey('screen')) {
        Navigator.pushNamed(context, extras['screen']);
      } else if (extras.containsKey('url')) {
        // Open URL with url_launcher package
        // launch(extras['url']);
      }
    });
  }

  @override
  void dispose() {
    _pushSubscription?.cancel();
    _responseSubscription?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Notifications')),
      body: Center(
        child: Text(_lastNotification),
      ),
    );
  }
}

Android Background Message Handler

For Android, you must set up a background message handler to receive push notifications when the app is completely terminated (not running in the foreground or background).

import 'package:flutter/material.dart';
import 'package:airship_flutter/airship_flutter.dart';

// Background message handler (must be a top-level function)
Future<void> backgroundMessageHandler(PushReceivedEvent event) async {
  print('Received background push:');
  print('Alert: ${event.pushPayload.alert}');
  print('Extras: ${event.pushPayload.extras}');
  
  // Perform background work
  // Note: Keep this lightweight and fast
  // Avoid UI operations or heavy processing
}

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  
  // Register the background message handler (Android only)
  Airship.push.android.setBackgroundPushReceivedHandler(backgroundMessageHandler);
  
  // Initialize Airship
  var config = AirshipConfig(
    defaultEnvironment: ConfigEnvironment(
      appKey: "YOUR_APP_KEY",
      appSecret: "YOUR_APP_SECRET"
    ),
    site: Site.us,
  );
  Airship.takeOff(config);
  
  runApp(MyApp());
}
 Important

Background handler requirements:

  • Must be a top-level function (not a class method)
  • Should complete quickly (within a few seconds)
  • Avoid UI operations or long-running tasks
  • Cannot access BuildContext or app state directly
  • Only applies to Android (iOS handles background notifications differently)

Working with Push Payloads

The PushPayload object contains all notification data:

Airship.push.onNotificationResponse.listen((event) {
  PushPayload payload = event.pushPayload;
  
  // Standard fields
  print('Alert: ${payload.alert}');
  print('Title: ${payload.title}');
  print('Subtitle: ${payload.subtitle}');
  print('Notification ID: ${payload.notificationId}');
  
  // Custom data
  Map<String, dynamic> extras = payload.extras;
  if (extras.containsKey('product_id')) {
    String productId = extras['product_id'];
    // Navigate to product details
  }
});