--- title: "Android custom inbox mobile" slug: "android-custom-inbox" updated: 2026-06-09T22:53:42Z published: 2026-06-09T22:53:42Z canonical: "docs.xtremepush.com/android-custom-inbox" stale: true --- > ## Documentation Index > Fetch the complete documentation index at: https://docs.xtremepush.com/llms.txt > Use this file to discover all available pages before exploring further. # 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 1. Implement the `InboxListListener` interface in your `Application` class: **Java** ```java public class XPushApplication extends Application implements InboxListListener {    @Override    public void inboxListReceived(ArrayList inboxList, WeakReference uiReference) {        // render your inbox UI    }    @Override    public void inboxListFailed() {        // handle error    } } ``` **Kotlin** ```kotlin class XPushApplication : Application(), InboxListListener {    override fun inboxListReceived(inboxList: ArrayList, uiReference: WeakReference) {        // render your inbox UI    }    override fun inboxListFailed() {        // handle error    } } ``` 1. Register the listener when initialising the SDK. If you don't call `setInboxListListener`, the SDK uses its built-in WebView inbox. ```java 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. ```java 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`. **Java** ```java // Reading a custom payload field String ctaLabel = item.message.data != null ? item.message.data.get("cta_label") : null; if (ctaLabel != null) {    button.setText(ctaLabel); } ``` **Kotlin** ```kotlin val ctaLabel = item.message.data?.get("cta_label") ctaLabel?.let { button.text = it } ``` > [!NOTE] > Campaign Templates > > Because 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. **Java** ```java 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    } } ``` **Kotlin** ```kotlin 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. **Java** ```java mPushConnector.reportMessageOpened(item.message, null, null); ``` **Kotlin** ```kotlin 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. **Java** ```java mPushConnector.reportMessageClicked(item.message, null, null); ``` **Kotlin** ```kotlin mPushConnector.reportMessageClicked(item.message, null, null) ``` ## Delete an inbox message **Java** ```java mPushConnector.deleteInboxMessage(String.valueOf(item.identifier), activity); ``` **Kotlin** ```kotlin 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. **Java** ```java int badge = mPushConnector.getInboxBadge(); ``` **Kotlin** ```kotlin val badge = mPushConnector.getInboxBadge() ```