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/KumulosSdkSwift.

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

Initialization

To configure the SDK for use you need to initialize it with your app's API credentials, this should be done early in your application startup so that you can start using API methods and features.

import UIKit
import KumulosSDK

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

  var window: UIWindow?

  func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

    let builder = KSConfigBuilder(apiKey: "your-api-key", secretKey: "your-secret-key")
    Kumulos.initialize(config: builder.build())

    // Override point for customization after application launch.
    return true
  }
}

Your API Key and Secret Key can be obtained from your App Dashboard in your agency console.

You don't need to initialize Kumulos every time you wish to make an API call. It only needs to be initialized once, after which it will remember the API key and secret key you've given it the first time.

Checking installs of your App

When you run your app on a simulator or install your app on a device, you can check that the SDK has been initialized correctly by selecting the app and clicking the Installs tab to see the ten most recent installs of your app. Click on any install to see more information.

Recent installs

If you experience any difficulties integrating an SDK or initializing the Kumulos client, please don't hesitate to contact support who are standing by to help!

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 access the class variable:

let 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.

Analytics

Kumulos provides concise and easy to consume analytics & reporting features. By initializing the SDK, you automatically get session & engagement reporting out the box.

Session Analytics

Kumulos records sessions based on application foreground and background events. When an app enters the background, Kumulos will wait for a configurable idle period. If there are no more foreground events during that idle period, the current session will be closed.

Session analytics

You can configure the idle period to suit your app's use-case. By default the idle period is 40 seconds of inactivity. The idle period does not count towards session duration calculations.

To adjust the idle period, you can configure the SDK as follows:

let builder = KSConfigBuilder(apiKey: "your-api-key", secretKey: "your-secret-key")
.setSessionIdleTimeoutSeconds(120);

Kumulos.initialize(config: builder.build())

Note that due to background task limits, in practise the idle timeout can only reasonably be up to a few minutes

Event Tracking

Kumulos allows you to track custom analytics events that can be used as a trigger to fire automation rules (e.g. to trigger a push notification) or as steps in a funnel to track conversion through key user journeys in your app.

Track conversion

To track a custom analytics event, use Kumulos.trackEvent as follows:

Kumulos.trackEvent(eventType: "product.purchased", properties: [
    "productId": 404
])

Event tracking is available offline as all events are persisted locally before being synced to the server in batches in the background.

Checking events from your App

When you run your app on a simulator or install your app on a device, you can check that the SDK is recording events correctly by selecting the app and clicking the Installs tab to see the ten most recent installs of your app. Click on any install and then click on the Events tab.

Install events

User Association

Kumulos allows associating a user identifier with the current installation ID. This user identifier is useful for performing analytics aggregations & analyses at the user level, for example, funnels completed by users across multiple devices.

To associate the current app installation with a user, you can use the helper method as shown below:

Kumulos.associateUserWithInstall(userIdentifier: "unique-user-identifier")

User association is time-aware, so in the case of two different users sharing a device to log in to the app, their user IDs will be associated with the same install for the time between subsequent calls to the helper method. For example:

Kumulos.associateUserWithInstall(userIdentifier: "Bob")

// This event will belong to Bob
Kumulos.trackEvent(eventType: "product.purchased", properties: [
    "productId": 404
])

Kumulos.associateUserWithInstall(userIdentifier: "Alice")

// This event will belong to Alice
Kumulos.trackEvent(eventType: "product.purchased", properties: [
    "productId": 404
])

Push

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

  1. Setup a provisioning profile with push certificates via the Apple Developer Member Center
  2. Configure Push in the Kumulos Agency Console
  3. Register for push notifications from your app

Setup APNS

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.

If you are using a combined APNS certificate then the Kumulos SDK will automatically register devices as production / sandbox based on the application release mode, debug will be treated as sandbox.

Configure Push in the Kumulos Agency Console

Next you need to enable and configure the Kumulos push service with the certificates you have created

Register for Push Notifications

The app notification settings must be set which tells the OS which notification types are being requested, then the OS triggered to prompt the user to allow your app to receive push tokens and get the device token.

