Android Integration: v.4+
Last Updated: Tuesday, July 26, 2022
The following information will show you how to integrate the Vibes Push Notifications SDK into an Android app.
The example-java and example-kotlin example apps in the SDK repository are also available to show you how to implement the SDK.
Key Integration Steps
- Implement basic device and push registration to simple push notifications.
- Enable association of push to device API or SDK call. This will make a user "known" and allow for platform targeting and segmentation. Note: If you are using cross channel segmentation between channels, the
external_person_id
must be the same in the SMS, Push, and Wallet channels. - Add advanced push options: rich push, notification sounds, deep linking, etc (Optional)
- Add app inbox support (Optional)
Note: Platform accounts are available via the platform for development and UAT testing.
App Configuration
Set the Vibes app ID in your AndroidManifest.xml, inside your block. You can retrieve your app ID by contacting your Vibes Account Manager.
<meta-data android:name="vibes_app_id" android:value="vibesAppId" />
If you want to update the default Vibes endpoint (to point to a different Vibes instance) you can specify the following in your AndroidManifest.xml:
<!-- WARNING: This is only if you want to change the default Vibes endpoint --> <meta-data android:name="vibes_api_url" android:value="${vibesAppUrl}" />
In your build.gradle (app):
android {
defaultConfig {
manifestPlaceholders = \[vibesAppId:"[YOUR APP ID]"]
}
...
}
or if you want to change the Vibes endpoint:
android {
defaultConfig {
manifestPlaceholders = \[vibesAppId: "[YOUR APP ID]",
vibesAppUrl: "[Vibes non Default endpoint]"]
}
...
}\
An alternative way to configure the Vibes SDK is through a programmatic means, such as creating an instance of the VibesConfig. You can use it to initialize the SDK in the main entry point to your app and then call any of the desired Vibes SDK methods such as _registerDevice
class DemoApplication extends MultiDexApplication(){
public void onCreate() {
super.onCreate();
String appId="abcd1234";
String serverUrl= "vibesAppUrl";
VibesConfig config = new VibesConfig.Builder()
.setApiUrl(appUrl)
.setAppId(appId).build();
Vibes.initialize(context, config);
...
} }
You must reset the Vibes default endpoint if you want to use the Vibes Platform Europe instance, as defined in Technical Details.
- Default Vibes Push endpoint (US): https://public-api.vibescm.com/mobile_apps
- Vibes Push Europe endpoint (UK): https://public-api.vibescmeurope.com/mobile_apps
Registering a Device
Use the following code to register a device. You can add the code wherever it is most appropriate for your application. You may find that an onCreate for your main Activity or custom Application-subclass is the best place.
// NOTE: the VibesListener is optional; you can ignore it if you don't care
// about the result of the registration.
Vibes.getInstance().registerDevice(new VibesListener<Credential>() {
@Override
public void onSuccess(Credential value) {
}
@Override
public void onFailure(String errorText) {
}
});
Unregistering a Device
Use the following code to unregister a device. You can add the code wherever it makes the most sense for your application:
// NOTE: the VibesListener is optional; you can ignore it if you don't care
// about the result of the unregistration.
Vibes.getInstance().unregisterDevice(new VibesListener<Void>() {
@Override
public void onSuccess(Void value) {
}
});
Push Messaging
Registering for Push
Use the following code to register for push. You can add it wherever it makes the most sense for your application:
// NOTE: the VibesListener is optional; you can ignore it if you don't care
// about the result of the unregistration.
String pushToken = FirebaseInstanceId.getInstance().getToken();
Vibes.getInstance().registerPush(pushToken, new VibesListener<Void>() {
@Override
public void onSuccess(Void value) {
} @Override
public void onFailure(String errorText) {
}
});
Unregistering for Push
Use the following code to unregister for push. You can add it wherever it makes the most sense for your application:
// NOTE: the VibesListener is optional; you can ignore it if you don't care
// about the result of the unregistration.
Vibes.getInstance().unregisterPush(new VibesListener<Void>() {
@Override
public void onSuccess(Void value) {
}
@Override
public void onFailure(String errorText) {
}
});
Update Device
A developer may want to submit period updates about changes in state from devices to the Vibes platform to make sure that targeting information is up to date. The most up-to-date device information (device timezone, your app version, vibes SDK version etc) will be submitted, as well as GPS location changes if it is enabled by the user of the app and the developer is collecting that information.
Vibes.getInstance().updateDevice(final boolean updateCredentials, Double latitude, Double longitude, new VibesListener<Credential>() {
@Override
public void onSuccess(Credential credential) {
...
}
@Override
public void onFailure(String s) {
...
}
});
It is recommend to false as the value for updateCredentials, unless you want to update the credentials with which the device connects to the Vibes platform.
Event Tracking
The events are automatically triggered by the SDK. If a device is not registered, the events will be stored locally and the next time the device is registered, the events will be sent to the Vibes back end. Nothing needs to be configured.
Events currently available:
- launch
- clickthru
- pushrecieved
Push Notification Handling with Vibes
To handle your push notifications with default behavior, simply override the FirebaseMessagingService and call the handleNotification method provided by Vibes.
public class FMS extends FirebaseMessagingService {
@Override
public void onMessageReceived(RemoteMessage message) {
Vibes.getInstance().handleNotification(getApplicationContext(), message.getData());
}
}
Handling and Recording User Interactions with Push Messages
Android allows the registration of an instance of android.content.BroadcastReceiver in the AndroidManifest.xml to handle a user’s interaction with a push message, and possibly collect information on such interactions. The Vibes SDK provides a default implementation of this BroadcastReceiver, which can be integrated into your Android app by making the following entry in the AndroidManifest.xml.
<receiver android:name="com.vibes.vibes.VibesReceiver">
<intent-filter>
<category android:name="${applicationId}" />
<action android:name="com.vibes.action.push.OPENED" />
<action android:name="com.vibes.action.push.DISMISSED" />
<action android:name="com.vibes.action.push.RECEIVED" />
</intent-filter>
</receiver>
This VibesReceiver instance reports back a click-through event to your campaign whenever a user actually opens a push message. In other words, it handles the “com.vibes.action.push.OPENED” event as registered in the manifest file above.
Handling Additional Events
While basic handling and recording of user interactions with push messages may be enough to know how your users are responding to your events, there are two other events that one can handle if desired. These are:
- com.vibes.action.push.DISMISSED
- com.vibes.action.push.RECEIVED
To do so, you may extend the com.vibes.vibes.VibesReceiver as follows:
public class NotificationBroadcastReceiver extends VibesReceiver {
@Override
protected void onPushOpened(Context context, PushPayloadParser pushModel) {
Log.d("OPENED", "Push was opened");
}
@Override
protected void onPushDismissed(Context context, PushPayloadParser pushModel) {
Log.d("DISMISSED", "Push was dismissed");
}
@Override
protected void onPushReceived(Context context, PushPayloadParser pushModel) {
Log.d("RECEIVED", "Push was received");
}
}
Your receiver then will need to replace the VibesReceiver in the AndroidManifest in the following way:
<receiver android:name=".NotificationBroadcastReceiver">
<intent-filter>
<category android:name="${applicationId}" />
<action android:name="com.vibes.action.push.OPENED" />
<action android:name="com.vibes.action.push.DISMISSED" />
<action android:name="com.vibes.action.push.RECEIVED" />
</intent-filter>
</receiver>
Deep Linking
If you’re using the above method to handle push notifications, you can launch a custom activity from the subclass of the VibesReceiver.
Deep linking in Android 12+
Because of a change made in Android 12, the following code will only work for Android 11 and earlier. To trigger the opening of any activity after a user opens a push notification from your app, please see our Android 12 deep-link resolution.
public class NotificationBroadcastReceiver extends VibesReceiver {
@Override
protected void onPushOpened(Context context, PushPayloadParser pushModel) {
if (pushModel.getDeepLink() != null) {
Intent deepLinkIntent = new Intent(context, DeepLinkActivity.class);
deepLinkIntent.putExtra(Vibes.VIBES_REMOTE_MESSAGE_DATA, pushModel.getMap());
context.startActivity(deepLinkIntent);
} else {
Intent mainActivityIntent = new Intent(context, MainActivity.class);
mainActivityIntent.putExtra(Vibes.VIBES_REMOTE_MESSAGE_DATA, pushModel.getMap());
context.startActivity(mainActivityIntent);
}
}
}
Customizing a Push Notification
If you require more customization to build the notification, implement a subclass of com.vibes.vibes.NotificationFactory and override the getBuilder method as follows:
public class MyNotificationFactory extends NotificationFactory {
public MyNotificationFactory(Context context) {
super(context);
}
/**
* Customize the notification built
*/
@Override
public NotificationCompat.Builder getBuilder(PushPayloadParser pushModel, Context context) {
// Be sure to call to super to ensure the default settings are used
// Afterwards the notification can be customized.
// NOTE: Changing the contentIntent or deleteIntent will prevent VibesReceviers from
// getting callbacks.
return super.getBuilder(pushModel, context)
.setSmallIcon(R.drawable.firebase_icon);
}
}
This implementation needs to be registered with the Vibes SDK by doing so in your extension of the FirebaseMessagingService.onMessage() method, as shown below:
public class FMS extends FirebaseMessagingService {
@Override
public void onMessageReceived(RemoteMessage message) {
Vibes.getInstance().setNotificationFactory(new MyNotificationFactory(getApplicationContext(),));
Vibes.getInstance().handleNotification(getApplicationContext(), message.getData
}
}
Default Icons
You can use Android Asset Studio to generate a default icon for your push notifications. The default icon will then be displayed on every push notification received and is displayed in the toolbar whether the app is in the foreground or the background.
To generate notification icons with the correct settings using the Android Asset Studio, be sure to enter the icon name as ic_stat_vibes_notif_icon, which is the name that the SDK looks for as the default icon for push notifications.
You can use icons with a different name, but to do so, you will need to override the NotificationFactory to use your icon instead of the default icon. For example, if your icon is named my_notification_icon
, then you can set that using .setSmallIcon(R.drawable.my_notification_icon);, as shown in the override of NotificationFactory below.
public class MyNotificationFactory extends NotificationFactory {
public MyNotificationFactory(Context context) {
super(context);
}
@Override
public NotificationCompat.Builder getBuilder(PushPayloadParser pushModel, Context context) {
// Be sure to call to super to ensure the default settings are used
return super.getBuilder(pushModel, context)
.setSmallIcon(R.drawable.my_notification_icon);
}
}
If you use your own icons, please ensure they are the correct size, for example:
mdpi - 24x24px
hdpi - 36x36px
xhdpi - 48x48px
xxhdpi - 72x72px
Notification Sound
If your application contains a custom sound for push notification, you can specify this sound on the Vibes Platform.
The specified sound should be part of the resources found in the /res/raw folder. Sound and channel will bind together if custom sound is triggered, so best practice is to have a unique channel name for each sound.
The push payload received will look like the following:
{
"to":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"data":{
"body":"Vibes Push SDK",
"title":"Implementing Push is Fun",
"sound":"sound.filename",
"message_uid":"ftgybd1b-e473-hue8-abf6-8d7929467dhe"
}
}
Custom Properties
You can specify custom data on the Vibes Platform. The push payload received will look like the following:
{
"to":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"data":{
"body":"Vibes Push SDK",
"title":"Implementing Push is Fun",
"client_custom_data":{
"key1":"val1",
"key2":"val2"
},
"message_uid":"ftgybd1b-e473-hue8-abf6-8d7929467dhe"
}
}
In your application, you can retrieve the custom data as follows:
public class FMS extends FirebaseMessagingService {
/**
* @see FirebaseMessagingService#onMessageReceived(RemoteMessage)
*/
@Override
public void onMessageReceived(RemoteMessage message) {
PushPayloadParser pushModel = Vibes.getInstance().createPushPayloadParser(message.getData());
JSONObject customClientData = pushModel.getCustomClientData();
if (customClientData != null) {
// Do something with the custom keys values.
}
}
}
Notification Channel
With Android O and above, the behavior of push notifications is determined by properties set in push notification channels related to each message. The Vibes SDK automatically creates a VIBES1 channel and associates all push messages handled by the SDK with that channel. However, you may specify a new channel that a message can be linked to when received.
Custom sound and channel will bind together if custom sound is triggered. In order to play a sound consistently, best practice would be to designate a unique channel name for each sound. The Vibes SDK will create a notification channel called “default_channel” if it doesn’t exist, with default values for properties like priority, sound, and lights behavior.
The push payload received will look like the following :
{
"to":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"data":{
"body":"Vibes Push SDK",
"title":"Implementing Push is Fun",
"notification_channel":"default_channel",
"message_uid":"ftgybd1b-e473-hue8-abf6-8d7929467dhe"
}
}
Priority
With Android O and above, you can define the notification priority when you create the local notification. This is applied during the process of creating a new notification channel but is ignored if the notification channel already exits. The push payload received will look like the following :
{
"to":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"data":{
"body":"Vibes Push SDK",
"title":"Implementing Push is Fun",
"notification_channel":"thisismynotificationchannel",
"priority":"normal", // or "high"
"message_uid":"ftgybd1b-e473-hue8-abf6-8d7929467dhe"
}
}
The two possible values for priority are Normal and High.
Rich Media: Image
You can define the image URL in the Vibes Platform. The push payload received will look like the following:
{
"to":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"data":{
"body":"Vibes Push SDK",
"title":"Implementing Push is Fun",
"client_app_data":{
"image_url" : "[URL to your image]",
},
"message_uid":"ftgybd1b-e473-hue8-abf6-8d7929467dhe"
}
}
The Vibes SDK will then use your supplied URL to appropriately render the image in the push notification.
Silent Push
On the Vibes Platform, you can specify to send a push notification as a silent push. The push payload received will look like the following:
{
"to":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"data":{
...
"silent_push": "true",
...
"client_custom_data":{
"key1":"val1",
"key2":"val2"
},
}
}
In your application, you can use the following to handle the push notification data and perform some actions without interrupting the user with a notification.
public class FMS extends FirebaseMessagingService {
/**
* @see FirebaseMessagingService#onMessageReceived(RemoteMessage)
*/
@Override
public void onMessageReceived(RemoteMessage message) {
PushPayloadParser pushModel = Vibes.getInstance().createPushPayloadParser(message.getData());
if (pushModel.isSilentPush()) {
// Handle data from pushModel.getCustomClientData() or do some work
} else {
// Create the local notification
}
}
}
Vibes Collapse ID
On the Vibes Platform, you can choose to define a vibes_collapse_id for the push notification. If a vibes_collapse_id is received, and two push notifications are sent to a customer, the latest push notification will replace the previous push notification. The user will see only the latest push notification in the top status bar. The push payload received will look like the following:
{
"to":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"data":{
"body":"Vibes Push SDK",
"title":"Implementing Push is Fun",
"vibes_collapse_id":"collapseKey",
...
}
}
Push Handling Examples
You can check out the example-java and example-kotlin example apps in the SDK repository for examples that re-implement android.content.BroadcastReceiver by navigating to a new Intent based on the user viewing the notification.
In these examples, the Vibes Platform is not even notified of the the click-thru event.
Person Management
Since v 4.0.0, it is now possible to fetch a Person record, which is also accessible via the Person API as documented here.
The Structure of a Person
A Person exposes the following methods for obtaining information more information.
Method | Comment |
---|---|
public String getPersonKey() | Returns the UUID that uniquely identifies the user associated with the device. |
public String getMdn() | Returns the MDN of the user associated with the device. |
public String getExternalPersonId() | Returns the external_person_id that may have been specified for this user associated with the person. |
Fetching the Person Record
The person associated with the device can be obtained by calling the getPerson method on the Vibes SDK.
Vibes.getInstance().getPerson(newVibesListener \< Person > () {
@OverridepublicvoidonSuccess(Personmessage) {}
@OverridepublicvoidonFailure(StringerrorText) {}
});
App Inbox
Inbox support is now available in 4.0.0 and later of the Vibes Push SDK. The current feature set only enables obtaining and updating these inbox messages and does not provide any UI components for rendering these inbox messages.
The Structure of an InboxMessage
An inbox may be constructed within your app using the Vibes Inbox components to match the design of your app. Here is an example of simple inbox construction, but multiple designs are possible. If additional fields or images are required, custom properties can be used for that purpose.
An InboxMessage exposes the following methods for obtaining information about an inbox message.
Method | Comment |
---|---|
public String getMessageUid() | Returns the messageUID that uniquely identifies this inbox message. |
public String getSubject() | Returns the subject that can be used as a header for an inbox message. |
public String getContent() | Returns the content for further textual information to the reader of the message. |
public String getDetail() | Returns a URL that may lead to an image, a web page or any rich media that one may want to display as the landing page of the inbox message. |
public Boolean getRead() | Returns true or false to determine if the message has previously been read by the user of the app. |
public Date getExpirationDate() | Returns a timestamp of when a message will be considered expired. |
public String getCollapseKey() | Returns a key that is used to remove other messages previously sent with the same key. |
public Date getCreatedAt() | Returns the date on which the message was created on the platform. |
public String getIconImage() | Returns a URL that points to an image that can displayed as an icon for an inbox message list (1 of 2). |
public String getMainIcon() | Returns a URL that points to an image that can displayed as an icon for an inbox message list (2 of 2). |
public Map<String, Object> getInboxCustomData() | Contains a map of custom data that you can pass to the app per message. |
Fetching Inbox Messages
A list of maximum 200 messages for each user of the app can be fetched by invoking the fetchInboxMessages method as show below. On success, a Collection of InboxMessages is obtained, otherwise there is an error message passed to the onFailure portion of the callback.
Note that by default, these messages are sorted in descending order by date created, which means the most recent message will be first in the collection.
Vibes.getInstance().fetchInboxMessages(new VibesListener < Collection < InboxMessage >> () {
@Override public void onSuccess(Collection < InboxMessage > messages) { }
@Override public void onFailure(String errorText) { }
});
Fetching A Single Inbox Message
A single inbox message can be fetched by invoking fetchInboxMessage with the messageUid of the requested message as shown below. On success, a single InboxMessage is obtained; otherwise, there is an error message passed to the onFailure portion of the callback.
Vibes.getInstance().fetchInboxMessage(messageUid, new VibesListener \< InboxMessage > () {
@Override public void onSuccess(InboxMessage message) { }
@Override public void onFailure(String errorText) { }
});
Call the inbox_open event trigger after calling the fetchInboxMessages function to represent opening an inbox message. This will trigger inbox_open event for the inbox message. This will track customer engagement for platform reporting.
Vibes.getInstance().onInboxMessageOpen(message)
Marking an Inbox Message as Read
An inbox message can be marked as read so it could possibly be rendered differently from unread inbox messages. This is done by invoking markInboxMessageAsRead with the messageUid of the requested message as shown below. On success, an updated version of the InboxMessage is returned; otherwise, there is an error message passed to the onFailure portion of the callback.
Vibes.getInstance().markInboxMessageAsRead(messageUid, new VibesListener \< InboxMessage > () {
@Override public void onSuccess(InboxMessage message) {}
@Override public void onFailure(String errorText) {}
});
Expiring an Inbox Message
An inbox message can be marked as expired which would automatically make it unavailable for viewing when inbox messages are refetched again. This is done by invoking expireInboxMessage
with the messageUid of the requested message as shown below. On success, an updated InboxMessage is returned with the expirationDate set; otherwise, there is an error message passed to the onFailure portion of the callback.
Vibes.getInstance().expireInboxMessage(messageUid, **new** VibesListener \< InboxMessage > () {
@Override
**public void** onSuccess(InboxMessage message) {}
@Override
**public void** onFailure(String errorText) {}
});
Push Message Linked to An InboxMessage
Since v 4.0.0, it is now possible for a push message to contain a pointer to an inbox message called inboxMessageUid. In such a scenario, one can override the default VibesReceiver, fetch the associated InboxMessage and then open your own custom detail activity when such a message is received. Below is an example:
protected void onPushOpened(Context context, PushPayloadParser pushModel) {
super.onPushOpened(context, pushModel);
Log.d(TAG, "Push was opened");
if (pushModel.getInboxMessageUid() != null) {
Vibes.getInstance().fetchInboxMessage(pushModel.getInboxMessageUid(), new VibesListener < InboxMessage > {
@Override
public void onSuccess(InboxMessage value) {
Intent inboxDetailIntent = new Intent(context, InboxDetailActivity.class);
inboxDetailIntent.putExtra(InboxDetailActivity.INBOX_MESSAGE_KEY, value);
TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(context);
taskStackBuilder.addNextIntentWithParentStack(inboxDetailIntent);
PendingIntent resultPendingIntent =
taskStackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
resultPendingIntent.send();
}
@Override
public void onFailure(String errorText) {
Log.d(TAG, errorText);
}
});
} else {
Intent mainActivityIntent = new Intent(context, MainActivity.class);
context.startActivity(mainActivityIntent);
}
}
Enhanced Logging Support in Android
Log Levels
Version 4.2.0 of the SDK now supports improved logging. The SDK now supports the following log levels
ERROR
WARN
INFO
VERBOSE
The lowest level of logging is the VERBOSE log level, which produces the most log output. ERROR produces the least output.
Subscribing to Log Statements
To subscribe to receive all log statements, you will need to implement the com.vibes.vibes.VibesLogger interface, and supply that implementation to the SDK at the time of initialization.
VibesConfig config = new VibesConfig.Builder()
.setApiUrl(appUrl)
.setAppId(appId).
.setLogger(new MyAppLogger())
.build();
Enabling Developer Logging
During development, a developer may enable developer logging at a particular log level. Doing this means that all log statement with a level equal or higher than the level specified will be displayed on the console of the application. Below is an example of enabling developer logging by calling enableDevLogging.
VibesConfig config = new VibesConfig.Builder()
.setApiUrl(appUrl)
.setAppId(appId).
.enableDevLogging(VibesLogger.Level.INFO)
build();
This will produce the following example output.
[12/22/2020 19:19:56]: INFO: Initializing Vibes SDK v4.1.1
[12/22/2020 19:19:56]: WARN: AppId has changed to: UATINTEGRATIONTEST
[12/22/2020 19:19:58]: INFO: Latest version of the Vibes SDK is 4.2.0. We suggest upgrading
[12/22/2020 19:20:03]: INFO: Device registration successful
[12/22/2020 18:15:46]: WARN: App Inbox is not enabled
Best practice
We strongly advise using the enableDevLogging only during development, as leaving logging enabled in a production version of the app may lead to higher memory consumption. By default, developer logging is disabled.
Also note that you can pass your own logger to the SDK in addition to calling enableDevLogging.
SDK Log Message Types
As can be seen from the sample output above, the SDK now generates different types of log statements.
- Current version of SDK deployed within the app, and a message about upgrading if there is a newer version
- Current Vibes appId that the SDK is configured with.
- Whether app inbox support is enabled for this Vibes appId or not.
- Multiple life-cycle messages about successful/unsuccessful invocation of all the major SDK functions.
Updated about 1 year ago