Push Notifications for iOS

By setting up push notification service to your app, the app users can receive messages even when they are offline. Typically, the users can receive push notifications after their app goes into the background. SendBird SDK automatically detects if your app enters the background and updates the user's connection status to Disconnected. Therefore, in normal cases, you do not have to call disconnect explicitly.

Note: Push notifications are only supported in the Group Channel. The SDK does not provide an option to receive push notifications from Open Channel.

Follow these 4 steps to send push notifications to users of your iOS application.

  1. Create a Certificate Signing Request(CSR).
  2. Create a Push Notification SSL certificate in Apple Developer site.
  3. Export a p12 file and upload it to SendBird Dashboard.
  4. Register a device token in SendBird SDK and parse SendBird APNS messages.

Step 1: Create a Certificate Signing Request(CSR)

Open Keychain Access on your Mac (Applications -> Utilities -> Keychain Access). Select Request a Certificate From a Certificate Authority.

CSR1

In the Certificate Information window, do the following:

  • In the User Email Address field, enter your email address.
  • In the Common Name field, create a name for your private key (for example, John Doe Dev Key).
  • The CA Email Address field must be left empty.
  • In the Request is group, select the Saved to disk option.

CSR2


Step 2: Create a Push Notification SSL certificate

Log in to the Apple Developer Member Center and find the Certificates, Identifiers & Profiles menu. Select App IDs, find your target application, and click the Edit button.

App IDs

Turn on Push Notifications and create a development or production certificate to fit your purpose.

Push Certificate

Upload the CSR file that you created in section (1) to complete this process. After doing so, download a SSL certificate.

Double-click the file and register it to your login keychain.

Push Certificate2


Step 3: Export a p12 file and upload it to SendBird Dashboard.

Under Keychain Access, click the Certificates category from the left menu. Find the Push SSL certificate you just registered and right-click it without expanding the certificate. Then select Export to save the file to your disk.

P12 export1

When keychain asks you for a password, just leave it empty.

Note: It is very important that your p12 has no password.

P12 export2

Then, log in to the SendBird Dashboard and upload your p12 file to the Push Notification section, under Settings.

Set Push Information

Note: Alternatively, you can register certificates via the Platform API.


Step 4: Register and unregister a device token in SendBird SDK

In your app's AppDelegate, store your device token as a variable.

// AppDelegate.m
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken {
    // ...

    // Save devToken to your own global variable.
    [SBDMain registerDevicePushToken:DEVICE_TOKEN unique:YES completionHandler:^(SBDPushTokenRegistrationStatus status, SBDError * _Nullable error) {
        if (error == nil) {
            if (status == SBDPushTokenRegistrationStatusPending) {
                // Registration is pending.
                // If you get this status, invoke `+ registerDevicePushToken:unique:completionHandler:` with `[SBDMain getPendingPushToken]` after connection.
            }
            else {
                // Registration succeeded.
            }
        }
        else {
            // Registration failed.
        }
    }];
// AppDelegate.swift
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    SBDMain.registerDevicePushToken(DEVICE_TOKEN, unique: true) { (status, error) in
        if error == nil {
            if status == SBDPushTokenRegistrationStatus.pending {
                // Registration is pending.
                // If you get this status, invoke `+ registerDevicePushToken:unique:completionHandler:` with `[SBDMain getPendingPushToken]` after connection.
            }
            else {
                // Registration succeeded.
            }
        }
        else {
            // Registration failed.
        }
    }
}

Note: If your token registration status is pending, this means that your user has not yet connected when you had attempted to register the device token. In this case, register a completionHandler after your user has successfully connected to store the pending token. To do this, invoke registerDevicePushToken:unique:completionHandler: in a callback of connectWithUserId:completionHandler: or connectWithUserId:accessToken:completionHandler: of SBDMain.

[SBDMain connectWithUserId:USER_ID completionHandler:^(SBDUser * _Nullable user, SBDError * _Nullable error) {
    if (error == nil) {
        [SBDMain registerDevicePushToken:[SBDMain getPendingPushToken] unique:YES completionHandler:^(SBDPushTokenRegistrationStatus status, SBDError * _Nullable error) {

        }];
    }
}];
SBDMain.connect(withUserId: USER_ID, completionHandler: { (user, error) in 
    if error == nil {
        SBDMain.registerDevicePushToken(SBDMain.getPendingPushToken()!, unique: true, completionHandler: { (status, error) in

        })
    }
})

