iOS

Sending push notifications using cloud code with Swift

Introduction

This section explains how you can send push notifications using Cloud Code through Back4App.

This is how it will look like:

Push Notification Via Dasboard App

At any time, you can access the complete iOS Project built with this tutorial at our GitHub repository.

Prerequisites

To complete this tutorial, you need:

Step 1 - Set up your iOS app to receive push

Every Parse application installed on a device registered for push notifications has an associated Installation object.

The Installation object is where you store all the data needed to target push notifications. For example, in your app, you could store which teams one of your users is interested in to send updates about their performance. Saving the Installation object is also required for tracking push-related app open events.

The simplest way to start sending notifications is using channels. This allows you to use a publisher-subscriber model for sending pushes. Devices start by subscribing to one or more channels, and notifications can later be sent to these subscribers. The channels subscribed to by a given Installation are stored in the channels field of the Installation object.

After that we will go over sending targeted push notifications to a single user or to a group of users based on a query.

Going forward we are going to assume you have completed all steps of the Back4App Push Notifications via Dashboard tutorial, even if you use the iOS Project built with this tutorial that is available at our GitHub repository.
You should have basic push notifications working and also be able to send pushes out via the admin console.

Step 2 - Subscribe your device to the News channel

  1. First we will add a channel to your installation object. We are going to do this by altering the method createInstallationOnParse in our App Delegate file. Open your project’s AppDelegate.swift file, and make sure your version of createInstallationOnParse is the same as the code below.
    AppDelegate.swift
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
     func createInstallationOnParse(deviceTokenData:Data){
         if let installation = PFInstallation.current(){
             installation.setDeviceTokenFrom(deviceTokenData)
             installation.setObject(["News"], forKey: "channels")
             installation.saveInBackground {
                 (success: Bool, error: Error?) in
                 if (success) {
                     print("You have successfully saved your push installation to Back4App!")
                 } else {
                     if let myError = error{
                         print("Error saving parse installation \(myError.localizedDescription)")
                     }else{
                         print("Uknown error")
                     }
                 }
             }
         }
     }
    

    We are adding one new line of code - ‘installation.setObject([“News”], forKey: “channels”)’ - which will set the installation object’s channel array to contain one channel called ‘News’.
    This will allow us to send a message to everyone who subscribes to the channel called News via cloud code.

  2. Test it by running your app on a physical device.

    You may not run this on simulator.
    You’ll need an actual push token to update your installation record, so a physical device is a must.

  3. After it runs successfully, you should see something similar to the image below in the Installation section of your Dashboard. You can check it by going to your app’s Dashboard at Back4App website and then checking the Installation table. Under the channels column you should see News, showing you that you are now subscribed to the News push channel.

    iOS Push Notification Settings In Xcode

Step 3 - Create your Cloud Code

To know more about how to get started with Cloud Code look at Cloud Code for iOS Tutorial.

  1. Create a .js file to put your Cloud Code into. You need to call it main.js in order for Back4App to know this is where you store your Cloud Code.
  2. Define a Cloud function, using Parse.Cloud.Define to call the push notification. Inside the function we will call Parse.Push.Send to send pushes to the News channel.

    It is required to use the master key in this operation.

The following code executes these steps:

main.js

1
2
3
4
5
6
7
8
9
10
Parse.Cloud.define("pushsample", (request) => {

    return Parse.Push.send({
        channels: ["News"],
        data: {
            title: "Hello from the Cloud Code",
            alert: "Back4App rocks!",
        }
    }, { useMasterKey: true });
});

main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Parse.Cloud.define("pushsample", function (request, response) {
    Parse.Push.send({
            channels: ["News"],
            data: {
                title: "Hello from the Cloud Code",
                alert: "Back4App rocks!",
            }
       }, {
            success: function () {
                // Push was successful
                response.success("push sent");
                console.log("Success: push sent");
            },
            error: function (error) {
                // Push was unsucessful
                response.error("error with push: " + error);
                console.log("Error: " + error);
            },
            useMasterKey: true
       });
});

Step 4 - Upload to Cloud Code

  1. Go to your App at Back4App website and click on Dashboard.
  2. Find the Cloud Code and click on Functions & Web Hosting. It looks like this:

    Cloud Code block

  3. Upload or create a new file (you can also edit the current main.js file directly on the browser). Then, click at Deploy as shown here:

    Cloud Code Settings

