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.

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.

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

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