Tag Archives: Objective-C

Using Code Blocks Instead of Delegates with IBM MobileFirst Platform in Native iOS Apps

We’ve been able to write native iOS apps leveraging the scaffolding and analytics of the IBM MobileFirst Platform Foundation Server for a while now. This was first introduced way back when MobileFirst still went by the Worklight name, serveral versions ago.

As I would write apps, one thing I really wanted was to use code blocks instead of having to implement delegate classes every time I need to call a procedure on the MobileFirst server.   In MobileFirst 7.0, the new WLResourceRequest API allows you to invoke requests using either the completionHandler (code block) or delegate implementations.

But… what if you’re still using an earlier version of the MobileFirst platform, or what if you still want to leverage your existing code that uses WLProcedureInvocationData parameters, but don’t want to have to create a new delegate for every request?  Well, look no further.  I put together a very simple utility class that helps with this task by allowing you to pass code blocks as parameters for the requests to the MobileFirst (or Worklight) server.

You can grab the Objective-C client-side utility class from https://github.com/triceam/MobileFirst-Helper

Right now it only contains two utlitiy methods, but I’ll update it if I i come up with anything else useful. 

The invokeProcedure method allows you to invoke a procedure and pass code blocks for success/error callbacks inline, without having to define delegates.

[objc]WLProcedureInvocationData *invocationData =
[[WLProcedureInvocationData alloc]
initWithAdapterName:@"StockAdapter"
procedureName:@"getList"];

[WLClientHelper invokeProcedure:invocationData
successCallback:^(WLResponse *successResponse) {

//handle the response
}
errorCallback:^(WLFailResponse *errorResponse) {

//handle the error response
}];[/objc]

I normally prefer code blocks b/c they allow you to encapsulate functionality inside of a single class, instead of having logic spread between a controller and delegate class (and having to worry about communication between the two).

The other getLoggerForInstance utility function is just a shortcut to get an OClogger instance with the package string matching the class name of the instance passed, with just a single line of code:

[objc]OCLogger *logger = [WLClientHelper getLoggerForInstance:self];[/objc]

Download the utility directly from https://github.com/triceam/MobileFirst-Helper

Enjoy!

GeoPix: A sample iOS app powered by IBM MobileFirst for Bluemix

In this post I’d like to show a fairly simple application that I put together which shows off some of the rich capabilities for IBM MobileFirst for Bluemix that you get out of the box – All with an absolute minimal amount of your own developer effort.  Bluemix, of course, being IBM’s platform as a service offering.

GeoPix is a sample application leveraging IBM MobileFirst for Bluemix to capture data and images on a mobile device, persist that data locally (offline), and replicate that data to the cloud. Since it’s built with IBM MobileFirst, we get lots of things out of the box, including operational analytics, user authentication, and much more.

(full source code at the bottom of this post)

Here’s what the application currently does:

  • User can take a picture or select an image from the device
  • App captures geographic location when the image is captured
  • App saves both the image and metadata to a local data store on the device.
  • App uses asynchronous replication to automatically save any data in local store up to the remote store whenever the network is available
  • Oh yeah, can’t forget, the user auth is via Facebook
  • MobileFirst provides all the analytics we need.  Bluemix provides the cloud based server and Cloudant NoSQL data store.
  • All captured data is available on a web based front-end powered by Node.js

Here’s a video of it in action:

… and you can check out the web interface at geopix.mybluemix.net.

(full source code at the bottom of this post)

This is powered by the iOS 8 MobileFirst application boilerplate on Bluemix.  With this application template you can have your backend infrastructure setup within minutes, and it includes:

  • User authentication
  • Usage/operational analytics
  • Cloudant NoSQL DB
  • Simplified Push Notifications
  • Node.js backend

In this sample I’m using everything but the Push Notifications service.  I’m using user authentication, the Cloudant DB (offline/local store and remote/cloud store), and the node.js backend.  You get the operational analytics automatically.

To get started, you just need to create a new iOS 8 mobile application on Bluemix.  See my video series on Getting Started with IBM MobileFirst for Bluemix for a complete walkthrough of creating a new app using MobileFirst for Bluemix, or check out the Getting Started Guide in the official docs.

You need to initialize your app, and make sure you have setup the Facebook identity provider.  You can create your Facebook authentication at https://developers.facebook.com/.  Once the user is authenticated, the client app is fully functional.

The app UI is very simple, basically just two buttons for capturing images (the last captured image shows up in the background):