Step 5 - Call Cloud Code from your iOS app

  1. Now, we are going to write some code to call this cloud function from your app. You will need both the simulator and a physical device to complete this task. You will call the cloud function from your app running in the simulator and you will see the push appear on your physical device.

    Your physical device should actually be closed with the lock screen on in order to see the push.
    A push will not appear on the screem if you are inside the app that is sending it when you receive the push.

  2. Open your project’s ViewController.swift file. We need to include Parse in the view controller by adding the following code - ‘import Parse’- at the top of the file.
    ViewController.swift
    1
    2
    
    import UIKit
    import Parse
    
  3. Next in the ViewController.swift file we will call an alert function from the viewDidAppear method. The alert will allow you to trigger the Cloud Code code which will send a push to your device. Be sure to include the following block of code after the viewDidLoad function.
    ViewController.swift
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    
     override func viewDidAppear(_ animated: Bool) {
         askToSendPushnotifications()
     }
    
     func askToSendPushnotifications() {
         let alertView = UIAlertController(title: "Send a push to the news channel", message: nil, preferredStyle: .alert)
         let OKAction = UIAlertAction(title: "OK", style: .default) { (action:UIAlertAction) in
             self.sendPushNotifications()
         }
         alertView.addAction(OKAction)
         let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (action:UIAlertAction) in
         }
         alertView.addAction(cancelAction)
         if let presenter = alertView.popoverPresentationController {
             presenter.sourceView = self.view
             presenter.sourceRect = self.view.bounds
         }
         self.present(alertView, animated: true, completion:nil)
     }
    
     func sendPushNotifications() {
         let cloudParams : [AnyHashable:String] = [:]
         PFCloud.callFunction(inBackground: "pushsample", withParameters: cloudParams, block: {
             (result: Any?, error: Error?) -> Void in
             if error != nil {
                 if let descrip = error?.localizedDescription{
                     print(descrip)
                 }
             }else{
                 print(result as! String)
             }
         })
     }
    
  4. Run your app in the simulator and when the alert asks to send the push pops up, hit “OK”. On your physical device you should see the push appear on the lock screen, like this:

Push Notification Via Dasboard App

Step 6 - Call Cloud Code from REST API

The REST API provides a quick and easy way to test if your Cloud function is working.
Just use the code below in your terminal or command prompt:

Click on to know more about how to get started with command line in Linux, MacOS
or Windows
.

curl -X POST -H "X-Parse-Application-Id: YOUR_APP_ID_HERE" \
-H "X-Parse-REST-API-Key: YOUR_REST_API_KEY_HERE" \
-H "Content-Type: application/json" \
-d ‘{ // Put the function parameters here in JSON format }’ \
https://parseapi.back4app.com/functions/pushsample

To test the push notifications, just use the REST code while the device is closed.

Step 7 - Send targeted Push Notifications using an User Object

Going forward we will be using a different iOS project that has a basic signup and signin features already built.
We are going to be using an iOS project that you can detect if a user is logged in, and if so save their installation with a link to their object id for querying in Cloud Code.

You can download the complete iOS Project built with this section’s tutorial at our GitHub repository but you will still have to do all of the setup from the previous tutorial that explains how to send pushes fromt he Back4App dashboard.

  1. Get the new version of the app setup and signup or login to the app. First make sure you download the working template from our GitHub repository. We are not going to walk through all the steps of building this app, instead we will focus on setting up the cloud code and why it works. Once you open this new app be sure to put your own app’s credentials in the AppDelegate.swift file.
    AppDelegate.swift
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
     func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
         let configuration = ParseClientConfiguration {
             $0.applicationId = "PASTE_YOUR_APPLICATION_ID_HERE"
             $0.clientKey = "PASTE_YOUR_CLIENT_ID_HERE"
             $0.server = "https://parseapi.back4app.com"
         }
         Parse.initialize(with: configuration)
         return true
     }
    
  2. This app has some major differences between the previous app. It features 2 sections, one for being logged into your app and one section when you are not logged in to your app. The next big change is the AppDelegate.swift file’s function ‘createInstallationOnParse’. We’ve added 1 line that store’s the user’s object id as part of the installation object. That way we can know which user is associated with which installation object and can target them individually for pushes.
    AppDelegate.swift
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
     func createInstallationOnParse(deviceTokenData:Data){
         if let installation = PFInstallation.current(){
             installation.setDeviceTokenFrom(deviceTokenData)
             installation.setObject(["News"], forKey: "channels")
             if let userId = PFUser.current()?.objectId {
                 installation.setObject(userId, forKey: "userId")
             }
             installation.saveInBackground {
                 (success: Bool, error: Error?) in
                 if (success) {
                     print("You have successfully saved your push installation to Back4App!")
                 } else {
                     if let myError = error{
                         print("Error saving parse installation \(myError.localizedDescription)")
                     }else{
                         print("Uknown error")
                     }
                 }
             }
         }
     }
    
  3. Since we are now storing the user’s object id as part of the installation object we do not want to request a new push token until the user is logged in. We do not want to request a token directly from AppDelegate.swift file’s function ‘application didFinishLaunchingWithOptions’ instead we want to call it from the LoggedInViewController’s function ‘viewDidAppear’. In ‘viewDidAppear’ we call a function on the AppDelegate to request access to a push notification token from Apple. Since you can only view this section once you are logged in we can assume the user is logged in when we create the installation object, but just to be safe we used an ‘if let statement’ to unwrap the Parse.currentUser() object and retrieve the object id.
    LoggedInViewController.swift
    1
    2
    3
    
     override func viewDidAppear(_ animated: Bool) {
         appDelegate?.startPushNotifications()
     }
    

    AppDelegate.swift

    1
    2
    3
    
     if let userId = PFUser.current()?.objectId {
         installation.setObject(userId, forKey: "userId")
     }
    
  4. Ok, now, to sign up or login. On your physical device - (iphone or ipad) start the app. You should see the image below. You should sign Up to create a new user or sign in if you have already created a user on your app.
    This is how it will look like:

