Rich Notifications
Contents
Sailthru Mobile supports Android Rich Notifications out of the box for image payloads.
Send Rich Notifications
When creating an in-app message with push notification, the image added to the in-app message will automatically be delivered to the Android device and displayed as a rich push notification. Alternatively, rich notifications can be sent using the API as per the Rich Push example.Extend or change default behavior
You can extend or change this default behavior by adding aNotificationCompat.Extender
and implementing your own notification style. This is useful if you want to add media controls, or you'd like to render the notification body with an expanded view.
Java
import android.support.v4.app.NotificationCompat;
public class RichPushNotificationExtender implements NotificationCompat.Extender {
protected static String TAG = "RichPushNotificationExtender";
protected static String KEY_PAYLOAD_ALERT = "alert";
protected static String KEY_PAYLOAD_TITLE = "title";
protected static String KEY_PAYLOAD_IMAGE_URL = "image_url";
protected static String KEY_PAYLOAD_ST = "_st";
@Override
public NotificationCompat.Builder extend(NotificationCompat.Builder builder) {
Bundle bundle = builder.getExtras();
Context context = builder.mContext;
// For Image or Video in-app messages, we will send the media URL in the
// _st payload
String imageUrl = null;
String stString = bundle.getString(KEY_PAYLOAD_ST);
if(stString != null && !stString.isEmpty()) {
try {
JSONObject stPayload = new JSONObject(stString);
if (!stPayload.isNull(KEY_PAYLOAD_IMAGE_URL)) {
imageUrl = stPayload.getString(KEY_PAYLOAD_IMAGE_URL);
}
} catch (JSONException e) {
Log.e(TAG, "Unable to get " + KEY_PAYLOAD_IMAGE_URL + " from '_st' payload: " + stString + ".\n" + e.getLocalizedMessage());
}
}
builder.setContentTitle(context.getResources().getString(R.string.app_name))
.setSmallIcon(R.drawable.st_bg_notification)
.setContentText(bundle.getString(KEY_PAYLOAD_ALERT));
if(imageUrl != null && !imageUrl.isEmpty()) {
Bitmap image = fetchImageForMessage(imageUrl);
NotificationCompat.BigPictureStyle largeFormatStyle = new NotificationCompat.BigPictureStyle()
.bigPicture(image)
.setBigContentTitle(context.getResources().getString(R.string.app_name))
.setSummaryText(bundle.getString(KEY_PAYLOAD_TITLE))
.bigLargeIcon(image);
builder.setLargeIcon(image);
builder.setStyle(largeFormatStyle);
}
return builder;
}
// code used to load image from url
private @Nullable Bitmap fetchImageForMessage(@NonNull String imageUrl) {
URL url;
try {
url = new URL(imageUrl);
} catch (MalformedURLException e) {
Log.e(TAG, "Malformed image URL in Push Payload: " + e.getLocalizedMessage());
return null;
}
AsyncTask<URL, Void, Bitmap> task = new AsyncTask<URL, Void, Bitmap>() {
@Override
protected Bitmap doInBackground(URL... params) {
try {
URL url = params[0];
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
return BitmapFactory.decodeStream(input);
} catch (IOException e) {
Log.e(TAG, "IO Error loading Message image:" + e.getLocalizedMessage());
return Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8);
}
}
}.execute(url);
try {
return task.get(5, TimeUnit.SECONDS);
} catch (Exception e) {
Log.e(TAG, "Failed to wait for Message Image in RichPushNotificationExtender: " + e.getMessage());
return null;
}
}
}
Kotlin
import androidx.core.app.NotificationCompat
class RichPushNotificationExtender : NotificationCompat.Extender {
override fun extend(builder: NotificationCompat.Builder): NotificationCompat.Builder {
val bundle: Bundle = builder.getExtras()
val context: Context = builder.mContext
// For Image or Video in-app messages, we will send the media URL in the
// _st payload
var imageUrl: String? = null
val stString = bundle.getString(KEY_PAYLOAD_ST)
if (stString != null && !stString.isEmpty()) {
try {
val stPayload = JSONObject(stString)
if (!stPayload.isNull(KEY_PAYLOAD_IMAGE_URL)) {
imageUrl = stPayload.getString(KEY_PAYLOAD_IMAGE_URL)
}
} catch (e: JSONException) {
Log.e(TAG, """Unable to get $KEY_PAYLOAD_IMAGE_URL from '_st' payload: $stString.
${e.getLocalizedMessage()}""")
}
}
builder.setContentTitle(context.resources.getString(R.string.app_name))
.setSmallIcon(R.drawable.st_bg_notification)
.setContentText(bundle.getString(KEY_PAYLOAD_ALERT))
if (imageUrl != null && !imageUrl.isEmpty()) {
val image = fetchImageForMessage(imageUrl)
val largeFormatStyle: NotificationCompat.BigPictureStyle = NotificationCompat.BigPictureStyle()
.bigPicture(image)
.setBigContentTitle(context.resources.getString(R.string.app_name))
.setSummaryText(bundle.getString(KEY_PAYLOAD_TITLE))
.bigLargeIcon(image)
builder.setLargeIcon(image)
builder.setStyle(largeFormatStyle)
}
return builder
}
// code used to load image from url
private fun fetchImageForMessage(imageUrl: String): Bitmap? {
val url: URL
try {
url = URL(imageUrl)
} catch (e: MalformedURLException) {
Log.e(TAG, "Malformed image URL in Push Payload: " + e.getLocalizedMessage())
return null
}
val task: AsyncTask<URL?, Void?, Bitmap?> = object : AsyncTask<URL?, Void?, Bitmap>() {
override fun doInBackground(vararg params: URL): Bitmap {
return try {
val url: URL = params[0]
val connection: HttpURLConnection = url.openConnection() as HttpURLConnection
connection.setDoInput(true)
connection.connect()
val input: InputStream = connection.getInputStream()
BitmapFactory.decodeStream(input)
} catch (e: IOException) {
Log.e(TAG, "IO Error loading Message image:" + e.getLocalizedMessage())
Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8)
}
}
}.execute(url)
return try {
task[5, TimeUnit.SECONDS]
} catch (e: Exception) {
Log.e(TAG, "Failed to wait for Message Image in RichPushNotificationExtender: " + e.message)
null
}
}
companion object {
protected var TAG = "RichPushNotificationExtender"
protected var KEY_PAYLOAD_ALERT = "alert"
protected var KEY_PAYLOAD_TITLE = "title"
protected var KEY_PAYLOAD_IMAGE_URL = "image_url"
protected var KEY_PAYLOAD_ST = "_st"
}
}
NotificationConfig
Java
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
SailthruMobile sailthruMobile = new SailthruMobile();
sailthruMobile.startEngine(getApplicationContext(), "your sdk key");
NotificationConfig notificationConfig = new NotificationConfig();
notificationConfig.addNotificationExtender(new RichPushNotificationExtender());
sailthruMobile.setNotificationConfig(notificationConfig);
}
}
Kotlin
class MyApplication : Application() {
fun onCreate() {
super.onCreate()
val sailthruMobile = SailthruMobile()
sailthruMobile.startEngine(applicationContext, "your sdk key")
val notificationConfig = NotificationConfig()
notificationConfig.addNotificationExtender(RichPushNotificationExtender())
sailthruMobile.setNotificationConfig(notificationConfig)
}
}