A couple of days ago on Twitter, Martin Lang asked if anyone had used the Apple Push Notification Service to push a message from SAP to an iOS device. The timing of this question was excellent, as a couple of weeks earler I had built a very basic Proof of Concept to push information about a users open Workitem count to their iOS device whenever a new Work Item arrived.
So, how do you do it? In the following Blog I’d like to run through the steps I took to connect all the pieces.
Step 1. You’ll need to register some stuff at developer.apple.com.
You’ll need to install your iOS Application on an actual physical device for the APNS to work. This means you’ll need to be a member of the Apple Developer Program so that you can request a Provisioning Profile for your device from the Apple Provisioning Portal.
So, assuming you are registered with the Apple Developer Program, you need to complete the following steps.
- Generate a “Certificate Request” from your OSX Keychain and store the file locally.
- From the Apple Developer Website, go to the Provisioning Portal and create an Application Id. The name you use is important and it’s needed later.
- Go into the details of the Application Id you have created and select “Enable for Push Notifications”, and then select the “Configure” button next to the Development Push SSL Certificate option.
- A Wizard will start up, and you will need to provide the Certificate Request you generated and downloaded earler. The Wizard will generate your Push SSL Certificate for you to download. You will need this certificate to talk with the APNS Server.
- Create a Provisioning Profile for your iOS device using the Application Id you created.
The screenshot below shows an Application Id with Push Notification enabled.
Step 2. Build the iOS Client Application.
Open Xcode and create a new Window Based iOS application. Make sure you use the Application Id you created in the Provisioning Portal for the Product Name of your new applcation. The Project that Xcode creates for you should look like this (my application is called “pushnotificationdemo”). Note that this example is for a Universal application, but the PoC will work just as well for an iPad or iPhone specific project.
For the PoC, the XCode application will serve 2 purposes. The first is to give us a way to get the Device Token for our Device. When we use the APNS to push a message to a Device, the Device Token is the unique identifier used to make sure that it is only our device that receives the notification.
The second purpose of the PoC is to provide a client application to listen for Push Notifications. Those familiar with iOS devices will know that when an application receives a push notification a popup is displayed showing the message that was sent, and the “Badge” on the application icon is updated with the badge count sent with the notification.
The screenshot below shows all the code you’ll need to make the PoC work.
For those not familiar with iOS development, the didFinishLaunchingWithOptions method is called when an iOS application is started. This gives us a place to set up the application, determine what is displayed first, and then open the Application Window. In this case I have not used any views, as the PoC is only being used to test the APNS.
By calling registerForRemoteNotificationsTypes, we are telling iOS that this application wants to register for Push Notifications. This registration request is sent to the APNS at Apple. If this call is successful, the didRegisterForRemoteNotificationsWithDeviceToken method is called, and we can write the returned device token to the console.
To complete the client application, we need to assign the Provisioning Profile we created earlier. We do this by signing the code.
At this stage we can deploy the application to our iOS device. By executing the application through Xcode we can see the device token displayed in the Console.
Once you have your device token you can move onto the next step.
Step 3. Talking with the APNS.
We now need to build our Notification Provider application that will generate the notifications that are sent to our iOS device. Our Provider will need to do 2 things.
- Open a secure socket to the APNS servers. This is what the Push SSL certificate generated in the Provisioning Portal will be used for.
- Create a message in the APNS format and send this via the opened socket. The message is composed of the device token and a JSON string representing the message details. The 2 components are converted to a binary format for transmission.
How I wish the WAS could open a TCP socket on an arbitrary port for me! Maybe its my BASIS skills failing me, but I can’t see how to do it…So my next choice is to open up NWDS and see how rusty my Java is 😉
I have built 2 Java classes to interact with the APNS. The first is an abstraction of the APNS service, and has one public method “sendNotification”. The code for this is shown below.
The class also has a private method used to open the secure socket connection to the APNS.
For clarity, the constants that I have used for the secure socket connection are:
The second class represents the actual APNS Notification. The class implements a toByteArray method which is used by the sendNotification method. This allows us to encapsulate the details of the Notification format within the Notification class, while providing a simple interface for the user to create the Notification. The details of how we create a Notification will be seen later in the blog.
Below are extracts of the toByteArray method, and one of its private helper methods.
The method convertDeviceTokenToByteArray is an implementation of a HEX to Binary conversion routine.
At this stage you will be able to to test sending notifications to your iOS device.
Please see the Apple Developer Library for a detailed discussion of the APNS Notification format.
Step 4. Connect SAP to the Provider Application. Did anyone say JCo?
So what’s the easiest way to make my Java APNS Provider and my WAS talk? Well in this case I believe it’s the SAP Java Connector (JCo).
Creating a JCo Server is fairly trivial. The code below is probably about as simple as it can get.
There are 2 important things to note in the code. The first is the factory call to getServer(SERVER), which maps to a properties file called SERVER.jcoServer. This provides details such as the Program Id and the SAP Gateway host. These details are needed when we create the RFC Connection in SM59. There is also a reference to a “Repository Destination”, which is needed for the new Connection Management model in JCo 3.0. This will require a second file to be placed on the server with the extension jcoDestination.
Examples of the 2 files are shown below.
The second point worth noting in the Server code is the function registration via the registerHandler method. We simply register the SAP function name against a class that implements the JCoServerFunctionHandler interface. For my PoC I have created a function module Y_PUSHWFCOUNT and the associated Java class PushWFCount. The implementation of this class is shown below.
This class ties the SAP function call to the APNS code we wrote earlier. The first part of the method just extracts the contents of the importing parameters. The next step is the creation of the Notification. Here you can see how a “Fluent Builder” allows us to express the intent of what we are doing, making our code more readable. The final step is to send the notification with our APNS functionality.
Not far to go now, were finally at the ABAP bit!
Step 5. Some ABAP at last!!!
It’s taken a while but we’re finally working with our beloved WAS. The first thing we need to do is create an RFC connection to our JCo server. Note that the Program Id must match the Program Id in our SERVER.jcoServer file.
Make sure you test the connection before going any further.
Next, we need to create an RFC enabled function module. In my PoC I have called the function module “Y_PUSHWFCOUNT”. You can see in the Importing Parameter definitions that the parameter names match those used in the PushWFCount class where the parameters are extracted.
Step 6. A Test.
Now that we have our function module defined and our RFC destination in place we can execute the function module in the test harness and watch what happens. Note the RFC target system is APNS, which is the RFC destination we set up earlier.
And then, as if by magic, I get the folowing on my iPad. Time for a very large Latte 🙂
You can see that the Badge Count for the application is also updated to 7.
I started this blog talking about pushing a notification to my iOS device whenever I received a new Workitem. Now I have my Y_PUSHWFCOUNT function I can integrate this into the WF runtime and do exactly this.
Of course, looking back on this now, the RFC function module should have been a generic interface to the APNS Provider functionality, providing a level of abstraction that we can use in many places, rather than a specific WF Function.
There are many other questions here too, like how to manage the Device Tokens and match them with Users or Work Crews.
I see this PoC as more of a start down the road to discovering what type of functionality can be built utilising this capability.