Push Notification Via Dasboard App

You should now be able to see the LoggedInviewController. It should look like this.

Push Notification Via Dasboard App

If you try to send pushes to yourself it won’t work yet because we haven’t added those methods to cloud code. So that’s what we will do next.

Step 8 - Add the targeted Push Methods to Cloud Code

Open your Main.js file that you created previously and add the following functions to target installations by user id.

It is required to use the master key in this operation.

main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Parse.Cloud.define('sendPushToYourself', (request) => {
    let userId = request.user.id;

    let query = new Parse.Query(Parse.Installation);
    query.equalTo("userId", userId);
    query.descending("updatedAt");
    return Parse.Push.send({
        where: query,
        data: {
            title: "Hello from the Cloud Code",
            alert: "Back4App rocks! Single Message!",
        }
    }, { useMasterKey: true });    
});

Parse.Cloud.define('sendPushToAllUsers', (request) => {
    let currentUser = request.user;
    let userIds = [currentUser.id];

    let query = new Parse.Query(Parse.Installation);
    query.containedIn('userId', userIds);
    return Parse.Push.send({
        where: query,
        data: {
            title: "Hello from the Cloud Code",
            alert: "Back4App rocks! Group Message!",
        }
    }, { useMasterKey: true });
});

main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
Parse.Cloud.define('sendPushToYourself', function (request, response) {
    var currentUser = request.user;
    var userId = currentUser.id;

    var query = new Parse.Query("Installation");
    query.equalTo("userId", userId);
    query.descending("updatedAt");
    Parse.Push.send({
        where: query,
        data: {
            title: "Hello from the Cloud Code",
            alert: "Back4App rocks! Single Message!",
        }
    }, {
        useMasterKey: true,
        success: function () {
            response.success("success sending a single push!");
        },
        error: function (error) {
            response.error(error.code + " : " + error.description);
        }
    });
});

Parse.Cloud.define('sendPushToAllUsers', function (request, response) {
    var currentUser = request.user;
    var userIds = [currentUser.id];

    var query = new Parse.Query(Parse.Installation);
    query.containedIn('userId', userIds);
    Parse.Push.send({
        where: query,
        data: {
            title: "Hello from the Cloud Code",
            alert: "Back4App rocks! Group Message!",
        }
    }, {
        useMasterKey: true,
        success: function () {
            response.success('Success sending a group push!');
        },
        error: function (message) {
            response.error(error.code + " : " + error.description);
        }
    });
});

Step 9 - Upload to Cloud Code

  1. Go to your App at Back4App website and click on Dashboard.
  2. Find the Cloud Code and click on Functions & Web Hosting. It looks like this:

    Cloud Code block

  3. Upload or create a new file (you can also edit the current main.js file directly on the browser). Then, click at Deploy as shown here:

    Cloud Code Settings

Step 10 - Test that you can send Targeted push Notifications to yourself

Open your app from the simulator while leaving your physical device closed with the lock screen on.

You can test that both push functions are working by pressing the ‘send push to a yourself’ button and the ‘send push to a group of people’ button. You should see the pushes appear on your devices lock screen, like this:

Push Notification Via Dasboard App

Final Thoughts

Now, you should have a firm understanding of how to send pushes based on a user’s channel or a user’s object id or any other query that involves getting the user’s object id.

Remember that in order to store the user’s object id you must add it to the push installation and only request a push token when the user is logged in. When sending pushes via query be aware that it is limited by default to 100 results and some users may have more than one instllation object.

Also it is not reccomended to send pushes to array of installation objects that are larger than 100 results. It could result in some pushes not getting sent. If you are dealing with large groups of people it is better to use channels or to send the pushes out in repeated requests.

It’s done!

At this stage, you can send push notifications using Cloud Code through Back4App!