The KumulosSDK provides a helper method to configure notification permissions for alert, badge and sound permissions then trigger the prompt with one line.

Kumulos.pushRequestDeviceToken()

The Kumulos SDK will automatically detect iOS 10 vs older versions and register for notifications appropriately.

Now send the returned device token to the Kumulos Push service, the OS will trigger a callback with the device token, depending on the OS version the definition will change slightly. From either you can forward the token to the Kumulos SDK.

iOS 9 and lower

func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
      Kumulos.pushRegister(deviceToken)
}

iOS 10

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {    
    Kumulos.pushRegister(deviceToken)
}

Checking Push Registrations

When you run your app on a simulator or install your app on a device, you can check that the install has successfully registered for push notifications by selecting the app and clicking the Installs tab to see the ten most recent installs of your app. Click on any install and then click on Push tab.

Install push details

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.


import UIKit
import KumulosSDK
// Import the framework for iOS10
import UserNotifications

// Add the delegate protocol
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Set up the delegate (for iOS10)
        UNUserNotificationCenter.current().delegate = self;

        return true
    }

    ...

    // iOS9
    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        if (UIApplication.shared.applicationState == UIApplicationState.inactive)) {
            Kumulos.pushTrackOpen(notification: userInfo)
        }
        completionHandler(UIBackgroundFetchResult.noData)
    }

    // iOS10
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        completionHandler([])
    }

    // iOS10
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        let userInfo = response.notification.request.content.userInfo;
        Kumulos.pushTrackOpen(notification: userInfo)
        completionHandler()
    }


}

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 pushTrackOpen 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)
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    if (UIApplication.shared.applicationState == UIApplicationState.inactive) {
        Kumulos.pushTrackOpen(notification: userInfo)

        if let custom = userInfo["custom"] as? [AnyHashable:Any], let urlStr = custom["u"] as? String {
            if let url = URL.init(string: urlStr) {
                DispatchQueue.main.async {
                    UIApplication.shared.openURL(url)
                }
            }
        }
    }

    completionHandler(UIBackgroundFetchResult.noData)
}

