Skip to Content

SAP Cloud Platform iOS SDK receiving Push Notifications from SAP Cloud Platform Mobile Services.

This blog post intents to show how you can set up an iOS project with the SAP Cloud Platform iOS SDK which is able to receive push notifications from Apples push notification service. Therefore this blog post shows the required steps to obtain the Apple push certificate and how to configure the SAP Cloud Platform Mobile Services.

Prerequisites

  • Real iOS device since push messages are not working on the simulator
  • Apple Developer Program Membership: You need a push notification certificate for your app ID which you can only get if you are a member of the Apple Developer Program.
  • Access to the SAP Cloud Platform Mobile Services

Finished application

A version of the finished application (without the SAP Cloud Platform iOS SDK Framework files) you can find on Github (https://github.com/walde1024/iOS-push-blog)

Configuration

Configuring Push User Role

Configuring Authentication Provider Settings in Mobile Services Cockpit (SAP Cloud Platform)

By default, SAP Cloud Platform uses SAP Cloud ID service to authenticate users against SAP user accounts. Assign the Notification User role to the SAP user ID to be able to send the push notification to the device. See the official documentation for additional information.

  1. Open the SAP Cloud Platform Cockpit
  2. Select Services.
  3. Under mobile service for development and operations, select Configure Development & Operations.
  4. Select Roles
  5. Select the Notification User role and assign a user ID to the role.

Configuring Push Notifications

For this step you need a iOS Application which you can configure to receive push notifications. This blog post uses the application which was created in one of my other blog posts regarding the onboarding process with the SAP Cloud Platform iOS SDK. You can find the blog post here. The finished application (without the SDK framework files) you can find on GitHub. But you can also use a blank application here.

Go to the general tab and set an unique bundle identifier.

 

Select your Development Team in the signing section below. This must be a paid developer account like described in the prerequisites.

 

Go to the Capabilities tab and enable Push Notifications.

 

You can verify the created App ID in the Apple Developer Center. Scroll down and click on Edit.

 

Scroll down to the Push Notifications section and click on Create Certificate. Here we use the development version of the certificate.

 

Follow the steps on the next screen.

 

Upload the CSR file and click on Continue.

 

Download the certificate and add it to your keychain by double clicking it.

 

Export the push certificate from your KeyChain as .p12 file and store it somewhere on your file system. This certificate is required to for the SAP Cloud Platform Mobile Services to send push messages to the device.

 

Go to your application in the SAP Cloud Platform Mobile Services Cockpit and navigate to the Push Notification section.

 

Upload the exported push certificate in the Apple APNS section by selecting the file and pressing Save.

 

The push configuration is now finished and the SAP Cloud Platform Mobile Services are ready now to send push messages.

 

Registering for Push Notifications

To register for push messages on the device there are two steps required. First the user needs to allow the application displaying push notifications. On the app start he will be asked with an alert for this permission.
After that the device needs to register itself by the Apple Push Notification Service (APNS) to obtain a device token. This device token is required to send push notifications to a particular device/app. Whereas the device token here is unique for every device – app combination.

Since we are using the SAP Cloud Platform Mobile Services as push provider (the server which sends the push notifications to the APNS, which sends them to the particular device) we need to send our device token to the Mobile Services as soon as we have registered for push notifications.

To fulfil these steps we need to adjust the sample application from the onboarding blog post.

 

Open the ESPMService.swift file and add the following code snippets to the ESPMService class:
This code snippet is responsible for sending the acquired device token to the SAP Cloud Platform Mobile Services. This method will be called after the user has performed the authentication.

public var deviceToken: Data?
private var remoteNotificationClient: SAPcpmsRemoteNotificationClient!

// MARK: - Push Configuration
    
func sendDeviceTokenToSAPCPms() -> Void {
    guard let deviceToken = self.deviceToken else {
        // Device token has not been acquired
        return
    }
    
    self.remoteNotificationClient = SAPcpmsRemoteNotificationClient(sapURLSession: ESPMService.shared.urlSession, settingsParameters: Constants.configurationParameters)
    self.remoteNotificationClient.registerDeviceToken(deviceToken) { error in
        if let error = error {
            print("Register DeviceToken failed Error: \(error.localizedDescription)")
            return
        }
        print("Register DeviceToken succeeded")
    }
}

 

Update the didSet callback of the urlSession attribute as following:
This callback is called as soon as the urlSession attribute is set. This happens here after the authentication. This is required since the device token cannot be sent to the Mobile Services without the prior authentication step.

private var urlSession: SAPURLSession! {
didSet {
        self.espmContainer = ESPMContainerDataAccess(urlSession: urlSession)
        sendDeviceTokenToSAPCPms()
    }
}

 

Open the AppDelegate.swift file and add the following code snippet to the AppDelegate class.

// MARK: - Remote Notification handling
    
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? = nil) -> Bool {
    UIApplication.shared.registerForRemoteNotifications()
    let center = UNUserNotificationCenter.current()
    center.requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
        // Enable or disable features based on authorization.
    }
    center.delegate = self
    return true
}

