Embed the Message Center

Airship’s SDK provides a simple interface for managing the Message Center within your application.

View as Markdown

This guide covers creating custom Message Center implementations for React Native applications.

Override Default Display Behavior

To use a custom Message Center implementation instead of the default UI, disable auto-launch and add a listener to handle display events:

// Disable the default UI
Airship.messageCenter.setAutoLaunchDefaultMessageCenter(false);

// Add a listener to handle display events
Airship.addListener(EventType.DisplayMessageCenter, (event) => {
  if (event.messageId) {
    // Navigate to specific message
  } else {
    // Navigate to message center
  }
});

Custom Message Center Implementation

For complete control over Message Center placement and navigation, create a custom implementation using the Message Center components.

Using the MessageView

The MessageView component can be used to display individual messages:

<MessageView 
  messageId="message-id"
  onLoadStarted={this.startLoading}
  onLoadFinished={this.finishLoading}
  onLoadError={this.failedLoading}
  style={{ flex: 1 }}
/>

Example: Custom Message Center Inbox

Here’s an example of a complete Message Center inbox implementation:

import * as React from 'react';
import {
  Text,
  View,
  FlatList,
  TouchableHighlight,
  RefreshControl,
} from 'react-native';
import Moment from 'moment';
import Airship, { Subscription, EventType, InboxMessage } from '@ua/react-native-airship';

interface MessageCenterScreenProps {
  navigation: any;
}

function Item({ message, navigation }: { message: any; navigation: any }) {
  return (
    <TouchableHighlight
      activeOpacity={0.6}
      underlayColor="#DDDDDD"
      onPress={() =>
        navigation.navigate('MessageDetails', {
          messageId: message.id,
          title: message.title,
        })
      }
    >
      <View style={styles.item}>
        <Text style={styles.itemTitle}>{message.title}</Text>
        <Text style={styles.itemSubtitle}>
          {Moment(message.sentDate).format('MM/DD/YYYY')}
        </Text>
        <View style={styles.itemSeparator} />
      </View>
    </TouchableHighlight>
  );
}

export default class MessageCenterScreen extends React.Component<
  MessageCenterScreenProps,
  {
    messages: InboxMessage[];
    refreshing: boolean;
  }
> {
  private updateSubscription?: Subscription;

  constructor(props: MessageCenterScreenProps) {
    super(props);
    this.state = {
      messages: [],
      refreshing: true,
    };

    this.refreshMessageCenter = this.refreshMessageCenter.bind(this);
    this.handleUpdateMessageList = this.handleUpdateMessageList.bind(this);
  }

  componentDidMount(): void {
    this.updateSubscription = Airship.addListener(
      EventType.MessageCenterUpdated,
      this.handleUpdateMessageList
    );
    this.handleUpdateMessageList();
  }

  componentWillUnmount(): void {
    this.updateSubscription?.remove();
  }

  handleUpdateMessageList() {
    Airship.messageCenter.getMessages().then((data) => {
      this.setState({
        messages: data,
        refreshing: false,
      });
    });
  }

  refreshMessageCenter() {
    Airship.messageCenter
      .refreshMessages()
      .then(() => {
        this.setState({
          refreshing: false,
        });
      })
      .catch((error) => {
        console.log('failed to refresh', error);
      });
  }

  render() {
    return (
      <View style={styles.backgroundContainer}>
        <FlatList
          data={this.state.messages}
          renderItem={({ item }) => (
            <Item message={item} navigation={this.props.navigation} />
          )}
          keyExtractor={(item) => item.id}
          refreshControl={
            <RefreshControl
              refreshing={this.state.refreshing}
              onRefresh={this.refreshMessageCenter}
            />
          }
        />
      </View>
    );
  }
}

Example: Message Detail Screen

Here’s an example of a message detail screen:

import * as React from 'react';
import { View, ActivityIndicator, Alert } from 'react-native';
import { MessageView } from '@ua/react-native-airship';

interface MessageScreenProps {
  navigation: any;
  route: any;
}

export default class MessageScreen extends React.Component<
  MessageScreenProps,
  {
    animating: boolean;
  }
> {
  constructor(props: MessageScreenProps) {
    super(props);
    this.state = {
      animating: true,
    };

    this.startLoading = this.startLoading.bind(this);
    this.finishLoading = this.finishLoading.bind(this);
    this.failedLoading = this.failedLoading.bind(this);
  }

  startLoading() {
    this.setState({ animating: true });
  }

  finishLoading() {
    this.setState({ animating: false });
  }

  failedLoading() {
    this.setState({ animating: false });
    Alert.alert('Error', 'Unable to load message. Please try again later', [
      { text: 'OK', onPress: () => this.props.navigation.goBack() },
    ]);
  }

  render() {
    const { params } = this.props.route;
    const messageId = params ? params.messageId : '';

    return (
      <View style={styles.backgroundContainer}>
        <MessageView
          messageId={messageId}
          onLoadStarted={this.startLoading}
          onLoadFinished={this.finishLoading}
          onLoadError={this.failedLoading}
          style={{ flex: 1 }}
        />
        {this.state.animating && (
          <View style={styles.loadingIndicator}>
            <ActivityIndicator size="large" animating={this.state.animating} />
          </View>
        )}
      </View>
    );
  }
}

For more examples, see our sample app.