Integration

Kumulos provides an SDK in the form of framework to ease integration Kumulos Build, Push Notification and Analytics features into your iOS app. This guide provides an overview of setting up the SDK for your project and sample usage.

Integrate SDK components

The Kumulos SDK is an open source project hosted on Github, for ease of use it is linked to from the agency console and can be found at https://github.com/Kumulos/KumulosSdkObjectiveC.

Both Carthage and CocoaPods integration instructions are available in the GitHub repo.

Generated Bindings

Using the generated bindings assumes that you have deployed an API for iOS/OSX and downloaded the libraries.

After downloading the libraries, to make use of the generated bindings, drag & drop the Kumulos.h and Kumulos.m files from the download into your project.

Add the files to your project

Initialization

Using the SDK

To initialize the Kumulos SDK, simply alloc & init the Kumulos class with your application's API key and secret key.

@import KumulosSDK;
...
KSConfig *config = [KSConfig configWithAPIKey:@"YOUR_API_KEY" andSecretKey:@"YOUR_SECRET_KEY"];
Kumulos *k = [[Kumulos alloc] initWithConfig:config];

Using the Generated Bindings

If you want to use the generated bindings, you can simply use the generated init method that has the keys provided:

#import "Kumulos.h"
...
Kumulos* k = [[Kumulos alloc] init];

Calling API Methods

This section shows various examples of calling your Kumulos API methods using the SDK or the generated bindings, and handling results with blocks or delegates as desired.

To talk to Kumulos, you need three things:

  • your method title (in lowerCamelCase)
  • a method parameters map (field names are also in lowerCamelCase)
  • some response handler code

All networking is performed asynchronously, but your result handling blocks & delegates will always be called back on the application's main thread

Using the SDK

Handling Results with Blocks

To make calls to your API methods, use the callMethod:... selectors on the Kumulos class. For an example using blocks to handle the response:

NSDictionary* params = @{@"author": "Jane Austin"};
// Assuming Kumulos instance has been initialized as a property called 'k'
[self.k callMethod:@"getAllBooksByAuthor" withParams:params success:^(KSAPIOperation* op, KSAPIResponse* response) {
    NSArray* books = response.payload;

    // Do something with the books
  } andFailure:^(KSAPIOperation* op, NSError* error) {
    NSLog(@"Something went wrong!");
  }];

Handling Results with Delegates

Alternatively you can handle results using a delegate conforming to the KSAPIOperationDelegate protocol:

@import KumulosSDK;

@interface ViewController () <KSAPIOperationDelegate>

@property (nonatomic) Kumulos* k;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.k = [[Kumulos alloc] initWithAPIKey:@"YOUR_API_KEY" andSecretKey:@"YOUR_SECRET_KEY"];
    [self.k [email protected]"getAllAuthors" withDelegate:self];
}

- (void) operation:(KSAPIOperation *)operation didCompleteWithResponse:(KSAPIResponse *)response {
    NSString* methodAlias = operation.method;
    NSLog(@"%@", response.payload);

    // Check which method it was and handle result as appropriate
}

// Optionally conform to handle errors
- (void) operation:(KSAPIOperation *)operation didFailWithError:(NSError *)error {
    NSLog(@"Something went wrong!");
}

@end

Using the Generated Bindings

If you are using the generated bindings, each of your API methods will be available to invoke directly on the Kumulos class thanks to the Kumulos (Bindings) category implemented by Kumulos.m.

In this mode of operation, you can only handle the reults using a delegate conforming to the KumulosDelegate protocol defined in Kumulos.h.

For example:

#import "Kumulos.h"

@interface ViewController () <KumulosDelegate>

@property (nonatomic) Kumulos* k;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.k = [[Kumulos alloc] initWithAPIKey:@"YOUR_API_KEY" andSecretKey:@"YOUR_SECRET_KEY"];

    // Tell Kumulos which delegate will handle API operation results
    [self.k setDelegate:self];
    // Invoke the API method directly
    [self.k getAllAuthors];
}

- (void) kumulosAPI:(Kumulos*)kumulos apiOperation:(KSAPIOperation*)operation getAllAuthorsDidCompleteWithResult:(NSArray*)theResults {
    // Handle the results for the getAllAuthors API call
}

// Optionally handle errors
- (void) kumulosAPI:(kumulosProxy *)kumulos apiOperation:(KSAPIOperation *)operation didFailWithError:(NSString *)theError {
    ...
}

@end

Cancelling API Operations

To cancel requests, just grab the KSAPIOperation* from the Kumulos object and call the cancel selector. For example:

KSAPIOperation* theOperation = [self.k callMethod:@"myNotSoAwesomeOperation" withDelegate:self];
// Change your mind
[theOperation cancel];

Push Notifications

The Kumulos SDK provides push notifications with APNS. To integrate Kumulos Push into your iOS project, you have to complete the following steps:

  1. Set up APNS certificates for your app
  2. Configure Push in the Kumulos Agency Console
  3. Integrate SDK components with your iOS project
  4. Register for push form the client app