// Called to let your app know which action was selected by the user for a given notification.
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping() -> Void) {
    print("App opened via user selecting notification: \(response.notification.request.content.body)")
    // Here is where you want to take action to handle the notification, maybe navigate the user to a given screen.
    completionHandler()
}

// Called when a notification is delivered to a foreground app.
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping(UNNotificationPresentationOptions) -> Void) {
    print("Remote Notification arrived while app was in forground: \(notification.request.content.body)")
    // Currently we are presenting the notification alert as the application were in the backround.
    // If you have handled the notification and do not want to display an alert, call the completionHandle with empty options: completionHandler([])
    completionHandler([.alert, .sound])
}

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    ESPMService.shared.deviceToken = deviceToken
}

func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
    print("Failed to register for Remote Notification Error: \(error.localizedDescription)")
}

 

So what happens here? The application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? = nil) -> Bool function is called by the iOS life cycle when the application will finish launching. We use this entry point to register the application for push notifications. What the device does here is it registers itself by the Apple Push Notification Service to obtain a device token.

func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? = nil) -> Bool {
    UIApplication.shared.registerForRemoteNotifications()
    let center = UNUserNotificationCenter.current()
    center.requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
        // Enable or disable features based on authorization.
    }
    center.delegate = self
    return true
}

 

The following methods are the callbacks for the push notification registration. If the registration was successful we store the device token in the ESPMService.

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    ESPMService.shared.deviceToken = deviceToken
}

func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
    print("Failed to register for Remote Notification Error: \(error.localizedDescription)")
}

 

The other methods are used to process incoming push notifications. We let them blank here for now.

// Called to let your app know which action was selected by the user for a given notification.
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping() -> Void) {
    print("App opened via user selecting notification: \(response.notification.request.content.body)")
    // Here is where you want to take action to handle the notification, maybe navigate the user to a given screen.
    completionHandler()
}

// Called when a notification is delivered to a foreground app.
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping(UNNotificationPresentationOptions) -> Void) {
    print("Remote Notification arrived while app was in forground: \(notification.request.content.body)")
    // Currently we are presenting the notification alert as the application were in the backround.
    // If you have handled the notification and do not want to display an alert, call the completionHandle with empty options: completionHandler([])
    completionHandler([.alert, .sound])
}

 

Now we have implemented the logic to register for push notifications, obtaining the device token and sending it to the SAP Cloud Platform Mobile Services.

If you start the application now on your device it will register itself and send the device token to the mobile services.

The finished application (without the SAP Cloud Platform iOS SDK framework files) you can find here on GitHub.

 

Checking the Device Registration

Start the application on the mobile device, log in and go to the SAP Cloud Platform Mobile Services Cockpit. Navigate to your application and press on the User Registrations tab.

 

If you scroll down you should be able to see the device registration of your device.

 

If you click on the registration you should be able to see the device token which was sent to the Mobile Services by your application.

 

Sending Push Messages to the Device

Here we want to test if everything works like expected. Therefore we try to send a push message to our device which we will trigger from a rest client. The push api of the SAP Cloud Platform Mobile Services is REST based and offers different possibilities to send messages to the registered devices. More information can be found here.

We will use the following scenario:

http[s]://<HMC base URL>/restnotification/application/<applicationId>/user

Here we can define the userId’s we want to push messages to in the HTTP body. With that we are able to push a notification to multiple users without knowing their registration id.

Open a rest client which you can use to send a HTTP Post request. I’m using postman for this.
Send the following request to your SAP Cloud Platform Mobile Services:
Don’t forget to change the host, the app ID, your base64 authorization string and the userId string.

POST /restnotification/application/com.sap.ios.sdk.onboarding/user/ HTTP/1.1
Host: hcpms-d056936trial.hanatrial.ondemand.com
Content-Type: application/json
Authorization: Basic Your Auth credentials in base64
Cache-Control: no-cache
Postman-Token: a304cc51-1355-914f-bb04-0fb7f7704995

{
    "notification": {
        "alert": "You have a new purchase order for approval",
        "badge": 1,
        "data" : "{\"acme1\":\"bar\", \"acme2\" : [\"bang\", \"whiz\" ]}",
        "sound": "soundval"
    },
    "users": [
        "d056936",
        "user1"
    ]
}

 

After that you should be able to see an incoming push notification on your mobile device.

 

Pushing messages from any Backend

So we are now able to send push notifications from our rest client. The demonstrated HTTP request can now be used in your backend to send the push notifications from there.

To report this post you need to login first.

2 Comments

You must be Logged on to comment or reply to a post.

    1. Waldemar Schlegel Post author

      Thank you Robin!

      I can’t say what HMC exactly means but probably something in that direction. I guess it’s something that wasn’t updated in the documentation of the push api.

      (0) 

Leave a Reply