Using the Android App Messaging SDK
A tutorial for adding the Android App Messaging SDK code to your app to allow your app users to receive push notifications from your Dotdigital account
Our Android App Messaging SDK uses Firebase Cloud Messaging (FCM) to send push notifications to your Android app users.
Our Android SDK is open source and can be found on Github here:
Basic sample apps can be found in Github here:
To embed in your native Android apps, complete the following tasks:
- Install the SDK
- Configure the SDK
- Initialise the SDK
- Optional: Change the icon or colour of your push notifications
Handling asynchronous requests
You can use either standard callbacks or observable streams to handle asynchronous requests. If you want to use observable streams, you need to add the RxJava library to your app. This tutorial explains how to use standard callbacks, but you can find a full sample of the RxJava code in the 'Android sample code' section.
Installing the SDK
- Add the App Messaging SDK to your module-level
build.gradle
file and change theminSDKVersion
attribute to 16 using the snippet below:
defaultConfig {
...
minSdkVersion 16
...
}
Dependencies {
...
implementation 'com.comapi:foundation:1.2.0'
}
Seeing a 'Manifest merger' error?
The SDK has a
minSDKVersion
attribute of 16, your attribute must have a value of at least 16.
- Add the Google services plugin to your module-level
build.gradle
file using the snippet below:
apply plugin: 'com.google.gms.google-services'
- Add the following dependencies to your module-level
build.gradle
file using the snippet below:
implementation ('com.google.android.gms:play-services-base:15.0.1') {force = true}
implementation ('com.google.firebase:firebase-messaging:17.0.0') {force = true}
Sync Now
Remember to synchronise
build.gradle
files after making any changes.
Configuring the Android SDK
Before you can configure the Android SDK, you need the following:
- The value of the API space ID field in Dotdigital
- A class that creates a JWT token
- Create a new instance of the
ComapiConfig
class, pass your API Space Id to theapiSpaceId()
method, and an instance of the class that creates a JWT to theauthenticator()
method using the snippet below:
ComapiConfig config = new ComapiConfig() .apiSpaceId("<API_SPACE_ID>") .authenticator(new ChallengeHandler());
Displaying push notifications when the app is in the foreground
Push notifications are automatically displayed only while the app is in the background. These notifications are sent to the system tray and launch your app when users tap them.
If you want to display the push notification message while the app is in the foreground, do the following:
- Create a class that implements the
pushMessageListener
class (here, we've called the example classPushHandler
). You'll need to decide what you want to do with the push notification and implement the logic by overriding theonMessageReceived()
method. This method is called when a push notification is received while the app is in the foreground.
Deep links
If a push notification is delivered while the app is in the foreground, you can build your own in the 'onMessageReceived()` method that creates a link to a particular activity in your app.
public class PushHandler implements PushMessageListener {
@Override
public void onMessageReceived(RemoteMessage message) {
// Check if message contains a notification payload.
if (message.getNotification() != null) {
Log.i("TAG", "Push notification: " + message.getNotification().getBody());
// Do something with the message to notify the user
// Example
createNotificationChannel(context);
Notification.Builder b = new Notification.Builder(context);
b.setAutoCancel(true)
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.drawable.common_google_signin_btn_icon_dark)
.setContentTitle("foreground message")
.setContentText(body)
.setContentInfo("INFO");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
b.setChannelId("test_channel_id1");
}
NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
nm.notify(1, b.build());
}
}
}
private void createNotificationChannel(Context context) {
// Create the NotificationChannel, but only on devices that have the Google API 26+ because the NotificationChannel class is new and not in supported in older libraries
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
CharSequence name = "test channel";
String description = "some description";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel("test_channel_id1", name, importance);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
- Pass your class to the
pushMessageListener()
on theComapiConfig
object
config.pushMessageListener(new PushHandler());
Configuring logs and proxy servers
You can set internal file logs, console logs, and network logs to the following levels. By default all log levels are set to WARNING
:
OFF
FATAL
ERROR
WARNING
INFO
DEBUG
To change the log levels, add the following line to the ComapiConfig
object and use the appropriate method on the LogConfig
object:
.logConfig(new LogConfig().setFileLevel(LogLevel.DEBUG).setConsoleLevel(LogLevel.INFO).setNetworkLevel(LogLevel.ERROR));
You can also set a custom limit for the size of internal log files by calling the following method on the ComapiConfig
object:
.logSizeLimitKilobytes(limit);
If your app connects through a proxy server, add the following line to the ComapiConfig
object:
.apiConfiguration(new APIConfig().proxy("http://xx.xxx.xx.xxx:xxxx"));
Initialising the Android SDK
Where to initialise the Android SDK in the activity lifecycle
Initialisation needs to be performed in the
onCreate()
[method](https://developer.android.com/reference/android/app/Application#onCreate() of the AndroidApplication
class so that your app users' profiles don't change every time they open the app.
- After you've configured the SDK, import the
com.google.firebase.FirebaseApp
class into your java file, and initialise the Firebase SDK.
FirebaseApp.initializeApp(this);
2 Pass the ComapiConfig
object to one of the following initialisation methods. These methods return a ComapiClient
object that you can use to access the session
and profile
services, which are used to create and update the user's profile.
- The
initialiseShared()
method: When you use this method, the SDK stores the 'ComapiClient' object, and you can access it at any time by calling theComapi.getShared()
method (Java) or theRxComapi.getShared()
method (RxJava) - The
initialise()
method: When you use this method, you need to store theComapiClient
object yourself. ThegetShared()
method is not available when you use this method.
public class MyApplication extends Application {
@Override
public void onCreate()
{
super.onCreate();
FirebaseApp.initializeApp(this);
ComapiConfig config = new ComapiConfig();
//<API space ID> string must be the same as the value of the 'API space ID' field in your push notification profile in Dotdigital.
config.apiSpaceId("<API space ID>");
//Set handler for authentication challenges (SDK asks for a JWT token)
config.authenticator(new ChallengeHandler());
Comapi.initialiseShared(this, config, new Callback<ComapiClient>() {
@Override
public void success(final ComapiClient client) {
//Use ComapiClient object to communicate with services
}
@Override
public void error(Throwable t) {
//Error
}
});
Changing the icon or colour of push notification
Our Android SDK uses Firebase Cloud Messaging (FCM) to send push notifications to your Android app users. As such, you can use the Android <meta-data>
tag in your AndroidManifest.xml
file to change the icon and colour of your push notifications.
<!-- Set icon used with incoming notification messages. This is used when no icon is set for the incoming notification message. -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@mipmap/ic_launcher_round" />
<!-- Set color used with incoming notification messages. This is used when no color is set for the incoming notification message. -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/colorAccent" />
Next steps
Now ensure your app passes an email address to the SDK for the app user to ensure they get a contact created in Dotdigital by following these instructions
Want to know more about the SDK?
To find out more about the SDK and it features and functions please go here
Sessions
Starting a session
To receive push messages the SDK requires an active session. A session will also be automatically created by the SDK if you have not initialized it already when it is required.
To create a session you must have successfully initialized and retrieved a client object, you need to be able to identify the app user so that the sub claim in the JWT can be populated for the user; when the SDK requests the JWT in order to start the session. To create a session call:
client.service().session().startSession(new Callback<Session>(){/* implement */});
rxClient.service().session().startSession()
.subscribe(new Observer<Session>(){/* implement */});
Ending a session
You only have to end a session if you want to stop the app receiving push notifications, or you want to change users on the app.
To end the current session, call:
client.service().session().endSession(
new Callback<ComapiResult<Void>>(){/* implement */});
rxClient.service().session().endSession()
.subscribe(new Observer<ComapiResult<Void>>(){/* implement */});
Android Sample Code
package com.example.testapp;
import com.google.firebase.FirebaseApp;
import com.comapi.Comapi;
import com.comapi.ComapiClient;
import android.app.Application;
import com.comapi.Callback;
import com.comapi.ComapiConfig;
import com.comapi.Session;
import com.comapi.internal.network.ComapiResult;
import java.util.HashMap;
import java.util.Map;
public class MyApplication extends Application {
@Override
public void onCreate()
{
super.onCreate();
FirebaseApp.initializeApp(this);
ComapiConfig config = new ComapiConfig();
//<API space ID> string must be the same as the value of the 'API space ID' field in your push notification profile in Dotdigital.
config.apiSpaceId("<API space ID>");
//Set the handler for authentication challenges (SDK asking for JWT token)
config.authenticator(new AuthChallengeHandler());
Comapi.initialiseShared(this, config, new Callback<ComapiClient>() {
@Override
public void success(final ComapiClient client) {
if(client.getSession() != null && client.getSession().isSuccessfullyCreated()) {
client.service().profile().getProfile(client.getSession().getProfileId(), new Callback<ComapiResult<Map<String, Object>>>() {
@Override
public void success(ComapiResult<Map<String, Object>> result) {
Map <String, Object> additionalMap = new HashMap<>();
//Add the user's email address to the profile
additionalMap.put("email", "[email protected]");
client.service().profile().patchMyProfile(additionalMap, result.getETag(), new Callback<ComapiResult<Map<String, Object>>>() {
@Override
public void success(ComapiResult<Map<String, Object>> result) {
}
@Override
public void error(Throwable t) {
}
});
}
@Override
public void error(Throwable t) {
}
}
);
} else {
client.service().session().startSession(new Callback<Session>() {
@Override
public void success(Session result) {
}
@Override
public void error(Throwable t) {
}
});
}
}
@Override
public void error(Throwable t) {
//Error
}
});
}
}
package com.example.testapp;
import android.app.Application;
import com.google.firebase.FirebaseApp;
import com.comapi.ComapiConfig;
import com.comapi.RxComapi;
import com.comapi.RxComapiClient;
import com.comapi.internal.network.ComapiResult;
import java.util.HashMap;
import java.util.Map;
import rx.Observable;
import rx.Subscriber;
import rx.functions.Func1;
public class MyApplication extends Application {
@Override
public void onCreate()
{
super.onCreate();
FirebaseApp.initializeApp(this);
RxComapi.initialise(
this, new ComapiConfig()
//<API space ID> string must be the same as the value of the 'API space ID' field in your push notification profile in Dotdigital.
.apiSpaceId("<API space ID>")
//Set the handler for authentication challenges (SDK asking for JWT token)
.authenticator(new ChallengeHandler(getSharedPreferences(Const.PREFS_NAME, MODE_PRIVATE)))
).flatMap(new Func1<RxComapiClient, Observable<RxComapiClient>>() {
@Override
public Observable<RxComapiClient> call(final RxComapiClient client) {
if (client.getSession() != null && client.getSession().isSuccessfullyCreated()) {
return Observable.fromCallable(new Callable<RxComapiClient>() {
@Override
public RxComapiClient call() throws Exception {
return client;
}
});
} else {
return client.service().session().startSession().map(new Func1<Session, RxComapiClient>() {
@Override
public RxComapiClient call(Session session) {
return client;
}
});
}
}
}).flatMap(new Func1<RxComapiClient, Observable<ComapiResult<Map<String, Object>>>>() {
@Override
public Observable<ComapiResult<Map<String, Object>>> call(final RxComapiClient client) {
if (!client.getSession().isSuccessfullyCreated()) {
return Observable.error(new Exception("Failed to update profile"));
}
return client.service()
.profile()
.getProfile(client.getSession().getProfileId())
.flatMap(new Func1<ComapiResult<Map<String, Object>>, Observable<ComapiResult<Map<String, Object>>>>() {
@Override
public Observable<ComapiResult<Map<String, Object>>> call(ComapiResult<Map<String, Object>> result) {
Map<String, Object> additionalMap = new HashMap<>();
//Add the user's email address to the profile
additionalMap.put("email", "[email protected]");
return client.service().profile().patchMyProfile(additionalMap, result.getETag());
}
}
);
}
}).subscribe(new Subscriber<ComapiResult<Map<String, Object>>>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(ComapiResult<Map<String, Object>> result) {
}
});
}
}
Updated 8 months ago