🎉 New release for Pusher Chatkit - Webhooks! Extend your in-app chat functionality
Hide
We're hiring
Products

Channels

Beams

Chatkit

DocsTutorialsSupportCareersPusher Blog
Sign InSign Up
Products

Channels

Build scalable, realtime features into your apps

Features Pricing

Beams

Send push notifications programmatically at scale

Pricing

Chatkit

Build chat into your app in hours, not days

Pricing
Developers

Docs

Read the docs to learn how to use our products

Channels Beams Chatkit

Tutorials

Explore our tutorials to build apps with Pusher products

Support

Reach out to our support team for help and advice

Status

Check on the status of any of our products

Products

Channels

Build scalable, realtime features into your apps

Features Pricing

Beams

Send push notifications programmatically at scale

Pricing

Chatkit

Build chat into your app in hours, not days

Pricing
Developers

Docs

Read the docs to learn how to use our products

Channels Beams Chatkit

Tutorials

Explore our tutorials to build apps with Pusher products

Support

Reach out to our support team for help and advice

Status

Check on the status of any of our products

Sign InSign Up

Using Pusher Beams to notify users of a new release of your iOS app

  • Lanre Adelowo
February 13th, 2019
You will need Xcode and React Native installed on your machine.

In this tutorial, we are going to look into building a todo iOS app with React Native. The most interesting part of this tutorial is the fact that we will be implementing push notifications via Pusher Beams. Every time an updated version of the app is released to the App Store, all devices that have the app installed will get a notification informing them of the available upgrade.

Prerequisites

To follow along in this tutorial you need the following things:

  • Xcode installed on your machine. Download here.
  • Know your way around the Xcode IDE.
  • React Native. Find out how to install it here. You will need to follow the section Building Projects with Native Code.
  • Carthage installed on your machine. Install it with brew install carthage.
  • A Pusher Beams account. Create one here.

If you happen not to have brew installed, you can do so by running /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)".

Creating the iOS project

We will be naming our project todoApp. To do that we will be needing to make use of the react-native CLI tool to create a new iOS project. Open a terminal and run the following command:

    $ react-native init todoApp

Depending on your internet connection, the above command should take some time. Once it is done, we are ready to add functionality to our iOS app.

The first thing we need to do is to actually build a useful app - the to-do app. Open up the project in your favorite editor, then create a file called Todo.js. It will serve as the model for our project. In Todo.js, you will have to paste the following code:

    // todoApp/Todo.js

    import { AsyncStorage } from 'react-native';

    export default class Todos {
      constructor() {
        this.tasks = {
          items: [],
        };

        this.all(() => {});
      }

      // register a callback event passing the items found in the store
      // as it's arguments
      all = callback => {
        AsyncStorage.getItem('pushertutorial', (err, allTasks) => {
          if (err !== null) {
            return;
          }

          if (allTasks === null) {
            return;
          }

          this.tasks = JSON.parse(allTasks);
          callback(this.tasks.items);
        });
      };

      // saves a new item to the store
      save = item => {
        this.tasks.items.push(item);
        return AsyncStorage.setItem('pushertutorial', JSON.stringify(this.tasks));
      };

      // deletes an item based off an index from the store.
      delete = index => {
        this.all(items => {
          const tasks = {
            items: items.filter((task, idx) => {
              return idx !== index;
            }),
          };
          AsyncStorage.setItem('pushertutorial', JSON.stringify(tasks));
        });
      };
    }

The above code uses the default key-value pair storage system bundled with React Native called AsyncStorage to retrieve and save our to-do items. You can read more about AsyncStorage here.