Don't forget to call the following code in the appropriate place to receive permissions from your users.

if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
   UIUserNotificationSettings* notificationSettings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
   [[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
   [[UIApplication sharedApplication] registerForRemoteNotifications];
} else {
   [[UIApplication sharedApplication] registerForRemoteNotificationTypes: (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
}
let notificationSettings = UIUserNotificationSettings(types: [UIUserNotificationType.alert, UIUserNotificationType.badge, UIUserNotificationType.sound], categories: nil)
        UIApplication.shared.registerUserNotificationSettings(notificationSettings)
        UIApplication.shared.registerForRemoteNotifications()

SendBird APNS push notifications are sent with the following options.

  • alert: "{Sender Nickname}: {Text Message}"
  • sound: default
  • badge: total unread message count of each user (you can disable the badge count from the SendBird Dashboard.)

SendBird also sends an additional payload with a sendbird key. You can parse the payload within didReceiveRemoteNotification: method and use it to handle user reactions.

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler{

    NSString *alertMsg = [[userInfo objectForKey:@"aps"] objectForKey:@"alert"];
    NSDictionary *payload = [userInfo objectForKey:@"sendbird"];

      // Your custom way to parse data
    completionHandler(UIBackgroundFetchResultNewData);
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    let alertMsg = (userInfo["aps"] as! NSDictionary)["alert"] as! NSDictionary
    let payload = userInfo["sendbird"] as! NSDictionary

    // Your custom way to parse data
    completionHandler(UIBackgroundFetchResult.newData)
}

Here is the complete format of each payload.

{
  category: "messaging:offline_notification",
  type: string,              // Message Type, User or File or Admin
  message: string,           // User input message
  data: string,              // Custom data field
  app_id : string,           // application_id
  unread_message_count : int // Total unread count of the user
  channel: {
    channel_url: string,     // Group channel URL
    name: string,            // Group channel name
  },
  channel_type: string,      // messaging, group_messaging, chat
  sender: {
    id: string,              // Sender's unique ID
    name: string,            // Sender's nickname
    profile_url: string      // Sender's profile image url
  },
  recipient: {
    id: string,              // Recipient's unique ID
    name: string,            // Recipient's nickname
  },
  files: [],  // If a message is a file link, this array represents files
  translations: {} // If a message has translations, this dict has locale:translation.
}

Notification preferences

Push notifications can be turned on or off. When turning notifications off for a specific user, call the following methods:

  • Objective-C: registerDevicePushToken:unique:completionHandler:, unregisterPushToken:completionHandler: and unregisterAllPushTokenWithCompletionHandler:

    Note: Call the above methods after the user has established connection with SendBird through connectionWithUserId:completionHandler: or connectionWithUserId:accessToken:completionHandler:.

  • Swift: registerDevicePushToken(_ devToken: Data, unique: Bool, completionHandler: ((SBDPushTokenRegistrationStatus, SBDError?) -> Swift.Void)?, unregisterPushToken(devToken: Data, completionHandler: (([AnyHashable : Any]?, SBDError?) -> Void)?) and unregisterAllPushToken(completionHandler: (([AnyHashable : Any]?, SBDError?) -> Void)?)

    Note: Call the above methods after the user has established connection with SendBird through connect(withUserId: String, completionHandler: ((SBDUser?, SBDError?) -> Void)?) or connect(withUserId: String, accessToken: String?, completionHandler: ((SBDUser?, SBDError?) -> Void)?).

- (void)setPushNotification:(BOOL)enable {
    if (enable) {
        [SBDMain registerDevicePushToken:[SBDMain getPendingPushToken] unique:YES completionHandler:^(SBDPushTokenRegistrationStatus status, SBDError * _Nullable error) {
            if (error != nil) {    // Error.
                return;
            }
        }];
    }
    else {
        // If you want to unregister the current device only, invoke this method.
        [SBDMain unregisterPushToken:[SBDMain getPendingPushToken] completionHandler:^(NSDictionary * _Nullable response, SBDError * _Nullable error) {
            if (error != nil) { // Error.
                return;
            }
        }];

        // If you want to unregister the all devices of the user, invoke this method.
        [SBDMain unregisterAllPushTokenWithCompletionHandler:^(NSDictionary * _Nullable response, SBDError * _Nullable error) {
            if (error != nil) { // Error.
                return;
            }
        }];
    }
}
func setPushNotification(enable: Bool) {
    if enable {
        SBDMain.registerDevicePushToken(SBDMain.getPendingPushToken()!, unique: true, completionHandler: { (status, error) in
            if error != nil { // Error.
                return
            }
        })
    }
    else {
        // If you want to unregister the current device only, invoke this method.
        SBDMain.unregisterPushToken(SBDMain.getPendingPushToken()!, completionHandler: { (response, error) in
            if error != nil { // Error.
                return
            }
        })

        // If you want to unregister the all devices of the user, invoke this method.
        SBDMain.unregisterAllPushToken(completionHandler: { (response, error) in
            if error != nil { // Error.
                return
            }
        })
    }
}

You can also change push notification settings for a specific group channel.

// If you want to turn push notification for this channel on, set this `YES`.
[channel setPushPreferenceWithPushOn:YES_OR_NO completionHandler:^(SBDError * _Nullable error) {
    if (error != nil) { // Error.
        return;
    }
}];
// If you want to turn push notification for this channel on, set this `true`.
channel.setPushPreferenceWithPushOn(true_or_false) { (error) in
    if error != nil { // Error.
        return
    }
}

If you want to snooze alerts (notifications) for some periods, use setDoNotDisturb.

// The current logged-in user doesn't receive push notifications during the specified time.
[SBDMain setDoNotDisturbWithEnable:YES_OR_NO startHour:START_HOUR startMin:START_MIN endHour:END_HOUR endMin:END_MIN timezone:TIMEZONE completionHandler:^(SBDError * _Nullable error) {
    if (error != nil) { // Error.
        return;
    }
}];
// The current logged-in user doesn't receive push notifications during the specified time.
SBDMain.setDoNotDisturbWithEnable(true_or_false, startHour: START_HOUR, startMin: START_MIN, endHour: END_HOUR, endMin: END_MIN, timezone: TIMEZONE) { (error) in
    if error != nil { // Error.
        return
    }    
}

Push notification message templates

Message templates define how a message is displayed when a push notification arrives to a user's device. You can choose between the default template and the alternative template, both of which are customizable.

Message templates

Text message File message
Default template {sender_name}: {message} (for example, John: Hello!) {filename} (for example, squirrel.jpg)
Alternative template New message arrived New file arrived

{sender_name}, {message}, and {filename} represent the corresponding string values. Use these fields to customize message templates from Dashboard Settings. The option is under Notifications > Push Notification Message Templates.

To determine whether a user receives messages in the form of the default template or the alternative template, use SBDMain setPushTemplateWithName:completionHandler:. The setPushTemplateWithName has two possible values: SBD_PUSH_TEMPLATE_DEFAULT, or SBD_PUSH_TEMPLATE_ALTERNATIVE.

[SBDMain setPushTemplateWithName:SBD_PUSH_TEMPLATE_ALTERNATIVE completionHandler:^(SBDError * _Nullable error) {
    if (error != nil) { // Error.
        return;
    }

    // Push template successfully set to SBD_PUSH_TEMPLATE_ALTERNATIVE.
}];
SBDMain.setPushTemplateWithName(SBD_PUSH_TEMPLATE_ALTERNATIVE) { (error) in
    if error != nil { // Error.
        return
    }

    // Push template successfully set to SBD_PUSH_TEMPLATE_ALTERNATIVE.
}

Note: The default configuration is SBD_PUSH_TEMPLATE_DEFAULT.

You can check your current setting with SBDMain getPushTemplateWithCompletionHandler:.

[SBDMain getPushTemplateWithCompletionHandler:^(NSString * _Nullable name, SBDError * _Nullable error) {
    if (error != nil) { // Error.
        return;
    }

    if ([name isEqualToString:SBD_PUSH_TEMPLATE_DEFAULT]) {
        // Currently configured to use the default template.
    }
    else if ([name isEqualToString:SBD_PUSH_TEMPLATE_ALTERNATIVE]) {
        // Currently configured to use the alternative template.
    }
}];
SBDMain.getPushTemplate { (name, error) in
    if error != nil { // Error.
        return
    }

    if name == SBD_PUSH_TEMPLATE_DEFAULT {
        // Currently configured to use the default template.
    }
    else if name == SBD_PUSH_TEMPLATE_ALTERNATIVE {
        // Currently configured to use the alternative template.
    }
}