Android: Rich Notifications

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.

11051105

Creating a message with an image inside the Sailthru Mobile platform.

709709

An Android Rich Notification on device created from the message.

Extend or change default behavior

You can extend or change this default behavior by adding a NotificationCompat.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.

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;
      }
  }
   
}
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"
    }
}

Then add your extender to NotificationConfig

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);
  }
}
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)
    }
}

Did this page help you?