Push notifications

The Layer Push Notification Service can be used to keep your app’s data updated.

Setting up push with Layer

If you don’t already have a .p12 certificate for push, you’ll have to generate them first:

Common mistake

There are two types of push notifications — Development and Production. You will see both types in the Apple Developer Portal. Make sure to generate the right kind.

If your app is using your staging Layer ID, you’ll want a Development push certificate. If your app is using your production Layer ID, you’ll want a Production push certificate.

If your app isn’t receiving push notifications, 90% of the time it’s because you’ve mixed up your certificate type and app type, or because you uploaded the same certificate for both your staging and production apps.

Enable push notifications from Apple

Navigate to the Apple Developer Portal and Log In. Select Certificates, Identifiers, & Profiles on the right side of the page.

image alt text

Click Identifiers in the iOS Apps section on the left side of the window.

image alt text

Select the App ID for your application and you will see a drop-down menu.

image alt text

Note

Wildcard app IDs don’t support push notifications. Make sure your app ID isn’t a wildcard ID (make sure it doesn’t have an asterisk in it).

Scroll down to the Push Notification line item. If your application is already enabled for push notifications, the dots next to Enabled will be green. If they are gray, you must enable your application to support push notification. Select the Edit at the bottom of the drop-down menu.

image alt text

Scroll down to Push Notifications section and click the checkbox to enable.

image alt text

Once your application is enabled for push notifications, you will need to generate both a Production SSL Certificate and a Development SSL Certificate and upload them to Apple. To do so, you must first create a Certificate Signing Request (CSR) for both.

Note

We currently do not support the new APS certificate type. Make sure to select the classic APNS type when generating certificates.

Keep the Apple Developer window open as you will need to return here to upload your CSRs.

Create A Signing Request

Open the Keychain Access application on your Mac. This can be found in Applications → Utilities, or by searching via Spotlight.

image alt text

Once in Keychain Access, navigate to Keychain Access → Certificate Assistant → Request a Certificate From a Certificate Authority

image alt text

In the Certificate Information window, enter the following information. The select Continue:

* In the `User Email Address` field, enter your email address.
* In the `Common Name` field, create a name for your private key (e.g., app-key).
* The `CA Email Address` field should be left empty.
* In the "Request is" group, select the `Saved to disk` option.

image alt text

You will be prompted save the certificate. Give your certificate a name and save it to your desktop.

image alt text

Note

You have create separate CSRs for Production and Development certificates. Follow these steps again to create a second certificate.

Upload the Signing Request

Navigate back to the Apple Developer Portal and select Create Certificate in the Development SSL Certificate section.

image alt text

As you have already created a signing request, you can click on the Continue button in the following window.

image alt text

Click on Choose File to select your certificate from your desktop and upload. Once uploaded, click the Generate button to generate your development SSL Certificate.

image alt text

Click the Download button to download your certificate to your computer, then click Done.

image alt text

Once your certificate is downloaded, double click on the certificate to automatically add it to your Keychain.

Export Certificate from Keychain

Open up the Keychain Access application and locate your certificate. Right click on the certificate and select “Export “YOUR_CERTIFICATE_NAME”.

image alt text

Save the certificate to your desktop as layer-dev-cert.

image alt text

You will be prompted to enter a password. Remember this password as you will need to provide it to Layer when you upload your certificate.

image alt text

You will then be asked to enter the admin password for your computer to complete the export process.

image alt text

Creating/Refreshing a Provisioning Profile

  1. Navigate back to the Apple Developer Portal. Select Provisioning Profiles.
  2. Click on the + button in the upper right corner to create a new provisioning profile.
  3. If you have already created a Provisioning Profile in the past you will need to refresh it once you’ve created your Push Certificate.

Upload Your Certificate to Layer

Note

Layer supports both Developent and Production push notifications. We will automatically detect the type of certificate you’ve uploaded and use the correct one when sending notifications.

Navigate to the Layer Developer Dashboard and login with your credentials. Select the application for which you would like to upload certificates from the Projects drop-down menu. Click on the “Push” section of the left hand navigation.

image alt text

Click on the Configure for iOS button.

image alt text