Moving on, we will have to actually make use of the Todo model we created earlier. To do this, you will need to edit the App.js file already created by React Native during the installation earlier. You should edit App.js and paste in the following:

    // todoApp/App.js

    import React, { Component } from 'react';
    import {
      AppRegistry,
      StyleSheet,
      Text,
      View,
      FlatList,
      AsyncStorage,
      Button,
      TextInput,
      Keyboard,
      Platform,
    } from 'react-native';
    import Todos from './Todo';

    export default class TodoList extends Component {
      constructor(props) {
        super(props);

        this.state = {
          tasks: [],
          text: '',
        };

        this.todos = new Todos();
        this.syncTodos();
      }

      syncTodos = () => {
        this.todos.all(items => {
          this.setState({
            tasks: items,
            text: '',
          });
        });
      };

      updateTaskText = text => {
        this.setState({ text: text });
      };

      addTask = () => {
        let notEmpty = this.state.text.trim().length > 0;

        if (notEmpty) {
          let { tasks, text } = this.state;

          this.todos.save({ text });
          this.syncTodos();
        }
      };

      deleteTask = i => {
        this.todos.delete(i);
        this.setState({
          tasks: this.state.tasks.filter((task, index) => {
            return index !== i;
          }),
        });
      };

      render() {
        return (
          <View style={[styles.container, { paddingBottom: 10 }]}>
            <FlatList
              style={{ width: '100%' }}
              data={this.state.tasks}
              keyExtractor={(item, index) => item.text}
              renderItem={({ item, index }) => (
                <View key={index}>
                  <View
                    style={{
                      flexDirection: 'row',
                      alignItems: 'center',
                      justifyContent: 'space-between',
                    }}
                  >
                    <Text
                      style={{
                        paddingTop: 2,
                        paddingBottom: 2,
                        fontSize: 18,
                      }}
                    >
                      {item.text}
                    </Text>
                    <Button title="X" onPress={() => this.deleteTask(index)} />
                  </View>
                </View>
              )}
            />
            <TextInput
              style={styles.input}
              onChangeText={this.updateTaskText}
              onSubmitEditing={this.addTask}
              value={this.state.text}
              placeholder="Add a new Task"
              returnKeyType="done"
              returnKeyLabel="done"
            />
          </View>
        );
      }
    }

    const styles = StyleSheet.create({
      container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#F5FCFF',
        padding: 10,
        paddingTop: 20,
      },
      input: {
        height: 40,
        paddingRight: 10,
        paddingLeft: 10,
        borderColor: 'gray',
        borderWidth: 1,
        width: '100%',
      },
    });

While the above code is simple and straightforward, I would like to explain deleteTask. After deleting an item from the database, we remove the app from the local state too. This is to allow a UI update.

You can now run this app by either:

  • react-native run-ios
  • Clicking the play button in Xcode. ( highly recommended ).

At this stage, you should have the following:

Push notifications

You have worked hard into this new release of your app, it wouldn’t make any sense to have just 2% of your existing users making use of the newer release - including critical bug fixes and some UI improvements probably. Sending push notifications to users can be a good way to keep your users informed.

In this section, we will configure and add Pusher Beams to our application to help us deliver push notifications about updates to users who have the app installed.

We will be making use of two packages to achieve this.

Using the React Native bridge requires the installation of the official SDK.

We will start by installing the official iOS SDK. We will make use of Carthage for this. Carthage makes use of a Cartfile to track dependencies to install, so we will need to create that file.

    $ # Assuming you are at the root directory which is todoApp
    $ cd ios
    $ touch Cartfile

The next thing to do is to specify the exact dependencies you want installed. This is as easy as pasting the following content in the Cartfile:

    // todoApp/ios/Cartfile
    github "pusher/push-notifications-swift"

Once the dependencies have been specified, the next point of action is to actually install them. To do that, you will need to run the below command in a terminal:

    # This assumes you are in the todoApp/ios directory
    $ carthage update

Once carthage is done installing, you will need to:

  1. In Xcode, visit the General settings tab of the application’s target, in the “Linked Frameworks and Libraries” section, drag and drop the PushNotifications.framework from the Carthage/Build folder on disk.

A directory called Carthage will be created next to the **Cartfile**. You will need to locate **PushNotifications.framework** in the iOS folder too.

  1. On your application targets’ Build Phases settings tab, click the + icon and choose New Run Script Phase. Create a run script in which you specify your shell (ex: /bin/sh), add the following contents to the script area below the shell:

    /usr/local/bin/carthage copy-frameworks

  1. Add the path below to PushNotifications.framework under “Input Files".

    $(SRCROOT)/Carthage/Build/iOS/PushNotifications.framework

  1. Add the path below to PushNotifications.framework under the “Output Files”.

    $(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/PushNotifications.framework

The next step is to now install the React Native bridge which will allow us access native code (the official iOS SDK in this case ) from JavaScript. To do that, you need to run the following command

    $ npm install react-native-pusher-push-notifications
  1. In Xcode, in the project navigator, right click LibrariesAdd Files to todoApp.
  2. Go to node_modulesreact-native-pusher-push-notifications and add RNPusherPushNotifications.xcodeproj
  3. In Xcode, in the project navigator, select your project. Add libRNPusherPushNotifications.a to your project's Build PhasesLink Binary With Libraries

Open the AppDelegate.m to register the device for push notifications. Append the following contents to the file:

    // todoApp/ios/AppDelegate.m

    // Add this to the top of the file where other imports are placed.
    #import "RNPusherPushNotifications.h" 

    - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
      NSLog(@"Registered for remote with token: %@", deviceToken);
      [[RNPusherPushNotifications alloc] setDeviceToken:deviceToken];
    }

    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
      [[RNPusherPushNotifications alloc] handleNotification:userInfo];
    }

    -(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
      NSLog(@"Remote notification support is unavailable due to error: %@", error.localizedDescription);
    }

