Set up APNs to deliver instant notifications in your iOS app
Tags: ios, applozic, apns, tutorial
Published: 2021-05-24 13:46:17

_This article was first published on [Applozic Blog](https://www.applozic.com/blog/firebase-start-up-your-base-or-fire-up-your-own-servers/)._

## Introduction

It's 8 pm and you're tired after a long day of work. You want to order in food but you also need to be on video for the marketing call for the next hour. How do you know when the food has been picked up and delivered without surreptitiously checking your iPhone?

Push Notifications!

The little ding of your phone that reminds you to check it for the latest notification and satiate your fear of missing out (FOMO) on what's going on with the world - did you know that this technology is possible through a technology called APNs?

Apple Push Notification Service (APNs) enable you to deliver remote notifications (also known as push notifications) that push small amounts of data to devices that use your app, even when your app isn’t running.

## How does APNs work?

The delivery of remote notifications involves these key components:

* Your organization's server (known as the provider server)
* Apple Push Notification service (APNs) set up
* The user’s device
* Your app (running on the user’s device)

![image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dsftg8avw7oh9j0iegkp.png) 

Remote notifications begin with your company’s server. You decide which notifications you want to send to your users, and when to send them. When it’s time to send a notification, you generate a request that contains the notification data and a unique identifier for the user’s device. You then forward your request to APNs, which handles the delivery of the notification to the user’s device. Upon receipt of the notification, the operating system on the user’s device handles any user interactions and delivers the notification to your app.

You’re responsible for setting up a provider server (or servers) and for configuring your app to handle notifications on the user’s device. Apple manages everything in between, including the presentation of notifications to the user. You must also have an app running on the user’s device that can communicate with your server and provide necessary information.

## What does APNs provide?

APNs provides a mechanism to ensure your app makes every effort to deliver your notifications from your server, and to deliver them with the best user experience:

* APNs manages an accredited, encrypted, and persistent IP connection to the user’s device.
* APNs allows you to remotely lock/wipe a lost/stolen/compromised device over the air. 
* APNs can store notifications for a device that’s currently offline. APNs then forwards the stored notifications when the device comes online. 
* APNs can combine notifications for the same app and display them at once.

## What can you use push notifications for?

* Display a short text message, called an alert, that draws attention to something new in your app. 
* Play a notification sound. 
* Set a badge number on the app’s icon to let the user know there are new items. 
* Provide actions the user can take without opening the app. 
* Show a media attachment
* And many more such actions!

Now that we have a clear understanding of how we can use APNs in our applications, let's learn about how we can set them up!

## Set up APNs in your chat app

In this tutorial, we will be learning how to set up APNs in your application and integrating the remote notification service. For the purpose of this tutorial, we will be using <a rel="noreferrer noopener" href="https://www.applozic.com/" target="_blank">Applozic's</a> iOS SDK offering. Please follow our <a rel="noreferrer noopener" href="https://github.com/AppLozic/Applozic-iOS-SDK#readme" target="_blank">documentation at GitHub</a> and complete the first two steps in your integration process, 

<ul><li><a rel="noreferrer noopener" href="https://github.com/AppLozic/Applozic-iOS-SDK#1-setup" target="_blank">Initial Setup</a> and adding <a rel="noreferrer noopener" href="https://github.com/AppLozic/Applozic-iOS-SDK#frameworks" target="_blank">frameworks</a> and <a rel="noreferrer noopener" href="https://github.com/AppLozic/Applozic-iOS-SDK#add-permissions" target="_blank">permissions</a>.</li><li><a rel="noreferrer noopener" href="https://github.com/AppLozic/Applozic-iOS-SDK#2-registerlogin-the-user" target="_blank">Registering a user</a> for your application </li></ul>

### Configure your app and register it with the APNs

#### Creating APNs certificates

<p>For Apple to send push notifications to user devices, you need to create an APNs certificate in your Apple developer account.</p>

<ol><li>Visit this&nbsp;<a rel="noreferrer noopener" href="https://developer.apple.com/account/resources/certificates/add" target="_blank">link</a>, to create Apple Push Notification service SSL (Sandbox) i.e development certificate.</li><li>Visit this&nbsp;<a rel="noreferrer noopener" href="https://developer.apple.com/account/resources/certificates/add" target="_blank">link</a>, to create Apple Push Notification service SSL (Sandbox &amp; Production), i.e, distribution certificate.</li></ol>

> Note: Supported format for APNs certificate is .p12

Once the certificates are created, you can download them and export the .p12 files with the password for development and distribution certificate using<a rel="noreferrer noopener" href="https://support.apple.com/en-in/guide/keychain-access/kyca1085/mac" target="_blank"><strong>Keychain Access in Mac</strong>.</a>

#### Upload APNs Certificates

Go to the&nbsp;<a rel="noreferrer noopener" href="https://console.applozic.com/settings/pushnotification" target="_blank">Applozic&nbsp;console&nbsp;push notification section</a>&nbsp;to upload the APNs development and distribution certificates. The following screenshot is what will be visible on the console for you:

<figure class="wp-block-image"><a href="https://raw.githubusercontent.com/AppLozic/Applozic-iOS-Audio-Video-SDK/main/Images/apns-certificate-upload.png" target="_blank" rel="noreferrer noopener"><img src="https://raw.githubusercontent.com/AppLozic/Applozic-iOS-Audio-Video-SDK/main/Images/apns-certificate-upload.png" alt="apns certificate upload in applozic console" title="apns-certificate-upload"/></a><figcaption>Push Notification screen in Console Dashboard</figcaption></figure>

#### Adding Capabilities to Your App

1. On the Xcode project’s Signing & Capabilities tab, Click (+ Capability) to add “Push Notifications” 
2. Next Click (+ Capability) to add "Background modes" enable these options from Background modes:

* Background fetch 
* Remote notifications 

After adding these capabilities, your screen should look like this:
<figure class="wp-block-image"><a href="https://github.com/AppLozic/Applozic-iOS-SDK/blob/master/images/xcode-capability.png" target="_blank" rel="noreferrer noopener"><img src="https://github.com/AppLozic/Applozic-iOS-SDK/raw/master/images/xcode-capability.png" alt="xcode-capability"/></a></figure>

#### Configure the push notification in the Appdelegate file of your project.

Add the below imports in the Appdelegate file
```
#import <Applozic/Applozic.h>
#import <UserNotifications/UserNotifications.h>
```

#### Handling app launch on notification click and register remote notification for APNs

Add the following code in AppDelegate.m class, this function will be called after the app launch to register for push notifications.

```
// UNUserNotificationCenterDelegate are required for APNs call backs please add this delegate to your AppDelegate file 
@interface AppDelegate () <UNUserNotificationCenterDelegate>

@end


// didFinishLaunchingWithOptions method of your app

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // checks whether app version is updated/changed then makes server call setting VERSION_CODE
    [ALRegisterUserClientService isAppUpdated];

    // Register APNs and Push kit
    [self registerForNotification];

    // Register for Applozic notification tap actions and network change notifications
    ALAppLocalNotifications *localNotification = [ALAppLocalNotifications appLocalNotificationHandler];
    [localNotification dataConnectionNotificationHandler];
    
    ALPushNotificationHandler *pushNotificationHandler = [ALPushNotificationHandler shared];
    [pushNotificationHandler dataConnectionNotificationHandler];

    // Override point for customization after application launch.
    NSLog(@"launchOptions: %@", launchOptions);
    if (launchOptions != nil) {
        NSDictionary *dictionary = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
        if (dictionary != nil) {
            NSLog(@"Launched from push notification: %@", dictionary);
            ALPushNotificationService *pushNotificationService = [[ALPushNotificationService alloc] init];
            BOOL applozicProcessed = [pushNotificationService processPushNotification:dictionary updateUI:[NSNumber numberWithInt:APP_STATE_INACTIVE]];

            //IF not a appplozic notification, process it
            if (!applozicProcessed) {
                //Note: notification for app
            }
        }
    }

    return YES;
}

// Register APNs

-(void)registerForNotification
{
    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
    center.delegate = self;
    [center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error)
     {
        if(!error)
        {
            dispatch_async(dispatch_get_main_queue(), ^ {
                [[UIApplication sharedApplication] registerForRemoteNotifications];  // required to get the app to do anything at all about push notifications
                NSLog(@"Push registration success." );
            });
        }
        else
        {
            NSLog(@"Push registration FAILED" );
            NSLog(@"ERROR: %@ - %@", error.localizedFailureReason, error.localizedDescription );
            NSLog(@"SUGGESTIONS: %@ - %@", error.localizedRecoveryOptions, error.localizedRecoverySuggestion );
        }
    }];
}
```

#### Sending an APNs device token to Applozic server

Add the below code in your Appdelegate file. If any of these methods already exist then you can copy-paste the relevant code from the below methods.

```
// APNs device token sending to Applozic

- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)
deviceToken {

    const unsigned *tokenBytes = [deviceToken bytes];
    NSString *hexToken = [NSString stringWithFormat:@"%08x%08x%08x%08x%08x%08x%08x%08x",
                          ntohl(tokenBytes[0]), ntohl(tokenBytes[1]), ntohl(tokenBytes[2]),
                          ntohl(tokenBytes[3]), ntohl(tokenBytes[4]), ntohl(tokenBytes[5]),
                          ntohl(tokenBytes[6]), ntohl(tokenBytes[7])];

    NSString *apnDeviceToken = hexToken;
    NSLog(@"apnDeviceToken: %@", hexToken);

    if (![[ALUserDefaultsHandler getApnDeviceToken] isEqualToString:apnDeviceToken]) {
        ALRegisterUserClientService *registerUserClientService = [[ALRegisterUserClientService alloc] init];
        [registerUserClientService updateApnDeviceTokenWithCompletion
         :apnDeviceToken withCompletion:^(ALRegistrationResponse
                                          *rResponse, NSError *error) {

            if (error) {
                NSLog(@"%@",error);
                return;
            }
            NSLog(@"Registration response%@", rResponse);
        }];
    }
}
```

#### Receiving push notification

Once your app receives notification, pass it to the Applozic handler for chat notification processing.

```
// UNUserNotificationCenter delegates for chat
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification*)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
    ALPushNotificationService *pushNotificationService = [[ALPushNotificationService                                                    alloc] init];
    NSDictionary *userInfo = notification.request.content.userInfo;
    NSLog(@"APNS willPresentNotification for userInfo: %@", userInfo);

    if ([pushNotificationService isApplozicNotification:userInfo]) {
        [pushNotificationService notificationArrivedToApplication:[UIApplication sharedApplication] withDictionary:userInfo];
        completionHandler(UNNotificationPresentationOptionNone);
        return;
    }
    completionHandler(UNNotificationPresentationOptionAlert|UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionSound);
}

- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(nonnull UNNotificationResponse* )response withCompletionHandler:(nonnull void (^)(void))completionHandler {


    ALPushNotificationService *pushNotificationService = [[ALPushNotificationService
                                                           alloc] init];
    NSDictionary *userInfo =  response.notification.request.content.userInfo;
    NSLog(@"APNS didReceiveNotificationResponse for userInfo: %@", userInfo);

    if ([pushNotificationService isApplozicNotification:userInfo]) {
        [pushNotificationService notificationArrivedToApplication:[UIApplication sharedApplication] withDictionary:userInfo];
        completionHandler();
        return;
    }
    completionHandler();
}

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

    NSLog(@"RECEIVED_NOTIFICATION_WITH_COMPLETION :: %@", userInfo);
    ALPushNotificationService *pushNotificationService = [[ALPushNotificationService alloc] init];
    if ([pushNotificationService isApplozicNotification:userInfo]) {
        [pushNotificationService notificationArrivedToApplication:application withDictionary:userInfo];
        completionHandler(UIBackgroundFetchResultNewData);
        return;
    }
    completionHandler(UIBackgroundFetchResultNewData);
}

- (void)applicationWillTerminate:(UIApplication *)application {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.

    [[ALDBHandler sharedInstance] saveContext];
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    // Called as part of the transition from the background to the inactive state; here you can undo any of the changes made on entering the background.

    NSLog(@"APP_ENTER_IN_FOREGROUND");
    [application setApplicationIconBadgeNumber:0];
}
```

## Conclusion

We began this article by going over the workings of APNs and how it can be utilized in our applications. We also learnt about what are the requirements in setting up APNs and the different use cases remote notifications provide for an application.

Next, we utilized Applozic's iOS SDK to configure and register an application with APNs. We also added the remote notification and background fetch capabilities in the app.

Finally, we went over the code snippets that will enable you to configure the sending and receiving of push notifications in an application.

As we end this tutorial, you should have a clear understanding of the push notification ecosystem in iOS and leveraging APNs in your applications.

Please leave your feedback and doubts in the comments below!