You will be presented with a tutorial. Click on Upload Certificate to skip the tutorial. Next, click on the Choose File button and select the certificate you saved to your desktop.

image alt text

You will also be prompted by Layer to input your certificate password. This is the same password you chose when you exported your certificate from the Keychain Access application. This field is optional and is only required if you have a password on your .p12 file.

Common mistake

There are two types of push notifications — Development and Production. If your app is using your staging Layer ID, you’ll need to upload a Development push certificate. If your app is using your production Layer ID, you’ll need to upload a Production push certificate.

If your app isn’t receiving push notifications, 90% of the time it’s because you’ve mixed up your certificate type and app type, or because you uploaded the same certificate for both your staging and production apps.

Enable push notifications in your app

Now that you have successfully uploaded your Apple Push Notification certificate to Layer, it is time to configure your application to support push notifications in XCode. Open your application in XCode and navigate to Project Settings → your application Target → Capabilities.

Expand the section titled “Background Modes”.

If the “Background Modes” on/off switch is toggled to “off”, make sure you toggle it to “ON”. Select the radio buttons next to “Background Fetch” and “Remote Notifications”. This will add the necessary background modes to your application’s Info.plist.

image alt text

Registering your app to receive notifications

Your application must register to receive remote notifications. To support device registration for both iOS 7 and iOS 8, your application must implement the following. We recommend you do this in application:didFinishLaunchingWithOptions.

// Checking if app is running iOS 8
if ([application respondsToSelector:@selector(registerForRemoteNotifications)]) {
  // Register device for iOS8
  UIUserNotificationSettings *notificationSettings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
  [application registerUserNotificationSettings:notificationSettings];
  [application registerForRemoteNotifications];
} else {
  // Register device for iOS7
  [application registerForRemoteNotificationTypes:UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound];
}

Your AppDelegate will be notified when your application has successfully registered with Apple’s Push Notification service via the UIApplicationDelegate method. This method will provide a device token which must then be submitted to Layer. Copy and paste the following code into your AppDelegate.

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
  NSError *error;
  BOOL success = [self.applicationController.layerClient updateRemoteNotificationDeviceToken:deviceToken error:&error];
  if (success) {
    NSLog(@"Application did register for remote notifications");
  } else {
    NSLog(@"Error updating Layer device token for push:%@", error);
  }
}

Note

The device push token can change, even on the same device and with the same user. Make sure to update Layer when you get a new device token by implementing the application:didRegisterForRemoteNotificationsWithDeviceToken: method.

Disabling push for the current user

To disable Layer push notifications for the current app, you can update Layer with a nil device token:

[self.applicationController.layerClient updateRemoteNotificationDeviceToken:nil error:&error];

This will disable push notifications across all conversations to the current device.

Sending push notifications

By default, Layer will deliver silent push notifications. These notifications do not trigger any banners or alerts. Furthermore, iOS does not guarantee when they will be delivered; they may not be received for many minutes after they’ve been sent.

However, when you send a message you can configure notifications so that they will immediately show up for recipients. The contents of a notification are defined with each message that gets sent, using the LYRPushNotificationConfiguration of LYRMessageOptions:

// Create a message with a string of text
NSString *messageText = @"Hi how are you?"
LYRMessagePart *part = [LYRMessagePart messagePartWithText:messageText];

// Configure the push notification text to be the same as the message text
LYRPushNotificationConfiguration *defaultConfiguration = [LYRPushNotificationConfiguration new];
defaultConfiguration.alert = messageText;
defaultConfiguration.sound = @"layerbell.caf";

LYRMessageOptions *messageOptions = [LYRMessageOptions new];
messageOptions.pushNotificationConfiguration = defaultConfiguration;

LYRMessage *message = [layerClient newMessageWithParts:@[part] options:messageOptions error:nil];

//Sends the specified message
NSError *error = nil;
BOOL success = [conversation sendMessage:message error:&error];
if (success) {
  NSLog(@"Message enqueued for delivery");
} else {
  NSLog(@"Message send failed with error: %@", error);
}

If your message is created with nil options, the notification will be silent.

User-specific notifications

You can use setPushConfiguration method of LYRPushNotificationConfiguration to specify user-specific messages.

