iOS native apps with MobileFirst Platform Foundation

I recently had the opportunity to put together an app that took advantage of IBM’s MobileFirst Platform Foundation (I’m sorry but in my mind its still Worklight, I can’t get used to these new names). I hope to share some of my experiences and tips as well as compare using Worklight for data retrieval versus standard mechanisms such as HTTP REST calls. For those who aren’t aware, MobileFirst Platform Foundation is a suite of tools and services to help you build mobile applications primarily for the enterprise. You might associate Worklight with hybrid apps, but it can also be used to create native apps, and as we shall see it provides a number of advantages over building the integration code yourself.

Setup

I found this video on youtube to be extremely useful to get started. It goes through the steps required to setup your project and configure Xcode to work with MobileFirst Platform. The first thing you need to do is actually not within Xcode at all, instead you have to create a native API project within MobileFirst Platform Studio. This is the client application that runs as a plug-in within Eclipse, so go ahead and install Eclipse, then search for MobileFirst in the marketplace and install it. Make sure you install the correct supported versions of Eclipse (in my case Luna SR2). Now create a Native API project and select iOS as the desired platform. Now create an adapter to retrieve your data, in my case I created a SQL adapter to a DB2 database and added several procedures to retrieve the data from our demo application called JKE Wallet. MobileFirst Studio allows you to create adapters to a wide variety of data sources such as HTTP/REST, SQL, Cast Iron, JMS, or SAP. Once the adapter is defined you then start the local MobileFirst Platform Development Server and deploy the adapter. You can call the adapter from within Eclipse and viewed the return JSON dataset to make sure it is getting what you expect.

Screen Shot 2016-04-11 at 8.24.54 AM

Now you can start setting up your Xcode environment to work with MobileFirst Platform Foundation. The first step is to copy the generated Worklight API folder in your native API project in Eclipse and copy it into the root of your Xcode project. Remember to check “Copy items if needed.” You also have to copy the Worklight.plist file from Eclipse to the root folder of your Xcode project. This contains the settings such as the hostname/IP address of your Worklight/MobileFirst Platform server. Once you have that you can go ahead and add the frameworks from the API to your project. You have to add these manually in project settings. The ones you need are:

  • SystemConfiguration.framework
  • MobileCoreServices.framework
  • CoreData.framework
  • CoreLocation.framework
  • Security.framework
  • SQLCipher.framework (from WorklightAPI/Frameworks)
  • openssl.framework (from WorklightAPI/Frameworks)
  • IBMMobileFirstPlatformFoundation.framework (from WorklightAPI/Frameworks)
  • libstdc++.6.tbd
  • libz.tbd
  • libc++.tbd

Now go ahead and add $(SRC_ROOT)/worklight/frameworks to the Build settings search path, and -ObjC to Other Linker Flags. However, since Worklight APIs are written in Objective-C you need a bridging header for it to work in your Swift app. So go ahead and create a <projectname>-bridging-header.h file in your project root. Inside the file add one line: #import “WLClient.h” then save and build your project. Now go to project settings and search for Objective-C bridging header settings and enter the name of the .h file you just created. Of course, if you don’t want to go through all those steps you can also use CocoaPods to include it in your project.

pod 'IBMMobileFirstPlatformFoundation', '~> 7.1.3'

Personally I’m not a fan of the way CocoaPods creates a separate workspace so I went with the manual approach (Plus I may not have realized there was a CocoaPod until after I was done!). Finally, you can start coding!

Accounts page

The JKE Wallet app needs to allow folks to check their financial accounts and view their balance. It also needs to allow them to view a consolidated list of their past and upcoming bill payments and check transaction. And it also needs to allow them input a new payment. I decided to use a UITabViewController at the time for each of the 3 screens, although in retrospect I should’ve put the accounts and transaction list in TabViewController and then chained a NavigationViewController to the transaction list to allow folks to add a new payment from that screen using a + button in the navigation bar. First things first, I created the invocation data object pointing to my adapter and procedure and then passed it to the Worklight server using

let invocationData = WLProcedureInvocationData(adapterName: "adapter_name", procedureName: "procedure_name")

WLClient.sharedInstance().invokeProcedure(invocationData, withDelegate: self)

Since the Worklight API uses delegates to handle the call you should add WLDelegate to the list of protocols your view controller adheres to. There are 2 functions you need to implement as a WLDelegate: onSuccess, and onFailure. In onFailure I just add an error message to the view and log the error to the console. Within onSuccess however is where you implement the code to parse the result and display it on screen. At the time I was not aware that there were libraries to deal with JSON parsing so I manually tore apart the dictionary of array of dictionaries to get the result set. It was painful. Only later did I discover SwiftyJSON which is a godsend. It makes working with JSON data so easy with subscripts. SwiftyJSON can be added to your project via CocoaPods, Carthage, or simply copying the SwiftyJSON.swift file to your project. For the accounts page I decided to display the data in a chart. I used iOS-charts which is provides beautiful charts in a view. Unfortunately since it is a port from an Android library, it has absolutely no documentation. There are a few sites that have examples but a lot of the time you are scouring the Android docs to find a corresponding function, or you just type ChartView<period> and use Xcode’s code completion to scroll through the list of methods that might be the one you want. In any case, once I fed the JSON data into a chartDataSet object I was able to get a gorgeous looking pie chart.

