Using the iOS SDK

A tutorial for adding the iOS SDK code to your app to allow your app users to receive push notifications from your Dotdigital account.

iOS SDK allows your app users to receive push notifications from your Dotdigital account. Dotdigital collects your user's email addresses which is then used to identify them so you can send push notifications.

Our iOS SDK uses the Apple Push Notification Service (APNS) to send push notifications to your contacts.

Our iOS SDK is open source and can be found in Github below:

To set up push notifications for native iOS apps, complete the following tasks:

  1. Ensure your app is registered for APNS use
  2. Install the iOS SDK
  3. Configure the iOS SDK
  4. Initialise the iOS SDK

Installing the iOS SDK

In order to install the SDK, we will use CMPComapiFoundation, a dependency manager for iOS/MacOS projects. To add the iOS SDK to your Xcode project with CMPComapiFoundation, do the following:

  1. Add the iOS SDK
# other podfile info

target '*Your-Target*'
use_frameworks!

pod 'CMPComapiFoundation'

end
  1. Install the iOS SDK
$ pod install
  1. Import the iOS SDK in your Objective-C or Swift file
#import <CMPComapiFoundation/CMPComapiFoundation.h>

Initialise

To initialise the SDK, you will need a few pre-requisites listed below:

  • A configured API Space
  • An authentication provider that can generate a JWT (JSON Web Token) that matches the auth scheme configured for your Api Space
  • The generated JWT must include the provided nonce as a claim in the generated JWT

In order for the client to be able to start a session, the config's authenticationDelegate object must conform to the protocol's method:

NSString *id = <Portal's authentication tab ID claim value>;
NSString *issuer = <Portal's authentication tab issuer value>;
NSString *audience = <Portal's authentication tab audience value>;
NSString *secret = <Portal's authentication tab secret value>;
  
- (void)client:(CMPComapiClient *)client didReceiveAuthenticationChallenge:(CMPAuthenticationChallenge *)challenge completion:(void (^)(NSString * _Nullable))continueWithToken {
    // request a JWT token from your provider (backend server)
    // example call
    [YourProviderServer getTokenForNonce:challenge.nonce id:id issuer:issuer audience:audience secret:secret completion:^(NSString * token, NSError * error) {
            // call continueWithToken block with generated token
        if (token && !error) {
            continueWithToken(token);
        }
    }];
}

A JWT is used to securely transmit information between parties as a JSON object; it's digitally signed, therefore the information can be verified and trusted. For more information on JWT, click here.

The JWT needs to include claims from the authentication panel in the dashboard. For further guidance, please click here.

Here's an example implementation of a token generator in Objective-C using JWT:

#import "CMPAuthenticationManager.h"
#import <JWT/JWT.h>

@implementation CMPAuthenticationManager

+ (NSString *)generateTokenForNonce:(NSString *)nonce profileID:(NSString *)profileID issuer:(NSString *)issuer audience:(NSString *)audience secret:(NSString *)secret {
    NSDate *now = [NSDate date];
    NSDate *exp = [NSCalendar.currentCalendar dateByAddingUnit:NSCalendarUnitDay value:30 toDate:now options:0];
    
    NSDictionary *headers = @{@"typ" : @"JWT"};
    /* Claims notes:
       ID claim, this claim name must be the same as the value of the 'ID claim' field in your push notification profile in Dotdigital,
       the default value is 'sub', and the value of the claim must be a consitent unique value for the app user. 
       
       'aud' audience claim must be the same as the value of the 'Audience' field in your push notification profile in Dotdigital.
       
       'iss' audience claim must be the same as the value of the 'Issuer' field in your push notification profile in Dotdigital.
    */
    NSDictionary *payload = @{@"nonce" : nonce,
                               @"sub" : profileID,
                               @"iss" : issuer,
                               @"aud" : audience,
                               @"iat" : [NSNumber numberWithDouble:now.timeIntervalSince1970],
                               @"exp" : [NSNumber numberWithDouble:exp.timeIntervalSince1970]};
    
    NSData *secretData = [secret dataUsingEncoding:NSUTF8StringEncoding];
    id<JWTAlgorithm> algorithm = [JWTAlgorithmFactory algorithmByName:@"HS256"];
    
    NSString *token = [JWTBuilder encodePayload:payload].headers(headers).secretData(secretData).algorithm(algorithm).encode;
    return token;
}