// Push message for User 1
LYRPushNotificationConfiguration *user1PushConfiguration = [LYRPushNotificationConfiguration new];
user1PushConfiguration.title = @"hey user1";
user1PushConfiguration.alert = @"alert";
user1PushConfiguration.sound = @"sound.caff";

// Push message for User 2
LYRPushNotificationConfiguration *user2PushConfiguration = [LYRPushNotificationConfiguration new];
user2PushConfiguration.title = @"hey user2";
user2PushConfiguration.alert = @"alert";
user2PushConfiguration.sound = @"sound.caff";

// Only User 1 and User 2 will get a push. Everyone else will get the message without a Push notification.
LYRPushNotificationConfiguration *configuration = [LYRPushNotificationConfiguration new];
[configuration setPushConfiguration:user1PushConfiguration forParticipant:@"user1"];
[configuration setPushConfiguration:user2PushConfiguration forParticipant:@"user2"];

LYRMessageOptions *messageOptions = [LYRMessageOptions new];
messageOptions.pushNotificationConfiguration = configuration;

LYRMessage *message = [self.layerClient newMessageWithParts:@[messagePart] options:messageOptions error:nil];

Silent notifications

Silent notifications are not reliable — it may seem like they are not being delivered. We’ve done extensive testing on silent notifications internally with various combinations of sound, alert, and content-available flags. The result is that there is no way to guarantee that iOS will wake the app and present the contents of a silent notification.

We believe this is because of how iOS handles power management. For example, if you start charging the device, it will get woken on every push. When it’s not plugged in, it is unpredictable when or if the app will be awakened.

If you want reliable, immediate delivery of push notifications, make sure to set the push configuration options and enable the “Show unread in badges” feature in the dashboard.

Common mistake

An anti-pattern we sometimes see is developers sending silent notifications, then having custom logic on the receiver’s device to determine whether to actually show a notification by emitting a local notification. Since we cannot guarantee the delivery or latency of a silent notification, we strongly advise against doing this.

Notification actions

In iOS 8 Apple introduced the ability to have custom actions appear when someone taps on a push notification on the iPhone and Apple Watch. For more information, check out the Apple documentation on push categories. You can set the push category in LYRPushNotificationConfiguration. The following example shows how you can you add a Accept/Ignore button when someone taps on a push; typically you might put this code in the app delegate:

// Constants
NSString *const LQSCategoryIdentifier = @"category_lqs";
NSString *const LQSAcceptIdentifier = @"ACCEPT_IDENTIFIER";
NSString *const LQSIgnoreIdentifier = @"IGNORE_IDENTIFIER";

- (void)setupPushNotificationOptions
{
    UIMutableUserNotificationAction *acceptAction =
    [[UIMutableUserNotificationAction alloc] init];
    acceptAction.identifier = LQSAcceptIdentifier;
    acceptAction.title = @"Show me!";
    acceptAction.activationMode = UIUserNotificationActivationModeBackground;
    acceptAction.destructive = NO;

    UIMutableUserNotificationAction *ignoreAction =
    [[UIMutableUserNotificationAction alloc] init];
    ignoreAction.identifier = LQSIgnoreIdentifier;
    ignoreAction.title = @"Ignore";
    ignoreAction.activationMode = UIUserNotificationActivationModeBackground;
    ignoreAction.destructive = YES;

    UIMutableUserNotificationCategory *category = [[UIMutableUserNotificationCategory alloc] init];
    category.identifier = LQSCategoryIdentifier;
    [category setActions:@[acceptAction, ignoreAction]
              forContext:UIUserNotificationActionContextDefault];
    [category setActions:@[acceptAction, ignoreAction]
              forContext:UIUserNotificationActionContextMinimal];

    NSSet *categories = [NSSet setWithObjects:category, nil];

    UIUserNotificationType types = UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound;
    UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types
                                                                             categories:categories];
    [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
    [[UIApplication sharedApplication] registerForRemoteNotifications];
}

When you send the message, you just need to add the category name to the push configuration.

// Creates and returns a new message object with the given conversation and array of message parts
NSString *pushMessage= [NSString stringWithFormat:@"%@ says %@",self.layerClient.authenticatedUserID ,messageText];

