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. It renders both web and native (SceneA mobile app or web experience of one or more screens displayed with fully native UI components in real time, providing immediate, contextual responses to user behaviors. Scenes can be presented in full-screen, modal, or embedded format using the default swipe/click mode or as a story. Scene content can also be displayed in a Message Center message and contain survey questions.) message content automatically:

<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.