Quickstart

Pre-requisite

Please make sure you are familiar with the Catalyst Platform before using this quick start here.

Tip

Take a note of your Android app's key and the endpoint url, as you'll need them to initialize the SDK later.

Compatibility

The Pulse library works with Android 4.3.1(API 18) to Android 13 (API 33) and with devices equipped with Bluetooth 4.0 or higher.

Integration Example

Use this Demo Application as a reference implementation for the SDK. Refer to PulseSdkApplication.java and MainActivity.java files in the respository for use of examples shared in this guide.

Installation


Add Pulse SDK

Add Pulse repository to your project's build.gradle file.

buildscript {
    repositories {
          mavenCentral()
           maven {
            url "https://repo1.maven.org/maven2"
        }
    }

Add following to your module’s build.gradle file:

android {
    ...
    packagingOptions {
        exclude 'META-INF/DEPENDENCIES.txt'
        exclude 'META-INF/LICENSE.txt'
        exclude 'META-INF/NOTICE.txt'
        exclude 'META-INF/NOTICE'
        exclude 'META-INF/LICENSE'
        exclude 'META-INF/DEPENDENCIES'
        exclude 'META-INF/notice.txt'
        exclude 'META-INF/license.txt'
        exclude 'META-INF/dependencies.txt'
        exclude 'META-INF/LGPL2.1'
    }
}

dependencies {
    ...
    implementation 'com.pulseid:pulse-sdk:5.1.2'
}

For build systems other than Gradle, please visit our Maven page

Access

If you're unable to use the Maven repository, contact support@pulseid.com to get installation package and instructions.

Integration


Initialize the SDK

In your main application class initialize the SDK and keep a reference to it as shown in the example below:

package com.pulseid.app;

import android.app.Application;

import com.pulseid.sdk.PulseSdk;
import com.pulseid.sdk.PulseSdkConfig;

public class PulseSdkApplication extends Application {
    public static final String TAG = "PulseSdkApplication";

    private static final String APP_KEY = "YOUR_APP_KEY"; // TODO: Replace with your own!
    private static final String APP_URL = "YOUR_APP_URL"; // TODO: Replace with your own!

    private static PulseSdkApplication application;
    private PulseSdk pulseSdk;

    @Override
    public void onCreate() {
        super.onCreate();

        application = this;

        PulseSdkConfig config = new PulseSdkConfig(APP_KEY, APP_URL);
        pulseSdk = new PulseSdk(this, config);
    }

    @Override
    public void onTerminate() {
        super.onTerminate();
    }

    public static PulseSdkApplication getInstance(){
        return application;
    }

    public PulseSdk getPulseSdk() {
        return pulseSdk;
    }
}

package com.pulse.demo

import android.app.Application

import com.pulseid.sdk.PulseSdk
import com.pulseid.sdk.PulseSdkConfig

class PulseSdkApplication : Application() {

    companion object {
        val TAG = "PulseSdkApplication"

        private val APP_KEY = "YOUR_APP_KEY" // TODO: Replace with your own!
        private val APP_URL = "YOUR_APP_URL" // TODO: Replace with your own!

        lateinit var instance: PulseSdkApplication
            private set
    }

    lateinit var pulseSdk: PulseSdk
        private set

    override fun onCreate() {
        super.onCreate()

        instance = this

        val config = PulseSdkConfig(APP_KEY, APP_URL)
        pulseSdk = PulseSdk(this, config)
    }
}

Tip

The PulseSdk can be Initialized with different modes.Click here for more detail.

Set the Session ID

The SDK relies on the session id parameter to uniquely identify a single user across multiple devices. This is optional. A valid session id is a 32 character hexadecimal string.

The custom session id needs to be set on the PulseSdkConfig class during initialization, as shown in the snippet bellow (based on the PulseSdkApplication example above):

@Override
public void onCreate() {
    super.onCreate();

    application = this;

    PulseSdkConfig config = new PulseSdkConfig(APP_KEY, APP_URL);
    String userId = SharedPreferenceHelper.getInstance(this).getUserId(); // Your app's custom user identifier
    config.setSessionId(userId);
    pulseSdk = new PulseSdk(this, config);
}

override fun onCreate() {
        super.onCreate()

        instance = this

        val config = PulseSdkConfig(APP_KEY, APP_URL)
        pulseSdk = PulseSdk(this, config)
        val userId = SharedPreferenceHelper.getInstance(this).getUserId() // Your app's custom user identifier
        config.setSessionId(userId)

If your use case requires that you set the session id after the SDK has been started, use the updateSessionId instance method on the PulseSdk class.

Notification Appearance

The Pulse SDK notification has five primary content elements:

Notification Anatomy

No. Content Description
1 Small Icon Mandatory small icon.Background color is transparent by default
2 App Name Set by the operating system
3 Notification Title Set by the operating system
4 Notification Content As set during the creation of the campaign
5 Large Icon Optional, large icon to be associated with each notification. None by default

Instructions to customize the notification appearance are below. Also refer to Android Notifications Design Guide regarding the notification design.

Small Icon

Warning

If the Small Icon is not set properly the SDK will not serve notifications.

The SDK will look for an icon named: ic_notification_above_lollipop.png in the drawable folders (drawable-hdpi, drawable-xhdpi, and etc.).

Example Folder
Refer to the demo app res folder for an example. Quickstart Capabilities

Background Color

Optionally, you can also customize the background color of the notification icon by adding the following property to the colors.xml file in the application project:

<color name="notification_icon_bg_color_above_lollipop">YOUR_COLOR_CODE</color>
Example Folder
Refer to the demo app's res/values folder for an example. Quickstart Capabilities

Large Icon

Optionally, you can provide an icon named: ic_notification_large_icon.png along side/in the same folders as the small icon and it will be used with every notification that the SDK displays to the users.

Start the SDK

Starting the SDK usually consists of two steps:

  1. Ask the user for location permission and notification permission (only for API version 33 or higher)
  2. Call SDK's start method

Both of these steps should be implemented in your main activity, as shown in the example below:

package com.pulseid.app;

import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

import com.pulseid.sdk.PulseSdk;

import static android.Manifest.permission.ACCESS_FINE_LOCATION;

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    private PulseSdk pulseSdk;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        pulseSdk = PulseSdkApplication.getInstance().getPulseSdk();
     }

     private void requestPermissions() {
       BackgroundLocation.checkLocationPermission(this);
       NotificationAccess.checkNotificationPermission(this);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
           super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            if (requestCode == BackgroundLocation.LOCATION_PERMISSION_CODE) {
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // User granted location permission
                    // For android level below 10 or api level 29
                    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
                        pulseSdk.start(ControlPanel.this);
                    }
                    // Now check if android version >= 11, if >= 11 check for Background Location Permission
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                        if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                            if (pulseSdk != null) {
                                pulseSdk.start(ControlPanel.this);
                            }
                        } else {
                            // Ask for Background Location Permission
                            BackgroundLocation.askPermissionForBackgroundUsage(this);
                        }
                    }
                } else {
                    // User denied location permission
                    BackgroundLocation.askForLocationPermission(this);
                }
            } else if (requestCode == BACKGROUND_LOCATION_PERMISSION_CODE) {
                if (grantResults.length == 2) {
                    if (grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
                        if (pulseSdk != null) {
                            pulseSdk.start(ControlPanel.this);
                        }
                    } else {
                        Snackbar.make(segmentKeyInput, "Permission denied please go to app settings.", Snackbar.LENGTH_LONG).show();
                    }
                } else if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Log.i(TAG, "Permission granted.");
                    //Start the SDK
                    if (pulseSdk != null) {
                        pulseSdk.start(ControlPanel.this);
                    }
                } else {
                    // User declined for Background Location Permission.
                    Snackbar.make(segmentKeyInput, "Permission denied please go to app settings.", Snackbar.LENGTH_LONG).show();
                }
            }

        }
}

