Message Center for the Flutter Plugin

Learn how to display Message Center, manage messages, and implement common inbox functionality in your Flutter app.

Message Center provides an inbox for rich, HTML-based messages. Learn more about Message Center in our user guide.

Display the Message Center

The Flutter plugin provides a simple way to display the built-in Message Center UI.

Using the default UI

Display the built-in Message Center UI with a single method call. This is perfect for quickly adding Message Center functionality without custom design work:

// Display the default Message Center UI
Airship.messageCenter.display();

This method can be called from anywhere in your app:

// Example: Add a button to your app bar
AppBar(
  title: Text('My App'),
  actions: [
    IconButton(
      icon: Icon(Icons.inbox),
      onPressed: () {
        Airship.messageCenter.display();
      },
    ),
  ],
)

Display a specific message

You can also display a specific message directly by providing its message ID:

Airship.messageCenter.display(messageId: "specific-message-id");

To customize the Message Center UI or navigation, see Embedding the Message Center.

Fetch messages

Retrieve all messages from the inbox:

List<InboxMessage> messages = await Airship.messageCenter.messages;

// Display messages in your UI
for (var message in messages) {
  print('Message: ${message.title}');
  print('ID: ${message.id}');
  print('Unread: ${message.unread}');
  print('Sent date: ${message.sentDate}');
}

InboxMessage properties

Each InboxMessage contains:

  • id: Unique identifier for the message
  • title: Message title
  • sentDate: When the message was sent
  • expirationDate: When the message expires (optional)
  • unread: Whether the message is unread
  • extras: Custom key-value pairs associated with the message

Listen for message updates

Subscribe to real-time message updates using streams. This is useful for updating your UI when new messages arrive or existing messages are modified:

StreamSubscription? inboxSubscription;

@override
void initState() {
  super.initState();
  
  // Listen for inbox updates
  inboxSubscription = Airship.messageCenter.onInboxUpdated.listen((event) {
    setState(() {
      // Reload messages when the inbox is updated
      _loadMessages();
    });
  });
}

Future<void> _loadMessages() async {
  List<InboxMessage> messages = await Airship.messageCenter.messages;
  setState(() {
    _messages = messages;
  });
}

@override
void dispose() {
  inboxSubscription?.cancel();
  super.dispose();
}

Track unread count

Monitor the unread message count to display badges or update UI elements:

Get current unread count

int unreadCount = await Airship.messageCenter.unreadCount;
print('Unread messages: $unreadCount');

Listen for unread count changes

// This is useful for updating badges in real-time
Airship.messageCenter.onInboxUpdated.listen((event) async {
  int unreadCount = await Airship.messageCenter.unreadCount;
  // Update your badge UI
  _updateBadge(unreadCount);
});

Example: Show unread badge

class InboxButton extends StatefulWidget {
  @override
  _InboxButtonState createState() => _InboxButtonState();
}

class _InboxButtonState extends State<InboxButton> {
  int _unreadCount = 0;
  StreamSubscription? _subscription;

  @override
  void initState() {
    super.initState();
    _loadUnreadCount();
    
    // Update badge when inbox changes
    _subscription = Airship.messageCenter.onInboxUpdated.listen((_) {
      _loadUnreadCount();
    });
  }

  Future<void> _loadUnreadCount() async {
    int count = await Airship.messageCenter.unreadCount;
    setState(() {
      _unreadCount = count;
    });
  }

  @override
  void dispose() {
    _subscription?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return IconButton(
      icon: Badge(
        label: _unreadCount > 0 ? Text('$_unreadCount') : null,
        child: Icon(Icons.inbox),
      ),
      onPressed: () {
        Airship.messageCenter.display();
      },
    );
  }
}

Refresh messages

Manually refresh the message list from the server. This is useful for implementing pull-to-refresh functionality:

// Refresh messages
bool success = await Airship.messageCenter.refreshInbox();

if (success) {
  print('Messages refreshed successfully');
} else {
  print('Failed to refresh messages');
}

Example: Pull-to-refresh

RefreshIndicator(
  onRefresh: () async {
    await Airship.messageCenter.refreshInbox();
  },
  child: ListView.builder(
    itemCount: messages.length,
    itemBuilder: (context, index) {
      return MessageListItem(message: messages[index]);
    },
  ),
)

Mark messages as read

Mark one or more messages as read to update their status:

// Mark a single message as read
await Airship.messageCenter.markRead(message.id);

// Or using the message object directly
await Airship.messageCenter.markRead(message.id);

Messages are typically marked as read automatically when viewed in the default Message Center UI. For custom implementations, you should mark messages as read when the user views them:

// When user taps on a message
void onMessageTapped(InboxMessage message) {
  // Mark as read
  Airship.messageCenter.markRead(message.id);
  
  // Navigate to message detail screen
  Navigator.push(
    context,
    MaterialPageRoute(
      builder: (context) => MessageDetailScreen(message: message),
    ),
  );
}

Delete messages

Delete messages from the inbox:

// Delete a single message
await Airship.messageCenter.deleteMessage(message.id);

Example: Swipe to delete

Dismissible(
  key: Key(message.id),
  direction: DismissDirection.endToStart,
  onDismissed: (direction) {
    Airship.messageCenter.deleteMessage(message.id);
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('Message deleted')),
    );
  },
  background: Container(
    color: Colors.red,
    alignment: Alignment.centerRight,
    padding: EdgeInsets.only(right: 20),
    child: Icon(Icons.delete, color: Colors.white),
  ),
  child: MessageListItem(message: message),
)

Filter messages by named user

By default, Message Center displays all messages sent to the device’s channel. If multiple users log into your app on the same device, they’ll all see the same messages.

To filter messages by named user, you need to:

  1. Include a custom key when creating messages with named_user_id as the key and the user’s actual ID as the value
  2. Implement filtering logic in your custom Message Center implementation

When creating Message Center messages:

Then filter messages in your Flutter code:

Future<List<InboxMessage>> getMessagesForCurrentUser() async {
  // Get the current named user ID
  String? currentUserId = await Airship.contact.namedUserId;
  
  if (currentUserId == null) {
    return []; // No user logged in
  }
  
  // Get all messages
  List<InboxMessage> allMessages = await Airship.messageCenter.messages;
  
  // Filter messages that match the current user
  return allMessages.where((message) {
    // Check if the message has a named_user_id extra
    String? messageUserId = message.extras['named_user_id'];
    return messageUserId == null || messageUserId == currentUserId;
  }).toList();
}