Configuration & Integration

In order to send push notifications to iOS devices with Kumulos, you'll need to create certificates in the Apple Developer Member Center. The steps to complete this are shown in the video guide.

Configuring APNS for iOS with Kumulos

After configuring your project, continue to follow the steps below.

Requesting & Registering a Push Token

When you consider it appropriate, you need to request permission from the user to send them push notifications.

Whilst you can handle this yourself, Kumulos provides a convenience method:

// Assuming a Kumulos property 'k'
[self.k pushRequestDeviceToken];

This will prompt the user to accept push notifications with the badge, alert, and sound settings. When the user accepts, your app delegate will receive the push token.

Once you have the device token, you will need to register this token with the current Kumulos installation like so:

- (void) application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    [self.k pushRegisterWithDeviceToken:deviceToken];
}

These steps are all that are required to register the device for push notifications. To track & report on push conversions, you need to track the push opens.

Track Push Conversions

When your app receives a push notification, or is launched by tapping on a push notification, your app's delegate will be called back by the OS.

To correctly report on push open rates & conversions, you need to tell Kumulos that the app was launched by the remote notification.

For iOS 9 & 10, this is handled slightly differently. In our example, we show an application delegate that can respond correctly on both iOS 9 & 10.

//
//  AppDelegate.m
//

#import "AppDelegate.h"

// Import the Kumulos framework
@import KumulosSDK;
// Used for push on iOS10
@import UserNotifications;

static NSString* const K_API_KEY = @"YOUR_API_KEY";
static NSString* const K_SECRET_KEY = @"YOUR_SECRET_KEY";

// Conform to the UNUserNotificationCenterDelegate protocol to handle push on iOS10
@interface AppDelegate () <UNUserNotificationCenterDelegate>

@property Kumulos* k;

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Initialize the Kumulos SDK
    self.k = [[Kumulos alloc] initWithAPIKey:K_API_KEY andSecretKey:K_SECRET_KEY];

    // Register the app delegate as the notification center handler
    [[UNUserNotificationCenter currentNotificationCenter] setDelegate:self];

    return YES;
}

...

// iOS9 handler for push notifications
// iOS9+10 handler for background data pushes (content-available)
- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateInactive) {
        [self.k pushTrackOpenFromNotification:userInfo];
    }

    completionHandler(UIBackgroundFetchResultNoData);
}

// Called on iOS10 when your app is in the foreground to allow customizing the display of the notification
- (void) userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
    completionHandler(UNNotificationPresentationOptionNone);
}

// iOS10 handler for when a user taps a notification
- (void) userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
    NSDictionary* userInfo = [[[[response notification] request] content] userInfo];
    [self.k pushTrackOpenFromNotification:userInfo];

    completionHandler();
}

@end

This sample shows how to track push open conversions when a user has tapped on a notification and launched the app. However, you may wish to customize when you want to track a push open. In those cases, you can simply call pushTrackOpenFromNotification as desired and pass in the userInfo object from the notification.

Handling URL Pushes

When you send a URL push with Kumulos, you will need to handle opening the browser from your delegate methods like so:

// iOS9 handler for push notifications
// iOS9+10 handler for background data pushes (content-available)
- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateInactive) {
        [self.k pushTrackOpenFromNotification:userInfo];

        // Handle opening URLs on notification taps
        NSURL* url = [NSURL URLWithString:userInfo[@"custom"][@"u"]];
        if (url) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [[UIApplication sharedApplication] openURL:url];
            });
        }
    }

    completionHandler(UIBackgroundFetchResultNoData);
}

// iOS10 handler for when a user taps a notification
- (void) userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
    NSDictionary* userInfo = [[[[response notification] request] content] userInfo];
    [self.k pushTrackOpenFromNotification:userInfo];

    // Handle URL pushes
    NSURL* url = [NSURL URLWithString:userInfo[@"custom"][@"u"]];
    if (url) {
        [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:^(BOOL success) {
            /* noop */
        }];
    }

    completionHandler();
}

Handling Background Data Pushes

When you send a background data push with Kumulos, the content-available flag will be set on the notification.

This will allow your app to be woken up to process the push notification in the background.

Make sure you have enabled the "Remote notifications" background mode in your project's "Capabilities" settings

The background push notification will trigger the application:didReceiveRemoteNotification:fetchCompletionHandler: application delegate:

- (void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    // iOS9 handle push opens
    if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateInactive) {
        [self.k pushTrackOpenFromNotification:userInfo];
    }

    // userInfo[@"aps"][@"content-available"] will be set to 1
    // userInfo[@"custom"][@"a"] will contain any additional data sent with the push

    completionHandler(UIBackgroundFetchResultNoData);
}

Note if you set a title & message then a notification will be shown to the user. If you want the push to be silent, don't set a title or message when sending.

Push Channels