package com.pulse.demo

import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import android.support.v4.app.ActivityCompat
import android.support.v7.app.AppCompatActivity
import android.util.Log

import com.pulseid.sdk.PulseSdk

import android.Manifest.permission.ACCESS_FINE_LOCATION
import kotlinx.android.synthetic.main.activity_demo.*

class MainActivity : AppCompatActivity() {

    private lateinit var pulseSdk: PulseSdk

    companion object {
        private val TAG = "MainActivity"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(com.pulse.demo.R.layout.activity_demo)

        sdkVersionName.text = BuildConfig.VERSION_NAME

        pulseSdk = PulseSdkApplication.instance.pulseSdk

    }

    private fun requestPermissions() {
        BackgroundLocation.checkLocationPermission(this)
        NotificationAccess.checkNotificationPermission(this)
    }


    public fun onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
           super.onRequestPermissionsResult(requestCode, permissions, grantResults);
           if (requestCode == BackgroundLocation.LOCATION_PERMISSION_CODE) {
          if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
              // User granted location permission
              // For android level below 10 or api level 29
              if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
                  pulseSdk.start(ControlPanel.this);
              }
              // Now check if android version >= 11, if >= 11 check for Background Location Permission
              if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                  if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                      if (pulseSdk != null) {
                          pulseSdk.start(ControlPanel.this);
                      }
                  } else {
                      // Ask for Background Location Permission
                      BackgroundLocation.askPermissionForBackgroundUsage(this);
                  }
              }
          } else {
              // User denied location permission
              BackgroundLocation.askForLocationPermission(this);
          }
      } else if (requestCode == BACKGROUND_LOCATION_PERMISSION_CODE) {
          if (grantResults.length == 2) {
              if (grantResults[0] == PackageManager.PERMISSION_GRANTED && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
                  if (pulseSdk != null) {
                      pulseSdk.start(ControlPanel.this);
                  }
              } else {
                  Snackbar.make(segmentKeyInput, "Permission denied please go to app settings.", Snackbar.LENGTH_LONG).show();
              }
          } else if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
              Log.i(TAG, "Permission granted.");
              //Start the SDK
              if (pulseSdk != null) {
                  pulseSdk.start(ControlPanel.this);
              }
          } else {
              // User declined for Background Location Permission.
              Snackbar.make(segmentKeyInput, "Permission denied please go to app settings.", Snackbar.LENGTH_LONG).show();
          }
      }
   }
}