Screen Shot 2016-04-11 at 9.21.55 AM

 

Transactions / Calendar Page

Next up was the list of transactions. Initially I wanted to display them in a calendar view with little dots representing transactions on a day and then having the detail info in a view below the month calendar. Unfortunately I simply could not find a suitable control for that (trust me I looked all over github and cocoacontrols). There are tons of calendar pickers, but none that provide an API to add events and display the events in the bottom half of the screen. So I decided to use a sectioned table view. In the ViewDidLoad for this view I called a different procedure than the first view with the accounts. I did face a bit of a challenge in this view since I had to consolidate transactions from both the checks as well as payments table each of which had slightly different schemas. Since the delegate model of Worklight relies on callback handlers I could call a procedure for each table and then process them because both would call onSuccess and there is no way to determine which one would return first. I thought of using separate model classes, one for checks and one for payments, each of which would gather their data into an array, and then perhaps I could merge the arrays using say NSArray <AnyObject?> but it seemed overly complicated and inefficient. Then it dawned on me to join both the tables with a SQL union and let the database do the work. So I UNIONed them in a sparse matrix table.

select * from (select 'check' as type, check.date, check.amount, check.description, check.account from check) UNION ALL (SELECT 'payment' as type, payment.date, payment.amount, payment.payee as account, payment.acctype as description from payment) ORDER BY date ASC

I’m sure the database performed this much faster than my handling 2 procedure calls and then merging the arrays! So now a single procedure call is sufficient to pull the data which I then add to a 2-D array where each row is a different date for the sections. The result is as follows, I added an image to differentiate between checks and bill payments.

Screen Shot 2016-04-11 at 10.08.27 AM

Add payment page

The last view is the form to add a new payment. I thought this was the easiest one, boy was I wrong. iOS is not an ideal platform for creating forms based applications. There are only text fields, pickers, sliders, switches, and buttons. The amount field was simple since it was just a text field with a numeric number pad entry. However I wanted the date field to be a date picker. Apparently you can’t just check a box in Interface builder and say I want this to be a date field with a date picker. Instead you add a normal text field then create a datePickerView and add it to the textview’s inputView once someone starts editing it. The date picker view doesn’t even come with a Done button to hide it by default, you have to create a toolbar and add it as an accessory to the date picker. Its the same story with the accounts view where I wanted a drop down list of accounts. I had to create a picker view and attach it as an input view to the accounts text field, then create picker view data source and delegate methods to populate the accounts drop down. As with the date view, the Done button and toolbar has to be created separately. This made me seriously miss the golden age of IDEs with Visual Basic and Powerbuilder. Finally when the Submit button is tapped, it calls the Worklight procedure call to INSERT the data into the database. At first the call kept failing then I realized it needs an ID field. I had to create a database 7 digit random ID with arc4random(). The other major challenge I had with this view was how to scroll the view up when the keyboard appeared so it wouldn’t hide the field. Adding a UIScrollView with the form view as a child took all morning. For some reason it just wouldn’t stick with the proper constraints. Then you have to add this notification center observer to detect when the keyboard appears. If it does, you use this function provided by Apple to detect if the active field is hidden. If it is it will scroll up to make it visible.

Screen Shot 2016-04-11 at 10.08.55 AM

 

Once new payment was added to the database I realized that the transaction list wasn’t updated because it was populated once on ViewDidLoad. Now I could have added a NotificationCenter listener to update the data every time a row was added but that would be inefficient if someone were entering a lot of new payments but not going back to view the transaction list. Instead I decided to implement pull to refresh on the table instead which was surprisingly easy. It involves adding the refresh control as a subview and registering an action handler. In the handler I just call the Worklight procedure again which causes onSuccess to fire and repopulate the table.

Wrap-up

So in the end this was a great experience with both iOS development as well as integrating with MobileFirst Platform Foundation. After using mostly HTTP REST calls in other projects I found MobileFirst Platform data adapters to be flexible and easy to use. Apart from the initial setup (which is straightforward if you use CocoaPods) calling them and working with the data is easier than using something like AlamoFire. Data adapters can be easily modified to point to a different data source and it is easy to manage them from a central console provided by the MobileFirst Platform Server. Moreover they allow you retrieve data from a wide variety of data sources with a simple form based UI.

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s