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)
updateSessionId
instance method on the PulseSdk
class.
Notification Appearance¶
The Pulse SDK notification has five primary content elements:
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. |
![]() |
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. |
![]() |
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:
- Ask the user for location permission and notification permission (only for API version 33 or higher)
- 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.