Background Location
This is custom code for accessing the background location in a incremental manner in according to Android guidelines for background location access.

public class BackgroundLocation {
    public static int LOCATION_PERMISSION_CODE = 1;
    public static int BACKGROUND_LOCATION_PERMISSION_CODE = 2;

    public static void checkLocationPermission(Activity context) {
        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
            ActivityCompat.requestPermissions((Activity) context,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_BACKGROUND_LOCATION}, BACKGROUND_LOCATION_PERMISSION_CODE);
        } else {
            if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                // Fine Location permission is granted
                // Check if current android version >= 11, if >= 11 check for Background Location permission
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                    if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED) {
                        // Background Location Permission is granted so do your work here
                    } else {
                        // Ask for Background Location Permission
                        context.shouldShowRequestPermissionRationale(Manifest.permission.ACCESS_BACKGROUND_LOCATION);
                        askPermissionForBackgroundUsage(context);
                    }
                }

            } else {
                // Fine Location Permission is not granted so ask for permission
                askForLocationPermission(context);
            }
        }
    }

    public static void askForLocationPermission(final Context context) {
        if (ActivityCompat.shouldShowRequestPermissionRationale((Activity) context, Manifest.permission.ACCESS_FINE_LOCATION)) {
            new AlertDialog.Builder(context)
                    .setTitle("Permission Needed!")
                    .setMessage("Location Permission Needed!")
                    .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            ActivityCompat.requestPermissions((Activity) context,
                                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_PERMISSION_CODE);
                        }
                    })
                    .setNegativeButton("CANCEL", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            // Permission is denied by the user
                        }
                    })
                    .create().show();
        } else {
            ActivityCompat.requestPermissions((Activity) context,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_PERMISSION_CODE);
        }
    }

    public static void askPermissionForBackgroundUsage(final Context context) {
        if (ActivityCompat.shouldShowRequestPermissionRationale((Activity) context, Manifest.permission.ACCESS_BACKGROUND_LOCATION)) {
            new AlertDialog.Builder(context)
                    .setTitle("Permission Needed!")
                    .setMessage("Background Location Permission Needed!, tap \"Allow all time in the next screen\"")
                    .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            ActivityCompat.requestPermissions((Activity) context,
                                    new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION}, BACKGROUND_LOCATION_PERMISSION_CODE);
                        }
                    })
                    .setNegativeButton("CANCEL", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            // User declined for Background Location Permission.
                        }
                    })
                    .create().show();
        } else {
            ActivityCompat.requestPermissions((Activity) context,
                    new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION}, BACKGROUND_LOCATION_PERMISSION_CODE);
        }
    }
}


Notification Permission
This is custom code for request the notification permission in a incremental manner in according to Android guidelines for show notifications in android 13 and above.

public class NotificationAccess {

    public static int NOTIFICATION_PERMISSION_CODE = 101;

    public static void checkNotificationPermission(Activity context) {
        if (Build.VERSION.SDK_INT >= 33) {
            if (ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(context, new String[]{Manifest.permission.POST_NOTIFICATIONS},NOTIFICATION_PERMISSION_CODE);
            }
        }
    }

}

Next Steps


Different Modes of Operation

The SDK can Initialized with different modes i.e Foreground mode, Background mode and background mode with foreground mode together.Refer to Different Modes of Operation for more detail.

Integration Tests

Refer to integration test guide to verify that SDK integration is working correctly.

Stop the SDK

Pulse iD interactions can be force stopped if required. This feature can be used to implement custom user controls within the app to allow users to opt-in/out of using Pulse-powered features.

Use the instance method stop() on the PulseSdk class.

Warning

Due to the async nature of the SDK it might take up to one minute for it completely stop. See the Lifecycle Events section, if you want to listen to this event.

Deep Linking

If are deploying deep linking Campaigns, please refer to these integration steps.

Set Segments

If you are targetting specific audiences using segment based Campaigns, please refer to the addSegments method to pass the relevant information from the app to the Catalyst Platform for targetting.