App's main UI
App’s main UI

There’s also a gallery for viewing local images:

Local gallery view
Local gallery view

Capturing Location

Capturing data is very straightforward.  The geographic location is captured using Apple’s Core Location framework.  We just need to implement the CLLocationManagerDelegate protocol:

[objc]- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations {

self.currentLocation = [locations lastObject];
NSDate* eventDate = self.currentLocation.timestamp;
NSTimeInterval howRecent = [eventDate timeIntervalSinceNow];
if (abs(howRecent) < 15.0) {
// If the event is recent, do something with it.
locationLabel.text = [NSString stringWithFormat:@" Lat: %+.5f, Lon: %+.5f\n",
self.currentLocation.coordinate.latitude,
self.currentLocation.coordinate.longitude];
}
}[/objc]

Then initialize CLLocationManager using our class as the location manager’s delegate:

[objc]if (self.locationManager == nil)
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
self.locationManager.pausesLocationUpdatesAutomatically = YES;[/objc]

Capturing Images

Capturing images from the device is also very straightforward.  In the app I leverage Apple’s UIImagePickerController to allow the user to either upload an existing image or capture a new image.  See the presentImagePicker and didFinishPickingMediaWithInfo below. All of this standard practice using Apple’s developer SDK:

[objc]- (void) presentImagePicker:(UIImagePickerControllerSourceType) sourceType {
if ( sourceType == UIImagePickerControllerSourceTypeCamera && ![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
[logger logErrorWithMessages:@"device has no camera"];
UIAlertView *myAlertView = [[UIAlertView alloc] initWithTitle:@"Error"
message:@"Device has no camera"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles: nil];
[myAlertView show];
};

if ( sourceType != UIImagePickerControllerSourceTypeCamera || [UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] ){
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self;
picker.allowsEditing = NO;
picker.sourceType = sourceType;

[self presentViewController:picker animated:YES completion:NULL];
}
}

– (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {

[logger logDebugWithMessages:@"didFinishPickingMediaWithInfo"];
UIImage *image = info[UIImagePickerControllerOriginalImage];
currentImage.image = image;
[[DataManager sharedInstance] saveImage:image withLocation:self.currentLocation];
[picker dismissViewControllerAnimated:YES completion:nil];
}[/objc]

Persisting Data

If you notice in the didFinishPickingMediaWithInfo method above, there is a call to the DataManager’s saveImage withLocation method. This is where we save data locally and rely on Cloudant’s replication to automatically save data from the local data store up to the Cloudant NoSQL database.  This is powered by the iOS 8 Data service from Bluemix.

The first thing that we will need to do is initialize the local and remote data stores. Below you can see my init method from my DataManager class. In this, you can see the local data store is initialized, then the remote data store is initialized. If either data store already exists, the existing store will be used, otherwise it is created.

[objc]-(id) init {
self = [super init];

if ( self ) {
logger = [IMFLogger loggerForName:NSStringFromClass([self class])];
[logger logDebugWithMessages:@"initializing local datastore ‘geopix’…"];

// initialize an instance of the IMFDataManager
self.manager = [IMFDataManager sharedInstance];

NSError *error = nil;
//create a local data store
self.datastore = [self.manager localStore:@"geopix" error:&error];

if (error) {
[logger logErrorWithMessages:@"Error creating local data store %@",error.description];
}

//create a remote data store
[self.manager remoteStore:@"geopix" completionHandler:^(CDTStore *store, NSError *error) {
if (error) {
[logger logErrorWithMessages:@"Error creating remote data store %@",error.description];
} else {
[self.manager setCurrentUserPermissions:DB_ACCESS_GROUP_MEMBERS forStoreName:@"geopix" completionHander:^(BOOL success, NSError *error) {
if (error) {
[logger logErrorWithMessages:@"Error setting permissions for user with error %@",error.description];
}

[self replicate];
}];
}
}];

//start replication
[self replicate];
}

return self;
} [/objc]

Once the data stores are created, you can see that the replicate method is invoked.  This starts up the replication process to automatically push changesfrom the local data store to the remote data store “in the cloud”.

Therefore, if you’re collecting data when the app is offline, then you have nothing to worry about.  All of the data will be stored locally and pushed up to the cloud whenever you’re back online – all with no additional effort on your part.  When using replication with the Cloudant SDK, you just have to start the replication process and let it do it’s thing… fire and forget.

In my replicate function, I setup CDTPushReplication for pushing changes to the remote data store.  You could also setup two-way replication to automatically pull new changes from the remote store.

[objc]-(void) replicate {
if ( self.replicator == nil ) {
[logger logDebugWithMessages:@"attempting replication to remote datastore…"];

__block NSError *replicationError;
CDTPushReplication *push = [self.manager pushReplicationForStore: @"geopix"];
self.replicator = [self.manager.replicatorFactory oneWay:push error:&replicationError];
if(replicationError){
// Handle error
[logger logErrorWithMessages:@"An error occurred: %@", replicationError.localizedDescription];
}

self.replicator.delegate = self;

replicationError = nil;
[logger logDebugWithMessages:@"starting replication"];
[self.replicator startWithError:&replicationError];
if(replicationError){
[logger logErrorWithMessages:@"An error occurred: %@", replicationError.localizedDescription];
}else{
[logger logDebugWithMessages:@"replication start successful"];
}
}
else {
[logger logDebugWithMessages:@"replicator already running"];
}
}[/objc]

Once we’ve setup the remote and local data stores and setup replication, we now are ready to save the data the we’re capturing within our app.

Next is my saveImage withLocation method.  Here you can see that it creates a new CDTMutableDocumentRevision object (this is a generic object for the Cloudant NoSQL database), and populates it with the location data and timestamp.   It then creates a jpg image from the UIImage (passed in from the UIImagePicker above) and adds the jpg as an attachment to the document revision.  Once the document is created, it is saved to the local data store.   We then let replication take care of persisting this data to the back end.

[objc]-(void) saveImage:(UIImage*)image withLocation:(CLLocation*)location {

[logger logDebugWithMessages:@"saveImage withLocation"];

//save in background thread
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^(void) {

[logger logDebugWithMessages:@"creating document…"];

NSDate *now = [NSDate date];
NSString *dateString = [NSDateFormatter localizedStringFromDate:now
dateStyle:NSDateFormatterShortStyle
timeStyle:NSDateFormatterFullStyle];

// Create a document
CDTMutableDocumentRevision *rev = [CDTMutableDocumentRevision revision];
rev.body = @{
@"sort": [NSNumber numberWithDouble:[now timeIntervalSince1970]],
@"clientDate": dateString,
@"latitude": [NSNumber numberWithFloat:location.coordinate.latitude],
@"longitude": [NSNumber numberWithFloat:location.coordinate.longitude],
@"altitude": [NSNumber numberWithFloat:location.altitude],
@"course": [NSNumber numberWithFloat:location.course],
@"type": @"com.geopix.entry"
};

[logger logDebugWithMessages:@"creating image attachment…"];

NSDate *date = [NSDate date];
NSString *imageName = [NSString stringWithFormat:@"image%f.jpg", [date timeIntervalSince1970]];

NSString *tempDirectory = NSTemporaryDirectory();
NSString *imagePath = [tempDirectory stringByAppendingPathComponent:imageName];

[logger logDebugWithMessages:@"saving image to temporary location: %@", imagePath];

NSData *imageData = UIImageJPEGRepresentation(image, 0.1);
[imageData writeToFile:imagePath atomically:YES];

CDTUnsavedFileAttachment *att1 = [[CDTUnsavedFileAttachment alloc]
initWithPath:imagePath
name:imageName
type:@"image/jpeg"];

rev.attachments = @{ imageName: att1 };

[self.datastore save:rev completionHandler:^(id savedObject, NSError *error) {
if(error) {
[logger logErrorWithMessages:@"Error creating document: %@", error.localizedDescription];
}
[logger logDebugWithMessages:@"Document created: %@", savedObject];
}];

[self replicate];
});
}[/objc]

If we want to query data from either the remote or local data stores, we can just use the performQuery method on the data store. Below you can see a method for retrieving data for all of the images in the local data store.

[objc]-(void) getLocalData:(void (^)(NSArray *results, NSError *error)) completionHandler {

NSPredicate *queryPredicate = [NSPredicate predicateWithFormat:@"(type = ‘com.geopix.entry’)"];
CDTCloudantQuery *query = [[CDTCloudantQuery alloc] initWithPredicate:queryPredicate];

[self.datastore performQuery:query completionHandler:^(NSArray *results, NSError *error) {

completionHandler( results, error );
}];
}[/objc]

At this point we’ve now captured an image, captured the geographic location, saved that data in our local offline store, and then use replication to save that data up to the cloud whenever it is available.

AND…

We did all of this without writing a single line of server-side logic.   Since this is built on top of MobileFirst for Bluemix, all the backend infrastructure is setup for us, and we get operational analytics to monitor everything that is happening.

With the operational analytics we get:

  • App usage
  • Active Devices
  • Network Usage
  • Authentications
  • Data Storage
  • Device Logs (yes, complete debug/crash logs from devices out in the field)
  • Push Notification Usage

Sharing on the web

Up until this point we haven’t had to write any back-end code. However the mobile app boilerplate on Bluemix comes with a Node.js server.  We might as well take advantage of it.

I exposed the exact same data captured within the app on the Node.js service, which you can see at http://geopix.mybluemix.net/.

Web UI
Web UI

The Node.js back end comes preconfigured to leverage the express.js framework for building web applications.  I added the jade template engine and Leaflet for web-mapping, and was able to crank this out ridiculously quickly.

The first thing we need to do is make sure  we have our configuration variables for accessing the Cloudant service from our node app.  These are environment vars that you get automatcilly if you’re running on Bluemix, but you need to set these for your local dev environment:

[js]var credentials = {};

if (process.env.hasOwnProperty("VCAP_SERVICES")) {
// Running on Bluemix. Parse out the port and host that we’ve been assigned.
var env = JSON.parse(process.env.VCAP_SERVICES);
var host = process.env.VCAP_APP_HOST;
var port = process.env.VCAP_APP_PORT;

credentials = env[‘cloudantNoSQLDB’][0].credentials;
}
else {

//for local node.js server instance
credentials.username = "cloudant username here";
credentials.password = "cloudant password here";
credentials.url = "cloudant url here";
}[/js]

Next we’ll add our URL/content mappings:

[js]app.get(‘/’, function(req, res){
prepareData(res, ‘map’);
});

app.get(‘/list’, function(req, res){
prepareData(res, ‘list’);
});[/js]

Next you’ll se the logic for querying the Cloudant data store and preparing the data for our UI templates. You can customize this however you want – caching for performance, refactoring for abstraction, or whatever you want. All interactions with Cloudant are powered by the Cloudant Node.js Client

[js]var prepareData = function(res, template) {
var results = [];

//create the index if it doesn’t already exist
var sort_index = {name:’sort’, type:’json’, index:{fields:[‘sort’]}};
geopix.index(sort_index, function(er, response) {
if (er) {
throw er;
}

//perform the search
//we’re just pulling back all
//data captured ("sort" will be numeric)
var selector = {sort:{"$gt":0}};
geopix.find({selector:selector, sort:["sort"]}, function(er, result) {
if (er) {
throw er;
}

//prepare data for template
for (var x=0; x<result.docs.length; x++) {
var obj = result.docs[x];

for (var key in obj._attachments) {
obj.image = credentials.url + "/" + database + "/" + obj._id +"/" + key;
break;
}

results.push( obj );
}
res.render(template, { results:results});
});
});
};[/js]

After the prepareData method has prepared data for formatting in the UI, the template is rendered by invoking Jade’s render method:

[js]res.render(template, { results:results});[/js]

This will render whichever template was passed in – I have two: map.jade (the map template) and list.jade (the list template). You can check out the list template below, and see it in action here: http://geopix.mybluemix.net/list

[html]html
head
title GeoPix – powered by Bluemix
link(href=’//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css’ rel=’stylesheet’)
link(href=’/public/css/index.css’ rel=’stylesheet’)
meta(name="viewport" content="width=device-width, initial-scale=1")
body
div(class=’well’)
h1 GeoPix – Powered by Bluemix
p
a(href=’/’) Map
&nbsp;|&nbsp;
a(href=’/list’) List
div(class="container-fluid")
each val, index in results
div(class="col-md-6")
div(class="panel panel-default")
div(class="panel-heading")
h3= val.clientDate
div(class="panel-body")
img(src=val.image)
p= ‘latitude: ‘ + val.latitude + ", longitude:" + val.longitude + ", altitude:" + val.altitude[/html]

In the map view I used the Leaflet map engine and Open Street Map data, along with the Leaflet Marker Cluster plugin for displaying clustered results.

Source Code

You can check out the web interface live at: http://geopix.mybluemix.net/.  If you want to setup the environment on your own, you can grab the complete source code at:

Helpful Links

Ready to start building your own apps on IBM Bluemix?  Just head over to http://bluemix.net and get a free developer trial today!

IBM Worklight Powered Native Objective-C iOS Apps

IBM MobileFirst Foundation (also known as IBM Worklight) is a middleware solution for developing mobile applications. Out of the box, Worklight enables security and authentication, device management, encrypted storage, operational analytics, simple cross platform push notifications, remote logging, data access, and more…

Historically, most people think that Worklight is just for creating hybrid mobile (HTML-powered) applications. While this is one of the powerful workflows that Worklight enables, it’s also the proverbial “tip of the iceberg”. Worklight does a lot more than just provide the foundation for secure hybrid applications. Worklight also provides a secure foundation for native applications, and can be easily incorporated to any existing (or new) native app.

In this post, I’ve put together a video series to take a look at just how easy it is to setup Worklight in an existing iOS native application to provide remote log collection, application management, and more. Read on for complete detail, or check out the complete multi-video playlist here.

The existing app that I’ll be integrating is based on an open source Hacker News client, which I downloaded from GitHub. Check out the video below for a quick introduction to what we’ll be building.

If you want, you can leverage the Worklight IDE – a set of developer tools built on top of the Eclipse development environment. If you don’t want to use Eclipse, that’s OK too – Worklight can be installed and configured using the Worklight command line interface (CLI) and you can leverage any developer tools that you’d like to build your applications. Want to tie into Xcode ? No problem. I’ll be using the Worklight CLI to setup the development environment in this series.

Setting up the Worklight Server

The Worklight server is the backbone for providing Worklight features. App managment, remote logging, operational & network analtics, and all of the Worklight features require the server, so the first thing that you need to do is setup the server for our environment. Check out the next video, which will guide you through setting up a Worklight server/project using the CLI.

First things first, you have to start the Worklight server. If you haven’t already configured a Worklight server, run the create-server command to perform the initial setup – this only has to be run once ever.

[shell]wl create-server[/shell]

Now that the server is setup, we need to create a Worklight project. For this walkthrough, I’ll just call it “MyWorklightServer”:

[shell]wl create MyWorklightServer[/shell]

Next, go into the newly created project directory and go ahead and start it.

[shell]cd MyWorklightServer
wl start[/shell]

Once the server is started, add the iOS platform:

[shell]wl add api[/shell]

You will be prompted for an API name. This can be anything, but you should probably give it a meaningful name that identifies what the API will be used for. In this walkthrough I specify the name “MyiOSNativeAPI”.

01-Worklight-CLI

Next you will be prompted to select a platform, select “iOS”
Next, build the project, and then deploy it to the server:

[shell]wl build
wl deploy[/shell]

Next, launch the Worklight console to view that the project has been deployed and the native API has been created. The console will launch in the system web browser.

[shell]wl console[/shell]

02-Worklight-Console
Worklight Console

 

Be sure to check out the Worklight CLI documentation for complete detail on the CLI commands.

Xcode Integration

Next we need to setup the Xcode project to connect to the newly created Worklight server. If you’re adding Worklight to a new Xcode project, or an existing Xcode project, the preparation steps are the same:

  1. Add Worklight files to your Xcode project
  2. Add framework dependencies
  3. Add the -ObjC linker flag

This next video walks through configuration of your Xcode project and connecting to the Worklight server (which we will cover next):

In the Xcode project navigator, create a folder/group for the Worklight files, then right click or CTRL-click and select “Add Files to {your project}”…

03-add-files

Next, navigate to the newly created MyiOSNativeAPI folder and select the worklight.plist file and WorklightAPI folder, and click the “Add” button.

04-add-files-2

Once we’ve added the files to our Xcode project, we need to link the required framework/library dependencies:

  • CoreData.framework
  • CoreLocation.framework
  • MobileCoreServices.framework
  • Security.framework
  • SystemConfiguration.framework
  • libstdc++.6.dylib
  • libz.dylib

Next, In the Xcode project’s Build Settings search for “Other Linker Flags” and add the following linker flag: “-ObjC”.

05-linker-flag

If you’d like additional detail, don’t miss this tutorial/starter app by Carlos Santanahttps://github.com/csantanapr/wl-starter-ios-app

 Connecting to the Worklight server

Connecting to the Worklight server is just a few simple lines of code. You only have to implement the WLDelegate protocol, and call wlConnectWithDelegate, and the Worklight API handles the rest of the connection process. Check out the video below to walk through this process:

Implement the WLDelegate protocol:

[objc]//in the header implement the WLDelegate protocol
@interface MAMAppDelegate : UIResponder <UIApplicationDelegate,
WLDelegate> {

//in the implementation, add the protocol methods
-(void)onSuccess:(WLResponse *)response {
}
-(void)onFailure:(WLFailResponse *)response {
}[/objc]

Connect to the Worklight Server:

[objc][[WLClient sharedInstance] wlConnectWithDelegate: self];[/objc]

Next, go ahead and launch the app in the iOS Simulator.

You’re now connected to the Worklight server! At this point, you could leverage app management and analytics through the Worklight Console, or start introducing the OCLogger class to capture client side logging on the server.

App Administration via Worklight Console
App Administration via Worklight Console

 

Worklight Analytics Dashboard
Worklight Analytics Dashboard

 

Remote Collection of Client Logs

Once you’re connected to Worklight, you can start taking advantage of any features of the client or server side APIs. In this next video, we’ll walk through the process of adding remote collection of client app logs, which could be used for app instrumentation, or for debugging issues on remote devices.

On the server, you’ll need to add log profiles to enable the capture of information from the client machines.

Adding Log Profiles
Adding Log Profiles

On the client-side, we just need to use the OCLogger class to make logging statements. These statements will be output in the Xcode console for local debugging purposes. If a log profile has been configured on the server, these statements will also be sent to the Worklight server.

[objc]OCLogger *logger = [OCLogger getInstanceWithPackage:@"MyAppPackageName"];
[OCLogger setCapture:YES];
[OCLogger setAutoSendLogs:YES];

//now log something
[logger log:@"worklight connection success"];
[logger error:@"worklight connection failed %@", response.description];
[/objc]

For complete reference on client side logging, be sure to review the Client-side log capture API documentation.

App Management & Administration

Out of the box, Worklight also provides for hassle-free (and code-free) app management. This enables you to set notifications for Worklight client apps and disable apps (cutting off access to services and providing update URLs, etc..). This next video walks you through the basics of app management.

Be sure to check out the complete documentation for app management for complete details.

All done, right?

At this point, we’ve now successfully implemented Worklight server integration into a native iOS app. We have remote collection of client-side logs, we can leverage app management, and we can collect operational analytics (including platforms, active devices, and much more).

If you don’t want to leverage any more Worklight features, then by all means, ship it! However, Worklight still has a LOT more to offer.

Exposing Data Through Adapters

Worklight also has the ability to create adapters to expose your data to mobile clients. Adapters are written in JavaScript and run on the server. They help you speed up development, enhance security, transform data serialization formats, and more.

In the next two videos we will walk through the process of collecting information inside the native iOS application and pushing that into a Cloudant NoSQL data base (host via IBM Bluemix services).

Cloudant databases have a REST API of their own, so why use a Worklight Adapter? For starters, Worklight becomes your mobile gateway.  By funneling requests through Worklight, you are able to capture analytic data for every server invocation, and Worklight gives us the ability to control access to the enterprise.  Worklight gives you the capability to cut off mobile access to the backend at any time, just by changing the API status.

Now let’s take a look at the process for exposing the Cloudant database through a Worklight Adapter:

Once the data adapter has been configured, it is simple to invoke the adapter procedures to get data into or out of the your applications.

This next video covers the process of pushing data into the Cloudant database adapter from the native mobile client application:

Once again, you will have to implement the WLDelegate protocol to handle success/error conditions, and the procedure invocation is implemented using the WLClient invokeProcedure method:

[objc]NSMutableDictionary *userProfile = [[NSMutableDictionary alloc] init];
[userProfile setValue:self.email.text forKey:@"email"];
[userProfile setValue:self.firstName.text forKey:@"firstName"];
[userProfile setValue:self.lastName.text forKey:@"lastName"];

WLProcedureInvocationData * invocationData = [[WLProcedureInvocationData alloc] initWithAdapterName:@"CloudantAdapter" procedureName:@"putData"];
invocationData.parameters = @[userProfile];

[[OCLogger getInstanceWithPackage:@"UserProfile"] log:@"sending data to server"];
[[WLClient sharedInstance] invokeProcedure:invocationData withDelegate:self];[/objc]

It is as simple as that.

IBM MobileFirst Foundation (aka Worklight) is for more than just hybrid app development. It is a secure platform to streamline your enterprise application development processes, including everything from encryption, security and authentication, to operational analytics and logging, to push notifications, and much more, regardless of whether you’re targeting hybrid app development paradigms, or native iOS, native Android, or native Windows Phone projects.