As a final step, you will need to add the following to your Header search path under **Build Settings, $(SRCROOT)/../node_modules/react-native-pusher-push-notifications/ios.

If you receive an error such as “dyld: Library not loaded:”, you should go to Build Settings and set Always Embed Swift Standard Libraries to yes.

Login or create an account to access your Pusher Beams dashboard here. Create a new Pusher Beams instance using the dashboard.

Complete only step one of the iOS setup guide and follow the onscreen instructions to upload (and how to find) your APN key and Team ID. Then press the X to exit the setup guide and you will be returned to your dashboard for that instance. Scroll to the bottom of this page and you will find your Pusher Beams instance ID and secret key, make note of these you will need them later.

As a final step, you will need to enable push notifications capabilities for the project. You will also need to set the correct team and bundle ID as without those, push notifications capabilities cannot be enabled.

You will need to edit the index.js file to ask the user for permissions to send notifications and also subscribe to the updates topic.

    // todoApp/index.js

    import { Alert, Linking, AppRegistry, Platform } from 'react-native';
    import App from './App';
    import { name as appName } from './app.json';
    import RNPusherPushNotifications from 'react-native-pusher-push-notifications';

    const appUpdateInterest = 'debug-updates';

    // Initialize notifications
    export const init = () => {
      // Set your app key and register for push
      RNPusherPushNotifications.setInstanceId(
        'YOUR_PUSHER_INSTANCE_KEY'
      );

      // Init interests after registration
      RNPusherPushNotifications.on('registered', () => {
        subscribe(appUpdateInterest);
      });

      // Setup notification listeners
      RNPusherPushNotifications.on('notification', handleNotification);
    };

    // Handle notifications received
    const handleNotification = notification => {
      if (Platform.OS === 'ios') {
        Alert.alert('App update', notification.userInfo.aps.alert.body, [
          { text: 'Cancel', onPress: () => {} },
          {
            text: 'Update now',
            onPress: () =>
              // Just open up Apple's Testlight in the app store.
              // Ideally we will replace this if the app has been previously released to 
              // the app store
              Linking.openURL(
                'itms-apps://itunes.apple.com/ng/app/testflight/id899247664?mt=8'
              ),
          },
        ]);
      }
    };

    // Subscribe to an interest
    const subscribe = interest => {
      console.log(interest);
      RNPusherPushNotifications.subscribe(
        interest,
        (statusCode, response) => {
          console.error(statusCode, response);
        },
        () => {
          console.log('Success');
        }
      );
    };

    init();

    AppRegistry.registerComponent(appName, () => App);

The above piece of code is really easy to understand as it all does is configure the PushNotifications library to make use of the key we got from the dashboard earlier. When the device has been registered with Pusher Beams, we subscribe the user to the debug-updates topic as all notifications for updating the app will be published to that topic.

In handleNotification , we show an alert dialog that provides the user with two options. One is to cancel, the other is to actually update. Clicking on the option to update the app will take the user to the Apple app store.

Since this is an hypothetical app, we will forward the user to Apple’s Testflight app. You can replace the link to that of a real app if the app already exists on the app store.

Sending push notifications to the device

The bulk of the entire work has been done. All is that is left now is to actually test that push notifications are delivered to the user. To do this, you will need to visit your instance page on the dashboard. You will want to navigate to the Debug console.

You will need to run the app on a real device as push notifications do not work on a simulator.

Once you have filled the above form, click on the Publish Notifications button. You will get an alert on your device in less than a second.

Here is an example of how the app works. You should be able to replicate this behavior on your device.

Conclusion

In this tutorial, we have built a mechanism for informing users of updates to our app with the help of Pusher Beams.

The source code can be found on GitHub.

Clone the project repository
  • Beams
  • iOS
  • JavaScript
  • React Native
  • Beams

Products

  • Channels
  • Chatkit
  • Beams

© 2019 Pusher Ltd. All rights reserved.

Pusher Limited is a company registered in England and Wales (No. 07489873) whose registered office is at 160 Old Street, London, EC1V 9BW.