Integration

Kumulos provides an SDK in the form of an NPM package to ease the integration of the Kumulos Analytics, Push Notification and Build features into your React Native apps.

Installation & Linking

The Kumulos React Native module requires native features so should be installed in an ejected project.

To install & link the project, run the following commands:

npm install kumulos-react-native --save
react-native link kumulos-react-native

Manual linking steps are required depending on platform. See the following sections for the necessary steps.

iOS Linking Steps (required)

To complete the linking process for iOS, it is necessary to manually link the data model file used by Kumulos for offline event persistence.

To link the data model:

  1. Open the Xcode project for your react native app
  2. Locate the linked kumulos library project
  3. Drag the KAnalyticsModel.xcdatamodel file from the kumulos project to the root of your app project
Linking the data model in Xcode

Android Linking Steps (required)

To complete the linking process for Android, you need to ensure your project uses the following versions for tools & libraries:

  • Gradle plugin v3.1.3 or greater
  • Build tools v23.0.3 or greater
  • Support library v27.+

In addition, you must add the following to your android/app/build.gradle file:

android {
    ...

    defaultConfig {
        ...

        manifestPlaceholders = [
                kumulos_gcm_sender_id: ''
        ]
    }

    packagingOptions {
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/ASL2.0'
        exclude 'META-INF/LICENSE'
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

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 calling API methods and using features.

import Kumulos from 'kumulos-react-native';

Kumulos.initialize({
    apiKey: 'YOUR_API_KEY',
    secretKey: 'YOUR_SECRET_KEY'
});

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

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!

That's it, you're now good to go! Continue reading to learn more about analytics, configuring push notifications and calling Build API methods in your app.

Installation ID

When initialized for the first time, the Kumulos SDK will create a unique identifier for the current installation. This identifier can be used to target push notifications to a specific device via KScript or the Push Notifications API.

In order to retrieve this identifier, simply access the class variable:

const id = await Kumulos.getInstallId();

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

So long as you initialize the SDK at some point in your app's lifecycle, Kumulos will automatically record analytics data such as the device model, operating system version and more, available in Analytics & Reporting for your app.

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('product.purchased', {
    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

Alternatively, to see counts of all analytics events, including system events such as opened a push notification, recorded by installs of the app in the last 30 days, expand 'Analytics' and click 'Explore' in the left menu. For comparison, the total number of sessions in the same period is shown.

Analytics Explorer

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. You can also optionally associate a collection of attributes with the user.

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

Kumulos.associateUserWithInstall('unique-user-id');

User association is time-aware, so say two different users 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('Bob');
// This event will belong to Bob
Kumulos.trackEvent('product.purchased', null);
Kumulos.associateUserWithInstall('Alice');
// This event will belong to Alice
Kumulos.trackEvent('product.purchased', null);

Attributes

You can optionally associate a collection of attributes with the user for targeting, personalization or attribution. To associate attributes with the user, pass a collection into the helper method as shown.

const attributes = {
    name: 'Shawn',
    age: 25
};

Kumulos.associateUserWithInstall('unique-user-id', attributes);

If you do not have a user identifier, use the installation ID generated by the Kumulos SDK.

Push

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

Integration

The Kumulos SDK provides utility methods to handle push tokens, with push registration being performed by the defacto standard modules.

To use push notifications, install & link the additional dependencies:

npm install react-native-push-notification --save
react-native link react-native-push-notification

For iOS, you will also need to manually link PushNotificationIOS.

For Android, you need to set up the Android project correctly.

Note you also need to enable the "Push Notifications" capability and "Remote notifications" background mode in your iOS project, and ensure that provisioning is set up correctly.

After integration has been completed, you can configure the APNS or GCM projects as follows.

Configuring APNS

Configuring APNS for iOS with Kumulos

Configuring GCM

Configuring GCM for Android with Kumulos

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

After this setup has been completed, you can continue with the client integration.

Registering for and handling Push Notifications

The following sample code shows how to set up handlers using Kumulos and the React Native push notifications plugin to handle the most common push scenarios.

// index.js
import PushNotification from 'react-native-push-notification';
import configurePush from './push';

...

configurePush();

When you are ready to request the push token from the user, you would then call:

PushNotification.requestPermissions();

The push configuration helper is shown below. This sample handles push conversion tracking and URL pushes for you, and can be adapted to suit your needs.

// push.js
import { Linking, Platform } from 'react-native';
import Kumulos from 'kumulos-react-native';

import PushNotification from 'react-native-push-notification';

function sendLocalNotification(notification) {
    let opts = {};

    if (Platform.OS === 'android') {
        opts.title = notification.title;
        opts.message = notification.alert;
        opts.data = notification.custom;
    }
    else if (Platform.OS === 'ios') {
        opts.title = notification.alert.title;
        opts.message = notification.alert.body;
        opts.userInfo = notification.data.custom;
    }

    PushNotification.localNotification(opts);
}

function handleNotificationReceived(notification) {
    if (Platform.OS === 'android' && !notification.bgn) {
        sendLocalNotification(notification);
    }
}

function handleNotificationOpened(notification) {
    let customFields = {};

    if (Platform.OS === 'android') {
        customFields = notification.data;
    }
    else if (Platform.OS === 'ios') {
        customFields = notification.data.custom;
    }

    // Track push open conversion
    Kumulos.pushTrackOpen(customFields['i']);

    // Handle URL push, open in browser
    if (customFields['u']) {
        let url = customFields['u'];
        Linking.canOpenURL(url).then(supported => {
            if (!supported) {
            } else {
                return Linking.openURL(url);
            }
        }).catch(err => console.error('An error occurred', err));
    }

    // Take any other desired action, deep linking etc.
}

function handleNotification(notification) {
    console.info(notification);
    if (notification.userInteraction === false) {//received
        handleNotificationReceived(notification);
    }
    else {//opened
        handleNotificationOpened(notification);
    }
}

export default function configurePush() {
    const options = {
        senderID: "YOUR GCM SENDER ID",
        onRegister: function (tokenObj) {
            Kumulos.pushStoreToken(tokenObj.token);
        },
        onNotification: notification => handleNotification(notification),
        requestPermissions: false,
        popInitialNotification: false
    };

    PushNotification.configure(options);
}

If you want to unregister the token for the current installation, you can use Kumulos.pushRemoveToken().

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

Push channels

You can create and manage subscriptions to push channels from the SDK. Channels allow you to send push notifications to certain interest groups.

All channel management is performed through methods of the PushSubscriptionManager class.

const subManager = Kumulos.getPushSubscriptionManager();

The interface of the subscription manager is as follows:

export interface PushChannel {
    uuid: string;
    name?: string;
    subscribed: Boolean;
    meta?: any;
}

export interface ChannelSpec {
    uuid: string;
    subscribe: boolean;
    meta?: any;
    name?: string;
    showInPortal?: boolean;
}

interface PushSubscriptionManager {
    constructor(client: KumulosClient);
    /**
     * Subscribes to the channels given by unique ID
     */
    subscribe(uuids: string[]): Promise<Response>;
    /**
     * Unsubscribes from the channels given by unique ID
     */
    unsubscribe(uuids: string[]): Promise<Response>;
    /**
     * Sets the current installations channel subscriptions to those given by unique ID.
     *
     * Any other subscriptions will be removed.
     */
    setSubscriptions(uuids: string[]): Promise<Response>;
    /**
     * Clears all of the existing installation's channel subscriptions
     */
    clearSubscriptions(): Promise<Response>;
    /**
     * Lists the channels available to this installation along with subscription status
     */
    listChannels(): Promise<PushChannel[]>;
    /**
     * Creates a push channel and optionally subscribes the current installation.
     *
     * Name is optional, but required if showInPortal is true.
     */
    createChannel(channelSpec: ChannelSpec): Promise<PushChannel>;
}

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

Location Tracking

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

Once you have configured location updates on the platform of choice you can send the updates to Kumulos via the helper method in the stats namespace.

Kumulos.sendLocationUpdate(-54.618946, -65.234551);

For information on receiving location updates, see the React Native Geolocation documentation.

Beacons

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.

The Kumulos SDK provides helper methods to notify our services of proximity to a detected beacon. Helpers for both Eddystone and iBeacon protocols are provided.

You will need to integrate a suitable plugin to detect the beacon proximity events (for example, react-native-beacons-manager).

Eddystone Beacon Detection

Kumulos.trackEddystoneBeaconProximity({
    hexNamespace: 'namespace',
    hexInstance: 'instance',
    distanceMetres: 10
});

Beacon monitoring on Android typically requires a device with BLE, and API level 18+. You can read more about detecting beacons in the Android Nearby reference.

iBeacon Detection

Kumulos.trackiBeaconProximity({
    uuid: 'vendor-uuid',
    major: 1,
    minor: 2
});

Build

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

To talk to Kumulos, you need two things:

  • your method title (in lowerCamelCase)
  • an (optional) parameters object

Kumulos.call returns a promise, see example usage below:

const params = {
    user: '[email protected]'
};

try {
    const data = await Kumulos.call("yourMethodName", params);
}
catch (err) {
    console.error(err);
}

And you're done! You can now make calls to Kumulos from your React Native application. The data object returned by Kumulos.call can be either an array of objects (in case of a select action) or a number in case of other actions.

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 configuration as follows:

Kumulos.initialize({
    apiKey: 'YOUR_API_KEY',
    secretKey: 'YOUR_SECRET_KEY',
    enableCrashReporting: true
});

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

For React Native, the crash reporting feature includes both native code crash reporting, and JavaScript error reporting. Native code crash reporting would catch crashes of the React Native host process, whilst JavaScript error reporting catches unhandled errors in your application source code.

Source Mapping

When you build your React Native app for production, you will generate a minified JavaScript bundle.

In order to show source file locations for any JS error traces, you need to do the following:

  • Generate a source map for the main JavaScript bundle for each platform
  • Set the sourceMapTag field in the Kumulos initialization options
  • Upload source maps matching the version of the configured sourceMapTag

For example, during initialization:

Kumulos.initialize({
    apiKey: 'YOUR_API_KEY',
    secretKey: 'YOUR_SECRET_KEY',
    enableCrashReporting: true,
    // Configure the version for the source maps
    sourceMapTag: '1.0.0-rc1'
});

To build the minified JS bundles with source maps, the following command can be used:

react-native bundle --dev false --platform ios --entry-file index.js --bundle-output main.jsbundle --sourcemap-output main.jsbundle.map

Now you would upload the source maps for version 1.0.0-rc1 to the Crash Dashboard in your App Delivery Console.

If you are automating your builds, you can upload the source maps from your CI environment. See the following sample script for reference.

#!/bin/sh
# TODO set version to match the configured sourceMapTag in the SDK init options
VERSION=''

# TODO set up the keys from your App Dashboard
API_KEY='YOUR_API_KEY'
SERVER_KEY='YOUR_SERVER_KEY'

# TODO customize the archiving step to include your source maps
zip -r maps.zip main.jsbundle.map

UPLOAD_URL='https://crash.kumulos.com/sourcemaps'

curl --fail --retry 3 --retry-delay 3 --user "$API_KEY:$SERVER_KEY" -X POST -F version="$VERSION" -F file="@maps.zip" "$UPLOAD_URL"
rm maps.zip

N.B. Due to an issue with the Metro bundler, source maps generated by React Native < 0.56 with minification enabled may not be processed correctly

Troubleshooting

iOS: Duplicate Symbol Errors when Using Other Crash Reporting Tools

If you intend to use a third party crash reporting tool instead of Kumulos, you may encounter duplicate symbol errors during the iOS project build step.

This happens when the other crash reporting tool also depends on the KSCrash library which Kumulos uses for native exception handling.

In order to resolve the duplicate symbol issue, you can strip the KSCrash symbols from the Kumulos static library with the following script.

Once the script has been run, it will produce a libKumulosSDKiOS-nocrash.a library which can then be linked in the Ract Native iOS project instead of the libKumulosSDKiOS.a library file.

#!/bin/sh

# This script strips out KSCrash symbols from the Kumulos SDK static library.
# This is necessary when using another crash reporting tool based on KSCrash.
#
# The script should be run from the directory of the Kumulos library file.
# After running, it will produce a -nocrash.a library file. This file can then
# be linked in the project instead of the default library.

COMBINED_LIB="libKumulosSDKiOS.a"
ARCHS="armv7 arm64 x86_64 i386"

if [ ! -f $COMBINED_LIB ]; then
    echo "$COMBINED_LIB not found, aborting!"
    exit 1
fi

ROOT="$PWD"
WRK_DIR=`mktemp -d -t k`

for arch in $ARCHS; do
    echo "Processing architecture $arch"

    ARCH_DIR="$WRK_DIR/$arch"

    # Split out the architecture slice from the library
    mkdir -p $ARCH_DIR
    ARCH_LIB="$ARCH_DIR/libKumulosSDKiOS-$arch.a"
    lipo -thin $arch $COMBINED_LIB -output $ARCH_LIB

    # Extract the object files
    cd $ARCH_DIR
    ar -x "libKumulosSDKiOS-$arch.a"

    # Remove KSCrash object files
    rm  KSCrash* \
        KSObjC.o \
        NSError+SimpleConstructor.o \
        Container+DeepSearch.o \
        KSCPU* \
        Demangle.o \
        KSCString.o \
        KSDate.o \
        KSDebug.o \
        KSDemangle* \
        KSDynamicLinker.o \
        KSFileUtils.o \
        KSID.o \
        KSJSON* \
        KSLogger.o \
        KSMach* \
        KSReachability* \
        KSStack* \
        KSSignal* \
        KSSymbolicator.o \
        KSSysCtl.o \
        KSThread.o \
        Punycode.o \
        NSData+GZip.o \
        NSMutableData+AppendUTF8.o \
        KSMemory.o \
        KSString.o

    # Combine back into a static library
    libtool -static *.o -o "../libKumulosSDKiOS-$arch-nocrash.a"
    cd $ROOT

done

# Bundle up a combined library with all architectures again
lipo -create "$WRK_DIR/"*-nocrash.a -output libKumulosSDKiOS-nocrash.a

# Cleanup
rm -rf "$WRK_DIR"

Changelog

2.0.0

  • Wrap native SDKs in native modules to improve maintainability & feature parity
  • Add session analytics events
  • Add custom event tracking
  • Add user association with attributes
  • Add beacon proximity helpers

Breaking Changes

  • SDK interface now matches static singleton of other SDKs
  • Manual linking steps now required for iOS & Android
  • New Android tooling version dependencies

1.0.0

  • Initial release with Analytics, Push, and Build support for iOS & Android