@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
    let userInfo = response.notification.request.content.userInfo;
    Kumulos.pushTrackOpen(notification: userInfo)

    // Handle opening URL
    if let custom = userInfo["custom"] as? [AnyHashable:Any], let urlStr = custom["u"] as? String {
        if let url = URL.init(string: urlStr) {
            UIApplication.shared.open(url, options: [:], completionHandler: { (_) in
                /* 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:

// iOS9 handler for push notifications
// iOS9+10 handler for background data pushes (content-available)
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        if (UIApplication.shared.applicationState == UIApplicationState.inactive) {
            Kumulos.pushTrackOpen(notification: userInfo)
        }

        if let aps = userInfo["aps"] as? [AnyHashable:Any],
           let custom = userInfo["custom"] as? [AnyHashable:Any] {
            let contentAvailable = aps["content-available"]
            let data = custom["a"]
            // ...
        }

        completionHandler(UIBackgroundFetchResult.noData)
    }

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 KumulosPushChannels class in the Kumulos SDK.

let pushChannels = KumulosPushChannels(sdkInstance: Kumulos.getInstance())

Helper methods are then available for creating, listing and managing subscriptions to channels.

pushChannels.listChannels()
pushChannels.createChannel(uuid: String, subscribe: Bool, name: String? = nil, meta: [String:AnyObject]? = nil)
pushChannels.subscribe(uuids: [String])
pushChannels.unsubscribe(uuids: [String])
pushChannels.setSubscriptions(uuids: [String])
pushChannels.clearSubscriptions()

Each helper can then be provided a success and failure block to handle the result, for example.

pushChannels.createChannel(uuid: "the-channel-uuid", subscribe: true, name: "channel name", showInPortal: true)
.success{ (item) in
    print("create success")
    print(item)
}
.failure{ (error) in
    print("create failed")
    print(error)
}

Channel visibility and metadata

Channel visiblity and meta data can be controlled when they are created.

Location Tracking

You can send Kumulos location updates and use this to trigger automations such as sending 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.

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
  let latestLocation: CLLocation = locations[locations.count - 1]
  Kumulos.sendLocationUpdate(location: latestLocation)
}

iBeacon Detection

You can send Kumulos beacon proximity updates and use these to trigger automations such as sending a push notification when an install is in proximity to a beacon.

How you configure the Core Location services for iOS depends on the use case for your app and you should consider throttling how regularly these events are transmitted for both battery life and network traffic.

The Kumulos SDK provides a helper method to notify our services of proximity to a detected beacon.

Kumulos.sendiBeaconProximity(beacon: beacon)

The cookbook contains example code for how to notify Kumulos when an iBeacon is relatively close.

Build

You can call API methods defined in the Kumulos Build service using the Kumulos.call method.

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

Parameters

Parameters are provided as a Dictionary, simply add a key for each parameter your API method expects and pass it as the second parameter to the call method.

Kumulos.call("methodName", parameters: ["param1": "value", "param2": "value2"])
.success {
    (response, operation) in
    print(response.payload)
}
.failure {
    (error, operation) in
    // Handle failed call
}

Handling Results

The result of an API call will be returned as a KSResponse object, the response body can be accessed via the payload property.

if let _ = response.payload as? Array<AnyObject > {
    // Handle a select action result
    print("It's an array of objects!")
}

if let _ = response.payload as? UInt {
    // Handle a create/delete/update action result
    print("It's an integer!")
}

Handling data fields

Kumulos stores data fields as base64 encoded data, so if you receive data from Kumulos, you will have to base64 decode it to access the original data. Similarly, when you send data to Kumulos, you should base64 encode it before transport.

Crash

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.

let builder = KSConfigBuilder(apiKey: "your-api-key", secretKey: "your-secret-key").enableCrash()
Kumulos.initialize(config: builder.build())

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:

Kumulos.logException(name, reason, language, lineOfCode, stackTrace, logAllThreads);

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

Upload dSYM Files for Symbolication

In order to ensure your stack traces are fully symbolicated, it is necessary to upload your dSYM information from your project.

To upload dSYM files for Release builds, you should add a new "Run Script Phase" to your Xcode project's "Build Phases".

For CocoaPods installations, use this script:

"$PODS_ROOT/KumulosSdkSwift/upload_dsyms.sh" API_KEY SERVER_KEY

For Carthage installations, use this script:

"$SRCROOT/Carthage/Checkouts/KumulosSdkSwift/upload_dsyms.sh" API_KEY SERVER_KEY

Copy the script snippet into a new Run Script Phase as shown below:

Add a new Run Script Build Phase

Make sure you replace the API_KEY and SERVER_KEY tokens with your app's API and server keys which can be found on the application's dashboard.

Bitcode-enabled Builds

If your project has bitcode enabled, it will be necessary to upload the dSYM files that Apple generates as part of App Store distribution step.

These generated dSYM files can be downloaded using the Xcode Organizer. Once downloaded, the generated dSYM files will be available in your app's archive.

You should follow the steps of the screen capture below to prepare your symbols for upload.

Fetching & preparing generated dSYMs for upload

Once prepared for upload, you should upload the dSYM zip file to your App Delivery Console.

Changelog

2.2.0

  • Add iBeacon helper method

2.1.1

  • Add dSYM upload script to SDK distribution

2.1.0

  • Add custom event tracking
  • Capture session analytics events
  • Add user association helper
  • Fix intermittent build issues due to scheme setup

2.0.2

  • Move KSConfig.swift to Sources

2.0.1

  • Fix Podspec dependencies

2.0.0

  • Add crash reporting
  • Change to builder pattern for SDK configuration

1.4.0

  • Add geolocation update helper method
  • Add locale & bundle to stats payload
  • Fix SDK type in stats payload

1.3.0

  • Add CocoaPods support

1.2.0

  • Add push channel & push subscription management
  • Mark blocks with @discardableResult to tidy up warnings on unused results

1.1.0

  • Swift 3 conversion
  • Add iOS10 push notifications support

1.0.1

  • Fixed issue with push token registration to allow use of combined certificates for push auth

1.0.0

  • Initial release with RPC & Kumulos Push Notification support