Android custom inbox mobile
Implement a custom inbox in your Android application.
By default, the XtremePush SDK renders the inbox as a built-in WebView. A custom inbox replaces that with your own native UI, giving you full control over layout and interaction.
When you implement a custom inbox, the SDK continues to handle:
- Fetching and paginating inbox messages from the platform
- Deleting messages
- Tracking badge counts
- Sending opened/clicked analytics events (when you call the reporting methods)
Your app becomes responsible for:
- Rendering each message (title, body, image, icon, card vs alert layout)
- Handling tap actions (deeplink navigation, opening URLs)
- Calling the reporting methods at the right time
Setup
- Implement the
InboxListListenerinterface in yourApplicationclass:
public class XPushApplication extends Application implements InboxListListener {
@Override
public void inboxListReceived(ArrayList<InboxMessageListItem> inboxList, WeakReference<Context> uiReference) {
// render your inbox UI
}
@Override
public void inboxListFailed() {
// handle error
}
}class XPushApplication : Application(), InboxListListener {
override fun inboxListReceived(inboxList: ArrayList<InboxMessageListItem>, uiReference: WeakReference<Context>) {
// render your inbox UI
}
override fun inboxListFailed() {
// handle error
}
}- Register the listener when initialising the SDK. If you don't call
setInboxListListener, the SDK uses its built-in WebView inbox.
new PushConnector.Builder(XPUSH_APP_KEY, GOOGLE_PROJECT_NUMBER)
.setInboxListListener(this)
.create(this);Retrieve inbox messages
Call inboxListWithOffset to fetch messages. Results are delivered to the inboxListReceived callback.
mPushConnector.inboxListWithOffset(context, LIMIT, OFFSET);InboxMessageListItem
Each item in the list has the following fields:
| Field | Type | Description |
|---|---|---|
identifier | int | Unique message ID |
isOpened | boolean | Whether the message has been marked as opened |
isClicked | boolean | Whether the message has been marked as clicked |
isDelivered | boolean | Whether the message has been delivered |
createTimestamp | Long | Unix timestamp of when the message was created |
expirationTimestamp | Long | Unix timestamp of expiry, or null if the message does not expire |
style | HashMap<String, String> | Style values — keys: bg (background colour), title_bg (title bar colour) |
isCard | boolean | true for card layout (full-width banner image), false for alert layout (small thumbnail) |
message | Message | Contains message content and tap action — see below |
Working with message content
The message field on each InboxMessageListItem contains the full message content:
| Field | Type | Set by |
|---|---|---|
id | String | Platform (system-assigned) |
campaignId | String | Platform (system-assigned) |
title | String | Campaign — Push title field |
text | String | Campaign — Push text / body field |
icon | String | Campaign — Push icon field (falls back to app icon, then project icon, if not set) |
deeplink | String | Campaign — present when action type is Deeplink; null otherwise |
url | String | Campaign — present when action type is URL; null otherwise |
data | HashMap<String, String> | Campaign — Custom payload fields (from the data key in the message JSON) |
deeplink and url are mutually exclusive — only one will be set depending on the action type configured in the campaign. If neither is set, the message has no tap action.
Layout and style are on the list item:
| Field | Type | Set by |
|---|---|---|
isCard | boolean | Campaign — inbox type setting. true = card layout (full-width banner), false = alert layout (small thumbnail) |
style.get("bg") | String | Campaign — inbox style background colour |
style.get("title_bg") | String | Campaign — inbox style title bar colour |
Custom payload fields
If your inbox UI requires data beyond the standard fields — for example a CTA label, a secondary URL, or a badge value — add custom fields in the campaign's Custom payload (payload_add) section. These are delivered in item.message.data.
// Reading a custom payload field
String ctaLabel = item.message.data != null ? item.message.data.get("cta_label") : null;
if (ctaLabel != null) {
button.setText(ctaLabel);
}val ctaLabel = item.message.data?.get("cta_label")
ctaLabel?.let { button.text = it }
Campaign TemplatesBecause your custom inbox UI is built to render a specific content structure, consider defining a reusable inbox campaign template in the Xtremepush platform that consistently populates the fields your UI expects. For example, if your card layout always shows a title, body, background colour, deeplink action, and a custom CTA label, define these as required fields for any inbox campaign targeting your custom implementation.
Handle message actions (deeplink & URL)
When a user taps a message, inspect item.message to determine what to do. The SDK does not fire DeeplinkListener callbacks automatically in a custom inbox — your app handles navigation directly.
Always call reportMessageClicked so that the interaction is registered on the platform.
private void onInboxItemTapped(InboxMessageListItem item) {
// Register the click with the platform
mPushConnector.reportMessageClicked(item.message, null, null);
if (item.message.deeplink != null && !item.message.deeplink.isEmpty()) {
// Route through your app's navigation handler
// MyRouter.navigate(item.message.deeplink);
} else if (item.message.url != null && !item.message.url.isEmpty()) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(item.message.url));
context.startActivity(intent);
} else {
// No tap action configured — message is informational only
}
}private fun onInboxItemTapped(item: InboxMessageListItem) {
// Register the click with the platform
mPushConnector.reportMessageClicked(item.message, null, null)
when {
!item.message.deeplink.isNullOrEmpty() -> {
// Route through your app's navigation handler
// MyRouter.navigate(item.message.deeplink)
}
!item.message.url.isNullOrEmpty() -> {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(item.message.url))
startActivity(intent)
}
else -> {
// No tap action configured — message is informational only
}
}
}Report inbox message opened
Call this when a message becomes visible to the user (e.g. scrolled into view in a feed) without a deliberate tap.
mPushConnector.reportMessageOpened(item.message, null, null);mPushConnector.reportMessageOpened(item.message, null, null)Report inbox message clicked
Call this when a user deliberately taps a message. This also automatically marks the message as opened. Do not call reportMessageOpened separately for tapped messages.
mPushConnector.reportMessageClicked(item.message, null, null);mPushConnector.reportMessageClicked(item.message, null, null)Delete an inbox message
mPushConnector.deleteInboxMessage(String.valueOf(item.identifier), activity);mPushConnector.deleteInboxMessage(item.identifier.toString(), activity)Get inbox badge number
Returns the cached unread count — use this to display a badge without making a network request.
int badge = mPushConnector.getInboxBadge();val badge = mPushConnector.getInboxBadge()Updated 12 days ago