LYRPushNotificationConfiguration *defaultConfiguration = [LYRPushNotificationConfiguration new];
defaultConfiguration.alert = pushMessage;
//The following options will appear in push payload
defaultConfiguration.category = LQSCategoryIdentifier;
LYRMessageOptions *messageOptions = [LYRMessageOptions new];
messageOptions.pushNotificationConfiguration = defaultConfiguration;

LYRMessage *message = [self.layerClient newMessageWithParts:@[messagePart] options:messageOptions error:nil];

Additional Push Configuration

Layer also lets you configure any element of Push Payload including

  • alert, title, sound
  • localized push information
  • additional APNS parameters like launch-image
  • any custom key/value pairs defined by your application

For more information about all these other options check out the API Reference for LYRPushNotificationConfiguration.

Receiving push notifications

The following is an example of a push payload from Layer:

{
    "aps" :  {
        "alert" : "This is the message text.",
        "badge" : 1,
        "sound" : "layerbell.caf",
        "content-available" : 1
    },
    "layer" :     {
        "conversation_identifier" : "layer:///conversations/7b3e0109-c411-434e-965d-f07b62705bc1",
        "event_url" : "layer:///conversations/7b3e0109-c411-434e-965d-f07b62705bc1/messages/4",
        "message_identifier" : "layer:///messages/3ae07c1c-fb90-4207-a533-743929b5e724"
    }
}

The conversation ID is contained in layer.conversation_identifier and the message ID is contained in layer.message_identifier.

Performing actions in response to a push

A common use case is to switch to a conversation list or conversation view immediately after someone taps on a push notification. However, if you try to navigate to the conversation view before the sync has completed the new messages may not appear until the sync has finished. To remedy this LYRClient provides a method called synchronizeWithRemoteNotification:. The code block inside synchronizeWithRemoteNotification: will get executed immediately after the sync has finished. So we recommend navigating to the conversation list or conversation view from within this method.

The following code prints out the contents of LYRMessage object from a push notification:

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    NSError *error;
    BOOL success = [self.layerClient synchronizeWithRemoteNotification:userInfo completion:^(LYRConversation * _Nullable conversation, LYRMessage * _Nullable message, NSError * _Nullable error) {
        if (conversation || message) {
            LYRMessagePart *messagePart = message.parts[0];
            if([messagePart.MIMEType  isEqual: @"text/plain"]) {
                NSLog(@"Pushed Message Contents: %@",[[NSString alloc] initWithData:messagePart.data encoding:NSUTF8StringEncoding]);
            } else if ([messagePart.MIMEType  isEqual: @"image/png"]){
                NSLog(@"Pushed Message Contents was an image");
            }
            completionHandler(UIBackgroundFetchResultNewData);
        } else {
            completionHandler(error ? UIBackgroundFetchResultFailed : UIBackgroundFetchResultNoData);
        }
    }];

    if (success) {
        NSLog(@"Application did complete remote notification sync");
    } else {
        NSLog(@"Failed processing push notification with error: %@", error);
        completionHandler(UIBackgroundFetchResultNoData);
    }
}

Badging

Layer makes it easy to update your application icon badge count automatically. To enable this feature, go to the Push section in the Developer Dashboard. Layer provides four options for the badge count:

  • Unread messages count: The total unread message count across all conversations
  • Unread conversations count: The count of conversations that contain unread messages
  • External count only: The externally set badge count available via the Server API
  • Don’t send badge count: Badge count is untouched

Want to include Announcements with your badge count? Make sure you check the following checkbox:

  • Include announcements: Count announcements in addition to one of the above options

The default setting is “Unread messages count”. The above setting is a server-side change, and requires no client-side iOS code changes. Please note that when you update the setting, the change may take a few minutes to propagate.

To retrieve the badge count in your application, use

NSInteger badgeCount = application.applicationIconBadgeNumber;

Note

If you attempt to set the badge count to 0 somewhere in your app, iOS may stop displaying banners or alerts.

Troubleshooting

If you are running into issues with push notifications, we recommend checking out our push notification troubleshooting guide.

Synchronization Deleting