Push Notifications

The StreamVideo SDK supports two types of push notifications: regular and VoIP notifications. You can use either or both depending on your use case.

Push notifications are sent in the following scenarios:

  • Ringing notifications: Sent when you create a call with the ringing value set to true. This triggers a VoIP notification to display a ringing screen.
  • Notify notifications: Sent when you create a call with the notify value set to true. These are regular push notifications.
  • Missed call notifications: Sent as a regular push notification if a call goes unanswered.

The handling of ringing (VoIP) notifications is explained here for Android and here for iOS. In this section, we focus on handling regular push notifications for notify and call.missed cases.

Whenever a notification is sent by the Stream Video backend, its payload will include a sender field set to stream.video. The type field in the payload can have one of the following values:

  • call.notification: Sent for notify notifications or other regular call notifications.
  • call.missed: Sent when a call is missed.
  • call.ring: Sent for ringing calls.

Android and Firebase Cloud Messaging (FCM)

In a high-level widget within your app, add the following code to listen for FCM messages:

@override
void initState() {
  ...
  _observeFcmMessages()
}

Future<bool> _handleRemoteMessage(RemoteMessage message) async {
  final payload = message.data;

  final sender = payload['sender'] as String?;
  final type = payload['type'] as String?;

  if (sender == 'stream.video' && type == 'call.notification') {
    final callCid = payload['call_cid'] as String?;
    // Show notification, for example using `flutter_local_notifications` package
  }
}

_observeFcmMessages() {
  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
  _fcmSubscription = FirebaseMessaging.onMessage.listen(_handleRemoteMessage);
}

You can handle call.missed notifications similarly to call.notification by showing a local notification. By default, the SDK handles this automatically. You can configure this behavior through the pushParams parameter when initializing StreamVideo:

StreamVideo(
  apiKey,
  user: user,
  pushNotificationManagerProvider: StreamVideoPushNotificationManager.create(
    ...,
    pushParams: const StreamVideoPushParams(
      appName: kAppName,
      ios: IOSParams(iconName: 'IconMask'),
      // Configure missed call notification here
      missedCallNotification: NotificationParams(
        showNotification: true,
        subtitle: 'Missed Call',
        callbackText: 'Call Back',
      )
    ),
  ),
);

iOS and Apple Push Notification Service (APNs)

For iOS, standard push notifications must be handled separately from VoIP notifications. When an APNs push provider is registered for iOS, the SDK sends both VoIP and standard push notifications through APNs.

Registering APN device token

Since the APNs device token is separate from the VoIP token, it must be registered explicitly. Enable this by setting registerApnDeviceToken to true when initializing the StreamVideo instance:

StreamVideo(
  apiKey,
  user: user,
  pushNotificationManagerProvider: StreamVideoPushNotificationManager.create(
    ...,
    registerApnDeviceToken: true, // <--- Add this line
  ),
);

Handling standard push notifications

To handle push notifications in your iOS app, add the following code to your AppDelegate.swift file:

@objc class AppDelegate: FlutterAppDelegate {
  override func application(
          _ application: UIApplication,
          didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
      ) -> Bool {
          GeneratedPluginRegistrant.register(with: self)

          UNUserNotificationCenter.current().delegate = self // <--- Add this line to handle standard push notifications

          return super.application(application, didFinishLaunchingWithOptions: launchOptions)
      }

  // This method will be called when notification is received
  override func userNotificationCenter(_ center: UNUserNotificationCenter,
                                      willPresent notification: UNNotification,
                                      withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    let streamDict = notification.request.content.userInfo["stream"] as? [String: Any]
    if(streamDict?["sender"] as? String != "stream.video") {
        return completionHandler([])
    }

    if #available(iOS 14.0, *) {
        completionHandler([.list, .banner, .sound])
    } else {
        completionHandler([.alert])
    }
  }
}

To handle notification tap events (e.g., navigating to the call screen upon a notify notification), include this code in AppDelegate.swift:

// This method will be called when notification is tapped
override func userNotificationCenter(_ center: UNUserNotificationCenter,
                                      didReceive response: UNNotificationResponse,
                                      withCompletionHandler completionHandler: @escaping () -> Void) {

    let streamDict = response.notification.request.content.userInfo["stream"] as? [String: Any]
    if(streamDict?["sender"] as? String != "stream.video") {
        return;
    }

    if(streamDict?["type"] as? String == "call.notification") {
        let callCid = streamDict?["call_cid"] as? String
        print("Call notification received with call cid: \(callCid)")
        //Navigate to call, for example implementing method channel
    }

    completionHandler()
}

If you want to customize the content of the push notification, consider implementing a Notification Service Extension.

Push notification permission

Remember, that in order to receive push notifications, you need to ask the user for relevant permission. One way of doing it is using permission_handler plugin.

Permission.notification.request();

Registering Devices

If you want to disable this default behavior and manage device registration yourself, set registerPushDevice to false during connection:

Once you configure a push provider and set it up on the Stream dashboard, a device that is supposed to receive push notifications needs to be registered on the Stream backend.

Device registration is carried out in the SDK every time a user connects and does not need to be implemented in your app. Subscription to token change events is also created and new token is registered when needed. Similarly unregistering token is done automatically when disconnect() method is called on StreamVideo instance.

If you want to disable this default behavior and manage device registration yourself, set registerPushDevice to false during connection:

StreamVideo.instance.connect(registerPushDevice: false);

Registering device manually

If you want to manually register the device you can do it by calling addDevice() method of StreamVideo instance:

StreamVideo.instance.addDevice(
  pushProvider: PushProvider.apn,
  pushProviderName: '{PROVIDER_NAME}',
  pushToken: '{TOKEN}',
  voipToken: true,
);

Removing registered device

To remove the already registered device, and stop receiving push notifications to it, simply call removeDevice() method:

StreamVideo.instance.removeDevice(
  pushToken: '{TOKEN}',
);

Listing devices

You can list devices registered to the current user with the getDevices() method:

let devices = await StreamVideo.instance.getDevices();

This method returns an list of the PushDevice type, that contains information about the device:

/** Date/time of creation */
DateTime createdAt;
/** Whether device is disabled or not */
bool? disabled;
/** Reason explaining why device had been disabled */
String? disabledReason;
String pushToken;
PushProvider pushProvider;
String? pushProviderName;

Deep linking

When a push notification is tapped, you can provide a deep linking mechanism in your app to join a call. You can find more details how to do that in the following page.

© Getstream.io, Inc. All Rights Reserved.