-
Notifications
You must be signed in to change notification settings - Fork 16
Inbox
Inbox allows you to communicate with all active mobile users without dependency on possible poor push deliverability or users not paying attention to their push notifications.
Method for fetching the inbox uses authorization. Secure authorization is required for production applications. Read about the details of inbox authorization in the following article
In order to add Inbox module into your application, declare an additional dependency in your application's build.gradle file:
dependencies {
...
implementation 'com.infobip:infobip-mobile-messaging-android-inbox-sdk:6.+@aar'
}
Check latest version here.
Inbox messages can be fetched only by personalized users (learn more about personalization here). It is important to mention that only personalization by External User Id is supported, however, since this Id can be any meaningful string, you can specify a unique users Phone number or Email as an External User Id but keep in mind that this is the case-sensitive data.
Mobile Messaging Inbox SDK provides API for fetching messages.
This API requires a securely signed JWT (JSON Web Token encoded in Base64 format) in order to pass authentication on Infobip's server side (See how to generate JWT). In order to enable this API, generate JSON Web Token (JWT) for inbox at App Profile configuration page by navigating to "JWT private keys for mobile app inbox" and press "Generate key".
```kotlin
MobileInbox.getInstance(this).fetchInbox(
"<# token - your JWT in Base64 #>",
"<# externalUserId - some user Id #>",
null, // MobileInboxFilterOptions
object : MobileMessaging.ResultListener<Inbox>() {
override fun onResult(result: Result<Inbox, MobileMessagingError>) {
}
})
```
expand to see Java code
MobileInbox.getInstance(this).fetchInbox(
"<# token - your JWT in Base64 #>",
"<# externalUserId - some user Id #>",
null, // MobileInboxFilterOptions
new MobileMessaging.ResultListener<Inbox>() {
@Override
public void onResult(Result<Inbox, MobileMessagingError> result) {
}
});
For Sandbox App Profiles we also provide API that does not require user to be authenticated (uses application code based authorization):
```kotlin
MobileInbox.getInstance(this).fetchInbox(
"<# externalUserId - some user Id #>",
null, // MobileInboxFilterOptions
object : MobileMessaging.ResultListener<Inbox>() {
override fun onResult(result: Result<Inbox, MobileMessagingError>) {
}
})
```
expand to see Java code
MobileInbox.getInstance(this).fetchInbox(
"<# externalUserId - some user Id #>",
null, // MobileInboxFilterOptions
new MobileMessaging.ResultListener<Inbox>() {
@Override
public void onResult(Result<Inbox, MobileMessagingError> result) {
}
});
This API has no additional requirements authorization and simple to use, but can be used only for testing and demo purposes. In order to enable this API for your App Profile choose the "Application code" radio button in "Inbox authorization type" section on your App Profile's configuration page.
You need to be very cautious about the Infobip server response when fetching users messages using JWT token based authorization.
There are many reasons why you might get "UNAUTHORIZED" error response from Infobip backend. For security reasons, we don't disclose any details about the error, so you need to be even more cautious. One of the most common reasons for that error are:
- Expiration of the JWT token. You always have to use "fresh" token and reissue the new one in case of expiration happened or is about to happen.
- Invalid JWT token payload (missing mandatory claims or headers, typos).
- Wrong Application Code that is used to generate the JWT token. It's easy to make mistake when you have multiple App Profiles.
- Invalid secret key used for signing (a typo occurred or the key could have been revoked by you/your colleagues on App Profile page).
The complete information about the JWT token requirements and implementation details can be found here.
The following example demonstrates, how you can recognize and handle the "UNAUTHORIZED" error:
MobileInbox.getInstance(this).fetchInbox(
"<# token - your JWT in Base64 #>",
"<# externalUserId - some user Id #>",
MobileInboxFilterOptions(), // filtering options or null
object : MobileMessaging.ResultListener<Inbox>() {
override fun onResult(result: Result<Inbox, MobileMessagingError>) {
if (result.error.code == "UNAUTHORIZED") {
//TODO: I'm pretty sure the JWT token payload is correct here,
// it's just the token got expired,
// I will call my backend to reissue the fresh token for me and try again.")
}
}
})
expand to see Java code
MobileInbox.getInstance(this).fetchInbox(
"<# token - your JWT in Base64 #>",
"<# externalUserId - some user Id #>",
new MobileInboxFilterOptions(), // filtering options or null
new MobileMessaging.ResultListener<Inbox>() {
@Override
public void onResult(Result<Inbox, MobileMessagingError> result) {
if ("UNAUTHORIZED".equals(result.getError().getCode())) {
//TODO: I'm pretty sure the JWT token payload is correct here,
// it's just the token got expired,
// I will call my backend to reissue the fresh token for me and try again.
}
}
}
);
Another error response that you might face is "ACCESS_TOKEN_MISSING". This error means that in your App Profile page it has been set up to use "JSON Web Token (JWT)" for Inbox authorization, thus in your mobile app, you need to switch to the JWT token based Inbox API:
use MobileInbox.getInstance(this).fetchInbox(token:externalUserId:options:object:)
instead of MobileInbox.getInstance(this).fetchInbox(externalUserId:options:object:)
.
The complete information about the JWT token requirements and implementation details can be found here.
You can specify the following filtering options to fetch Inbox messages:
- filtering by particular time interval to get messages with
sendDateTime
greater than or equalMobileInboxFilterOptions.fromDateTime
and less thanMobileInboxFilterOptions.toDateTime
. By default or in case ofnull
, filter by date/time is not applied. For example the followingfetchInbox
call would return Inbox messages sent for current day:
val now = Date()
val calendar = Calendar.getInstance()
calendar.set(Calendar.HOUR_OF_DAY, 0)
calendar.set(Calendar.MINUTE, 0)
calendar.set(Calendar.SECOND, 0)
calendar.set(Calendar.MILLISECOND, 0)
val startTime = calendar.time
val todaysMessagesFilter = MobileInboxFilterOptions(startTime, now, null, null)
MobileInbox.getInstance(this).fetchInbox(
"<# token - your JWT in Base64 #>",
"<# externalUserId - some user Id #>",
todaysMessagesFilter,
object : MobileMessaging.ResultListener<Inbox>() {
override fun onResult(result: Result<Inbox, MobileMessagingError>) {
val inbox = result.data
// handle error or get inbox data:
Log.d("inbox", "Total number of messages ${inbox?.countTotal}")
Log.d("inbox", "Total number of unread messages ${inbox?.countUnread}")
Log.d("inbox", "Fetched messages ${inbox?.messages}")
}})
expand to see Java code
Date now = new Date();
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
Date startTime = calendar.getTime();
MobileInboxFilterOptions todaysMessagesFilter = new MobileInboxFilterOptions(startTime, now, null, null);
MobileInbox.getInstance(this).fetchInbox(
"<# token - your JWT in Base64 #>",
"<# externalUserId - some user Id #>",
todaysMessagesFilter,
new MobileMessaging.ResultListener<Inbox>() {
@Override
public void onResult(Result<Inbox, MobileMessagingError> result) {
Inbox inbox = result.getData();
// handle error or get inbox data:
Log.d("inbox", "Total number of messages " + (inbox != null ? inbox.getCountTotal() : 0));
Log.d("inbox", "Total number of unread messages " + (inbox != null ? inbox.getCountUnread() : 0));
Log.d("inbox", "Fetched messages " + inbox.getMessages());
}
}
);
- filtering by a specific topic can be handy if you have a specific UI/UX approach to separate messages by different topics. By default or in case of
null
, filter by topic is not applied.
val promoMessagesFilter = MobileInboxFilterOptions(null, null, "myPromoTopic", null)
MobileInbox.getInstance(this).fetchInbox(
"<# token - your JWT in Base64 #>",
"<# externalUserId - some user Id #>",
promoMessagesFilter,
object : MobileMessaging.ResultListener<Inbox>() {
override fun onResult(result: Result<Inbox, MobileMessagingError>) {
// get messages, message counters from `inbox` or handle `error`
}})
expand to see Java code
MobileInboxFilterOptions promoMessagesFilter = new MobileInboxFilterOptions(null, null, "myPromoTopic", null);
MobileInbox.getInstance(this).fetchInbox(
"<# token - your JWT in Base64 #>",
"<# externalUserId - some user Id #>",
promoMessagesFilter,
new MobileMessaging.ResultListener<Inbox>() {
@Override
public void onResult(Result<Inbox, MobileMessagingError> result) {
// get messages, message counters from `inbox` or handle `error`
}
}
);
- limiting the maximum number of messages that will be returned by Infobip server. By default or in case of
null
, server returns 20 messages as maximum. This one together with filtering bytoDateTime
is useful when you need to implement pagination that might help reducing mobile data usage and fetch messages by chunks. For example, the following listing shows how to fetch whole inbox by chunks of 10 messages, one by one, from the most recent to the oldest:
val myMessages: List<InboxMessage> = listOf()
val oldestMessageDate: Long = oldestInboxMessage.getSentTimestamp()
val toDateTime = Date(oldestMessageDate)
val chunkMessagesFilter = MobileInboxFilterOptions(null, toDateTime, null, 10)
MobileInbox.getInstance(this).fetchInbox(
"<# token - your JWT in Base64 #>",
"<# externalUserId - some user Id #>",
chunkMessagesFilter,
object : MobileMessaging.ResultListener<Inbox>() {
override fun onResult(result: Result<Inbox, MobileMessagingError>) {
if (result.isSuccess) {
val inboxMessages: MutableList<InboxMessage> = ArrayList()
for (message in myMessages) {
inboxMessages.add(message)
}
}}})
expand to see Java code
List<InboxMessage> myMessages = new ArrayList<>();
long oldestMessageDate = oldestInboxMessage.getSentTimestamp();
Date toDateTime = new Date(oldestMessageDate);
MobileInboxFilterOptions chunkMessagesFilter = new MobileInboxFilterOptions(null, toDateTime, null, 10);
MobileInbox.getInstance(this).fetchInbox(
"<# token - your JWT in Base64 #>",
"<# externalUserId - some user Id #>",
chunkMessagesFilter,
new MobileMessaging.ResultListener<Inbox>() {
@Override
public void onResult(Result<Inbox, MobileMessagingError> result) {
if (result.isSuccess()) {
List<InboxMessage> inboxMessages = new ArrayList<>();
for (InboxMessage message : myMessages) {
inboxMessages.add(message);
}
}
}
}
);
You can mark Inbox messages as seen/read using the following API:
val messageIds : List<String> = listOf("<# list of message Ids that you consider as seen by the end user #>")
MobileInbox.getInstance(this).setSeen(
"<# externalUserId - some user Id #>",
messageIds,
object : ResultListener<Array<String>>() {
override fun onResult(result: Result<Array<String>, MobileMessagingError>) {
if (!result.isSuccess) {
// retry the call if error occurs
}}})
expand to see Java code
List<String> messageIds = Arrays.asList("<# list of message Ids that you consider as seen by the end user #>");
MobileInbox.getInstance(this).setSeen(
"<# externalUserId - some user Id #>",
messageIds,
new ResultListener<String[]>() {
@Override
public void onResult(Result<String[], MobileMessagingError> result) {
if (!result.isSuccess()) {
// retry the call if error occurs
}
}
}
);
If you have any questions or suggestions, feel free to send an email to [email protected] or create an issue.
- Library events
- Server errors
- Users and installations
- Messages and notifications management
- Inbox
Geofencing API- DEPRECATED- Android Manifest components
- Privacy settings
- In-app chat
- Infobip RTC calls and UI
- Backup rules