You can create and manage subscriptions to push notification Channels via the SDK. Channels allow your users to define preferences for the type of content they would like to receive via notifications.

You can manage all channel interactions via the KumulosPushSubscriptionManager class.

Kumulos* k = [[Kumulos alloc] initWithAPIKey:K_API_KEY andSecretKey:K_SECRET_KEY];
KumulosPushSubscriptionManager* manager = [[KumulosPushSubscriptionManager alloc] initWithKumulos:k];

The push manager exposes several methods to manage subscriptions:

@interface KumulosPushSubscriptionManager

- (void) subscribeToChannels:(NSArray<NSString*>* _Nonnull) uuids onComplete:(KSPushSubscriptionCompletionBlock) complete;

- (void) unsubscribeFromChannels:(NSArray<NSString*>* _Nonnull) uuids onComplete:(KSPushSubscriptionCompletionBlock) complete;

- (void) setSubscriptions:(NSArray<NSString*>* _Nonnull) uuids onComplete:(KSPushSubscriptionCompletionBlock) complete;

- (void) clearSubscriptions:(KSPushSubscriptionCompletionBlock) complete;

- (void) listChannels:(KSPushChannelsSuccessBlock) complete;

- (void) createChannelWithUuid:(NSString* _Nonnull) uuid shouldSubscribe:(BOOL) subscribe name:(NSString* _Nullable) name showInPortal:(BOOL) shownInPortal andMeta:(NSDictionary* _Nullable) meta onComplete:(KSPushChannelSuccessBlock) complete;

@end

Results are handled by passing a block for the operation's completion like so:

[self.manager listChannels:^(NSError * _Nullable error, NSArray<KSPushChannel *> * _Nullable channels) {
    if (error) {
        // Handle any error as you want
        return;
    }

    // Handle channel listing result
}];

When creating channels, the visiblity and meta data can be controlled. Please make sure you understand these concepts when creating channels from the SDK.

Crash Reporting

Crash reporting allows you to track unhandled exceptions in your app, and optionally log any caught exceptions for further investigation. Crash reporting is not enabled by default, to enable this feature, simply modify your Kumulos initialization to include enabling crash reporting.

KSConfig *config = [KSConfig configWithAPIKey:@"YOUR_API_KEY" andSecretKey:@"YOUR_SECRET_KEY"];
[config enableCrashReporting];
Kumulos *k = [[Kumulos alloc] initWithConfig:config];

That's it! Unhandled exceptions that lead to crashes will now be recorded automatically and shown in your App Delivery Console.

Note that crash reporting is not available whilst connected to a debugger, but it does work with debug builds.

If you wish to log any caught exceptions, you can record them with the helper method:

[k logExceptionWithName:@"name" reason:@"reason" language:@"objc" lineNumber:@"1" stackTrace:@[@"boom", @"clunk", @"bang"] loggingAllThreads:YES];

Ensure that crash reporting is enabled when attempting to log exceptions.

Installation ID

When initialized for the first time, the Kumulos SDK will create a unique identifier for the app installation that initialized the SDK.

This identifier can be used to target push notifications to a specific device through KScript or the Push Notifications API.

In order to retrieve this installation ID, simply use the class method:

NSString* installId = [Kumulos installId];

Once you have the installation ID, you can send it to your app's backend to be used later for push targeting. For more information about push targeting, please see the KScript Documentation or push notification documentation as appropriate.

Location Tracking

You can send Kumulos location updates and use this to trigger events such as push notifications when an install enters a GeoFence.

How you configure the Core Location services for iOS depends on the specific use case of your app. You should consider both accuracy and battery life when making this decision. Refer to the Apple documentation for details of how to configure location services.

Once you have created a CLLocationManagerDelegate you can use the helper method in the Kumulos SDK to send location updates to Kumulos.

[self.k sendLocationUpdate:location];

Changelog

1.4.1

  • Add public header file to Podspec

1.4.0

  • Add Crash Reporting

1.3.2

  • Version bump

1.3.1

  • Expose geolocation update helper publicly
  • Fix nil reference exception in stats

1.3.0

  • Add geolocation update helper method
  • Add locale & bundle to stats payload

1.2.1

  • Add missing header guard for macOS

1.2.0

  • Add Podspec for CocoaPods support
  • Update installation instructions
  • Fix include guards for iOS & macOS headers

1.1.0

  • Add push channel subscription management

1.0.1

  • Fix compilation of framework to include full bitcode

1.0.0

  • Initial release of SDK as a framework
  • Initial release of support for Kumulos Push
  • Clean up of public interfaces & properties
  • Move supporting behavior for generated bindings from the core SDK to the generated bindings
  • Modernize Objective-C throughout
  • Utilize latest AFNetworking throughout

The generated bindings code has been updated to be compatible with our latest SDK whilst aiming to maintain backwards compatibility with the most commonly used features of the older SDKs. However, if you have any trouble upgrading, please drop a line to [email protected] -- we'd be happy to help.