iOS custom inbox mobile
Implement a custom inbox in your iOS 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
Retrieve inbox messages
The inboxListWithOffset:limit:callback: method asynchronously fetches a list of inbox items. Use the offset and limit parameters to support pagination.
XPush.inboxList(withOffset: 0, limit: 20) { (list, badge, error) in
if let list = list {
// render list
} else if let error = error {
// handle error
}
}[XPush inboxListWithOffset:0 limit:20 callback:^(NSArray<XPInboxItem *> * _Nullable list, NSUInteger badge, NSError * _Nullable error) {
if (list != nil) {
// render list
} else if (error != nil) {
// handle error
}
}];XPInboxItem
Each item in the returned array is an XPInboxItem with the following properties:
| Property | Type | Description |
|---|---|---|
identifier | NSInteger | Unique message ID |
isOpened | BOOL | Whether the message has been marked as opened |
isClicked | BOOL | Whether the message has been marked as clicked |
isDelivered | BOOL | Whether the message has been delivered |
createTimestamp | NSNumber * | Unix timestamp of when the message was created |
expirationTimestamp | NSNumber * | Unix timestamp of expiry, or nil if the message does not expire |
style | XPInboxItemStyle * | Background and title background colour values |
isCard | BOOL | YES for card layout (full-width banner image), NO for alert layout (small thumbnail) |
response | XPMessageResponse * | Contains the message content and tap action — see below |
Working with message content
Each XPInboxItem exposes its content through item.response, which contains two objects:
item.response.message (XPMessage) — the message content:
| Property | Type | Set by |
|---|---|---|
identifier | NSString * | Platform (system-assigned) |
campaignIdentifier | NSString * | Platform (system-assigned) |
title | NSString * | Campaign — Push title field |
text | NSString * | Campaign — Push text / body field |
icon | NSString * | Campaign — Push icon field (falls back to app icon, then project icon, if not set) |
data | NSDictionary * | Campaign — Custom payload fields (payload_add), with SDK-reserved keys removed |
payload | NSDictionary * | Full raw message dictionary — use when you need direct access to fields not surfaced above |
item.response.action (XPAction) — the tap action:
| Property | Type | Set by |
|---|---|---|
deeplink | NSString * | Campaign — present when action type is Deeplink; nil otherwise |
url | NSURL * | Campaign — present when action type is URL; nil otherwise |
identifier | NSString * | Platform — pass to reporting methods |
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 item:
| Property | Type | Set by |
|---|---|---|
isCard | BOOL | Campaign — inbox type setting. YES = card layout (full-width banner), NO = alert layout (small thumbnail) |
style.background | NSString * | Campaign — inbox style background colour |
style.titleBackground | NSString * | 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.response.message.data as a key-value dictionary, with all SDK-reserved keys already stripped out.
// Reading a custom payload field
if let ctaLabel = item.response.message.data?["cta_label"] as? String {
button.setTitle(ctaLabel, for: .normal)
}NSString *ctaLabel = item.response.message.data[@"cta_label"];
if (ctaLabel) {
[button setTitle:ctaLabel forState:UIControlStateNormal];
}
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.response.action to determine what to do. The SDK does not fire deeplink callbacks automatically in a custom inbox — your app handles navigation directly.
Always call reportMessageClicked so that the interaction is registered on the platform.
func userDidTap(_ item: XPInboxItem) {
// Register the click with the platform
XPush.reportMessageClicked(item.response.message, actionIdentifier: item.response.action.identifier)
if let deeplink = item.response.action.deeplink {
// Route through your app's navigation handler
// MyRouter.shared.navigate(to: deeplink)
} else if let urlString = item.response.action.url,
let url = URL(string: urlString) {
UIApplication.shared.open(url)
} else {
// No tap action configured — message is informational only
}
}- (void)userDidTapInboxItem:(XPInboxItem *)item {
// Register the click with the platform
[XPush reportMessageClicked:item.response.message actionIdentifier:item.response.action.identifier];
if (item.response.action.deeplink) {
// Route through your app's navigation handler
// [[MyRouter shared] navigateTo:item.response.action.deeplink];
} else if (item.response.action.url) {
NSURL *url = [NSURL URLWithString:item.response.action.url];
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
} 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.
XPush.reportMessageOpened(item.response.message, actionIdentifier: item.response.action.identifier)[XPush reportMessageOpened:item.response.message actionIdentifier:item.response.action.identifier];Report inbox message clicked
Call this when a user deliberately taps a message. This automatically also marks the message as opened. Do not call reportMessageOpened separately for tapped messages.
XPush.reportMessageClicked(item.response.message, actionIdentifier: item.response.action.identifier)[XPush reportMessageClicked:item.response.message actionIdentifier:item.response.action.identifier];Delete an inbox message
XPush.removeInboxMessage(item) { badge in
// reload inbox list
// update badge display
}[XPush removeInboxMessage:item callback:^(NSInteger badge) {
// reload inbox list
// update badge display
}];Get inbox badge number
Returns the cached unread count — use this to display a badge without making a network request.
let badge: NSInteger = XPush.getInboxBadge()NSInteger badge = [XPush getInboxBadge];Updated 12 days ago