@end
  
/* Note that this should preferably be generated by your backend, the app should only retreive the token through an HTTP call */

Configuring the iOS SDK

Before you can configure the iOS SDK, you need the following:

To configure the iOS SDK:

  1. Create a new instance of the CMPComapiConfig class and store it in a variable

  2. As the first argument of the CMPComapiConfig instance, pass your API Space ID

  3. As the second argument of the CMPComapiConfig instance, pass an instance of a class that creates a JWT token

// create a config object with your api-space-id and an object conforming to CMPAuthenticationDelegate protocol;
CMPComapiConfig * config = [
  [
    [
      [CMPComapiConfig builder]
      setApiSpaceID: @ "<API_SPACE_ID>"
    ]
    setAuthDelegate: <CMPAuthenticationDelegate_Conforming_Object>
  ] <CMPAuthenticationDelegate_Conforming_Object> build
];

CMPComapiClient * client = [CMPComapi initialiseWithConfig: config];

// we can use the client object now

Retrieving the client

The client can be retrieved either as a separate object using:

CMPComapiClient *client = [CMPComapi initialiseWithConfig:config];
// client instance ready to use

or as a singleton:

[CMPComapi initialiseSharedInstanceWithConfig:config];

CMPComapiClient *client = [Comapi shared];
// shared client ready to use

Sessions

Starting a session

To receive push messages the SDK requires an active session. A session will also be automatically created by the SDK if you have not initialized it already when it is required.

To create a session you must have successfully initialized and retrieved a client object, you need to be able to identify the app user so that the sub claim in the JWT can be populated for the user; when the SDK requests the JWT in order to start the session. To create a session call:

[client.services.session startSessionWithCompletion:^{
  // session successfully created
} failure:^(NSError * _Nullable error) {
  // error ocurred
}];

Ending a session

You only have to end a session if you want to stop the app receiving push notifications, or you want to change users on the app.

To end the current session, call:

[client.services.session endSessionWithCompletion:^(CMPResult<NSNumber *> * result) {
    if (result.error) {
      // error occurred
    } else {
      BOOL success = [result.object boolValue];
      if (success) {
        // session successfully ended
      }     
    }
}];

Configuring your app to ask users' permission to send them push notifications

To receive push notifications, app users must give their permission.

Call the application(_:didRegisterForRemoteNotificationsWithDeviceToken:) method to get the deviceToken string and pass it to the setPushToken() method on the ComapiClient object.

🚧

Device token string formatting

Since iOS 13 the NSData deviceToken format has changed and you cannot simply cast the deviceToken to string to pass to the SDK, as this will corrupt the token. Instead the deviceToken must be converted to a hexidecimal string from the bytes. The code below shows how this can be done.

An APNS token should look like this: 02df25c845d460bcdad7802d2vf6fc1dfce97283bf75cc993eb6dca835ea2e2f

Note, if it is correct it will be a 64 character hex string.

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    NSMutableString *token = [NSMutableString string];
    
    // Convert the deviceToken bytes to a hexidecimal string 
    const char *data = [deviceToken bytes];
    for (NSUInteger i = 0; i < [deviceToken length]; i++) {
        [token appendFormat:@"%.2hhx", data[i]];
    }
  
    // Pass the hexideicmal string version of the token to the SDK to use
    if (token) {
        [client setPushToken:token completion:^(CMPResult<NSNumber *> * result) {
            BOOL success = [result.object boolValue];
            if (result.error || !success) {
                // error occurred
            } else {
                // configuration successful
            }
        }];
    }
    
    // rest of you push notification code
}

Displaying push notifications when the app is in the foreground

Push notifications are displayed only while the app is in the background. These notification are sent to the notification center and launch your app when users tap them.

If you want to display the push notification message while the app is in the foreground, do one of the following, depending on the iOS version that your app is running on:

For iOS 9

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    if (application.applicationState == UIApplicationStateActive) {
        
    }
}

For iOS 10 and above

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

👍

Next steps

Now ensure your app passes an email address to the SDK for the app user to ensure they get a contact created in Dotdigital by following these instructions

📘

Want to know more about the SDK?

To find out more about the SDK and it features and functions please go here


Did this page help you?