Friday 19 October 2012

Extending PhoneGap with native plugins for iOS


This article examines native plugins for PhoneGap (also known as Apache Cordova) applications in Xcode, targeting iOS devices. If you are just starting out with PhoneGap or if you need to review the fundamentals of PhoneGap, readGetting started with PhoneGap in Xcode for iOS before continuing.
The terms Cordova and PhoneGap are used interchangeably within this article to refer to the same open source application platform that lets you create natively-installed mobile applications using HTML and JavaScript. The PhoneGap codebase moved to open source at Apache Software Foundation under the name Cordova. Adobe is still distributing it under the name PhoneGap. For more information, check out Brian Leroux's blog post "PhoneGap, Cordova, and what's in a name?" As Brian says in the post, "Currently, the only difference is in the name of the download package and will remain so for some time."
Not only does PhoneGap enable you to build user interfaces for natively installed mobile applications using web technologies, PhoneGap also provides a JavaScript-based API to interact with native device functionality. By default, PhoneGap provides access to the device camera, accelerometer, file system, GPS location, and media playback among other capabilities. However, PhoneGap does not expose every native API for use within your JavaScript applications. If you want PhoneGap to do more than its default feature set, you can use the PhoneGap native plugin model to extend the capabilities of the core PhoneGap API.
Native plugins in PhoneGap are not like plugins in desktop browsers; rather they provide a way for you to plug incustom code to add to what the PhoneGap application framework can do. PhoneGap native plugins enable you to create completely new, custom functionality in native code, and expose that to your PhoneGap applications via PhoneGap's native-to-JavaScript bridge. This means that you can expose any native library or framework for use within your JavaScript-based PhoneGap applications.

Understanding the PhoneGap native plugin structure

Before you start to write PhoneGap native plugins, it will help to understand how the PhoneGap application container exposes native operating system functionality to JavaScript-based applications.
All Cordova APIs consist of two related parts: a JavaScript-based interface that can be accessed within your applications, and the corresponding native class for performing operations in native code. Typically, the JavaScript classes and the native classes have APIs that mirrors each other, so that they are easy to follow. The JavaScript class invokes the native code using the Cordova.exec() function. When it invokes Cordova.exec , it can pass in a result handler function, an error handler function, and an array of parameters to be passed into native code, as well as a reference to the native class's name and native function name. Cordova will manage the JavaScript-to-native communication, and you can focus on building your application.
To learn more about PhoneGap native plugins, take a look at the core API's source code, available at the Cordova wiki. The entire PhoneGap framework is built upon the same paradigm you'll find there.

Building your first plugin

To start building your first PhoneGap native plugin, you'll need to create a new PhoneGap project following the steps outlined in the article Getting started with PhoneGap in Xcode for iOS. I named my project MyFirstPhoneGapNativePlugin.

The JavaScript class

Once you have set up your Hello Xcode project, you're ready to create the JavaScript interface for the native plugin. You will need to create a class with functions that will mirror the logic exposed by the native code. Under the www folder, create a JavaScript file named HelloPlugin.js that contains the simple JavaScript class shown below.
var HelloPlugin = { callNativeFunction: function (success, fail, resultType) { return Cordova.exec( success, fail, "com.tricedesigns.HelloPlugin", "nativeFunction", [resultType]); } };
The HelloPlugin class has a single function named callNativeFunction , which accepts a success callback function, an error callback function, and a resultType string parameter. The callNativeFunction function wraps the Cordova.exec function, which will invoke the actual native code. There is no additional JavaScript inside of this class, but you can add JavaScript code here if you need to.
When Cordova.exec is invoked, it expects five parameters:
  • a reference to a success callback function (a function that will be invoked upon a successful response from the native code layer)
  • an error callback function (a function that will be invoked upon an error response from the native layer)
  • a string reference to the native code class (I cover this in more detail below)
  • a string reference to the name of the function that should be invoked
  • an array of parameters to be passed into the native code
Keep in mind that code execution between the JavaScript and native code layers is not synchronous, so you'll need to use callback functions and asynchronous coding practices when developing PhoneGap native plugins.

The Native class

To create the native code layer, start by creating a new native Objective-C class that extends the CDVPlugin class from the core Cordova API:
  1. Right-click the Plugins directory inside of your PhoneGap project, and select New File (see Figure 1).
Figure 1. Creating the new file.
Figure 1. Creating the new file.
  1. In the New File wizard, select the Objective-C class template and click Next (see Figure 2).
Figure 2. Selecting the Object-C class template.
Figure 2. Selecting the Object-C class template.
  1. Type HelloPlugin for the new class name and make the class a subclass of CDVPlugin (see Figure 3).
Figure 3. Naming the class.
Figure 3. Naming the class.
The CDVPlugin class is the parent class that all Cordova classes must extend. The CDVPlugin class encapsulates all logic necessary for native-JavaScript communication via the PhoneGAP API. The PhoneGap.exec function enables you to invoke functions on this new class. The CDVPlugin class has a core function named writeJavascript , which enables you to invoke JavaScript within the PhoneGap application's web view. All communication in the direction of native to web JavaScript must be done using the writeJavascript function.
  1. Click Next.
  2. When prompted specify a location for the new files (preferably the "Plugins" directory within your Xcode project), and then click Finish to proceed.
You should see the new header file (.h) and implementation file (.m) in your PhoneGap project (see Figure 4).
Figure 4. The new native class files.
Figure 4. The new native class files.
  1. Next, add a definition for the nativeFunction function in your .h file; for example:
#import <Cordova/CDV.h> @interface HelloPlugin : CDVPlugin - (void) nativeFunction:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options; @end
This definition has two parameters: an NSMutableArray of arguments received from the JavaScript layer and a dictionary (map) of options. For this example, you only need to worry about the array of arguments. The header file only contains method signatures; you do not include any application logic in the .h file.
  1. Once you've created your class signature, add your logic to the nativeFunction function instance in the .m file. Below you will see a sample Objective-C function used inside of this native plugin class.
#import "HelloPlugin.h" @implementation HelloPlugin - (void) nativeFunction:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options { //get the callback id NSString *callbackId = [arguments pop]; NSLog(@"Hello, this is a native function called from PhoneGap/Cordova!"); NSString *resultType = [arguments objectAtIndex:0]; CDVPluginResult *result; if ( [resultType isEqualToString:@"success"] ) { result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString: @"Success :)"]; [self writeJavascript:[result toSuccessCallbackString:callbackId]]; } else { result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString: @"Error :("]; [self writeJavascript:[result toErrorCallbackString:callbackId]]; } } @end
Inside of the nativeFunction method, you first need to get a reference to the NSString callbackId , which is used by the core PhoneGap API to map the response of this function back to the originating JavaScript that invoked this function.
Next this method writes a message out to the Xcode debug console using NSLog ; this just shows that it is executing native code.
After writing to the debug console, the function examines the resultType that was passed into the function, and creates the appropriate CDVPluginResult instance. The resultType value is a simple string. If resultType is "success" , the function will create a success result, and write the success callback to the JavaScript layer using the[self writeJavascript] function. Any other value for the resultType parameter will generate an error result, and the function will write the error callback to the JavaScript layer.
When you write back to the success or error callback functions in JavaScript, always use a CDVPluginResult instance. However, you can also use the writeJavascript function to pass any JavaScript string back to the JavaScript layer. This technique can even be used to push data from the native layer to the JavaScript layer in real time.

Invoking the plugin

Now that you have created a plugin, you can invoke it from within your PhoneGap application.
  1. First, you will need to add a reference to the new plugin's JavaScript interface class (HelloPlugin.js). Add a new<script> tag inside of your index.html file:
<script type="text/javascript" charset="utf-8" src="HelloPlugin.js"></script>
  1. Also after the onDeviceReady() function, add the JavaScript for invoking the native plugin and handling the plugin results. Add JavaScript functions named callNativePlugin , nativePluginResultHandler , andnativePluginErrorHandler as shown below:
function callNativePlugin( returnSuccess ) { HelloPlugin.callNativeFunction( nativePluginResultHandler, nativePluginErrorHandler, returnSuccess ); } function nativePluginResultHandler (result) { alert("SUCCESS: \r\n"+result ); } function nativePluginErrorHandler (error) { alert("ERROR: \r\n"+error ); }
  1. The callNativePlugin function will simply call the JavaScript interface of the native plugin class. When it invokes the callNativeFunction method, it passes the callback functions for success and error status received from the native code layer. The nativePluginResultHandler function will be invoked if there is a success callback from the native layer, and the nativePluginErrorHandler function will be invoked upon an error callback from the native layer.
  1. Next add two JavaScript buttons as shown in the code below to invoke the plugin.
<body onload="onBodyLoad()"> <h1>Hey, it's Cordova!</h1> <button onclick="callNativePlugin('success');">Click to invoke the Native Plugin with an SUCCESS!</button> <button onclick="callNativePlugin('error');">Click to invoke the Native Plugin with an ERROR!</button> </body>
When clicked, the first button will invoke the callNativeFunction method with the parameter "success". PhoneGap will then execute native code and invoke a success callback in the JavaScript layer (it will invoke thenativePluginResultHandler function).
When you click the second button, the callNativeFunction method with will be called with the parameter "error". PhoneGap will execute native code and invoke an error callback in the JavaScript layer (it will invoke thenativePluginErrorHandler function).

Mapping the native code class

At this point you have almost everything wired up and ready to go, but there is still one more step that you have to complete before you will be able to invoke native code from JavaScript.
You have to add a mapping so that Cordova can identify your native code class. Remember the string reference that you used to identify the native class when calling Cordova.exec? You need to map that string to the actual class instance in the Cordova.plist file. The Cordova.plist file contains all configuration information for the current Cordova project.
  1. In the project navigator, open the Supporting Files folder, and click the file named Cordova.plist.
  2. On the right, scroll down to the Plugins entry and click to expand it.
  3. Add an entry with the key com.tricedesigns.HelloPlugin and the value "HelloPlugin" (see Figure 5), and replace com.tricedesigns with your company identifier. This is the string reference that you used to identify the native class in the third parameter when calling Cordova.exec.
The key is the unique string reference that is used by PhoneGap.exec to map to the native code class. The value is the name of the actual native class that will be invoked.
  1. Save your changes.
Figure 5. Editing Cordova.plist.
Figure 5. Editing Cordova.plist.
Now you are ready to launch the application and test it out.
To launch the application click the Run button or choose Product > Run.
Once the application launches in the iOS Simulator (or on a connected device), you will see a simple interface with two buttons (see Figure 6). Click on either button to invoke the native plugin's native code, and an alert message will be displayed via JavaScript upon either a success or error callback.
Figure 6. The application running in the iOS simulator.
Figure 6. The application running in the iOS simulator.

Saturday 13 October 2012

Free To Paid iPhone Application Data Migrations With Custom URL Handlers


Free stores user data in an encrypted SQLite Database. Since we really wanted a way to copy the data file from Free to paid we developed a fairly clever solution: use a registered URL handler as a means of communication between application versions. This is how it works:
  1. A customer downloads  free and enters some unique private data. All information is written to a database in the application’s document directory.
  2. When the 10 record limit is hit free asks them to upgrade. An upgrade button launches to explain the process and allow the user to download the paid version of the product.
  3. Once Strip is purchased and installed, our customer will launch free and click an “Export to free” button. free reads the application database into an NSData object, Base64 encodes it and then Launches a “strip://” URL with the encoded file contents as a URL parameter.
  4. The full version of paid is registered as a handler for “strip://” URLs. The OS launches paid and passed the URL to the handleOpenURL method of the application delegate. It parses and decodes the data and writes the database to the desired location in the new applications Document folder.
  5. Our customer now has access to all the data the originally entered into free!

Project Setup

This tutorial assumes that your project is already configured with two targets, one for your full version, and one for the Lite.
Start by creating a new InfoLite.plist file for your Lite version. We use 2 separate .plist files to ensure that the Full version is the only registered URL handler (we don’t want the Lite version responding to upgrade events itself!). It is easiest to just make a copy of the existing Info.plist file named InfoLite.plist.
Next, Open up the Build preferences for the Lite target. Change the Info.plist File property to read InfoLite.plist. This will ensure that the Lite target includes the proper file.
Now open the Info.plist (used by the Full Version) and register a custom URL handler. This is a straightforward process of adding elements as shown in the following screenshot.
Please note that the URL identifier and URL scheme must be unique for your application — see this stepwise overview of the process for reference.
Finally, the application must include code to perform Base64 encoding itself. This functionality is, unfortunately, not directly accessible in the framework SDK. There are a few options in Cocoa, including using OpenSSL’s libcrypto, but the easiest method is to use the encoding libraries fromGoogle Toolbox for Mac which is conveniently distributed under the Open Source Apache License. Download GTMDefines.h, GTMBase64.h and GTMBase64.m, then add them to your project. The GTM code compiles perfectly on the iPhone and even includes web safe variants that are immediately suitable for use in URLs without percent encoding.

he controller action code will read the data file, encode it and then format a URL with the protocol prefix / URL scheme configured in the previous step.
#import "GTMBase64.h" 
...
NSData *fileData = [NSData dataWithContentsOfFile:@"/path/to/LiteApplication/Documents/file"];
NSString *encodedString = [GTMBase64 stringByWebSafeEncodingData:fileData padded:YES];
NSString *urlString = [NSString stringWithFormat:@"myapp://localhost/importDatabase?%@", encodedString];
NSURL *openURL = [NSURL URLWithString:urlString];
[[UIApplication sharedApplication] openURL:openURL];

The Full Version

The final step is to make your application handle the Open URL event and reverse the encoding process.
Add a handleOpenURL method to the AppDelegate implementation as follows. This will receive the URL, sanity check it, and then parse the query string directly. The resulting binary data is written to the file in the full application’s data directory.
#import "GTMBase64.h" 
...
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {
    if([@"/importDatabase" isEqual:[url path]]) {
        NSString *query = [url query];
        NSString *importUrlData = [GTMBase64 webSafeDecodeString:query];

        // NOTE: In practice you will want to prompt the user to confirm before you overwrite their files!
        [importUrlData writeToFile:@"/path/to/FullApplication/Documents/file" atomically:YES];
        return YES;
    }
    return NO; 
}

Tuesday 2 October 2012

use single developement profile in different devices


Use one iPhone development license on different mac.

Step 1: To export your private key and certificate for safe-keeping and for enabling development on multiple systems, open up the Keychain Access Application and select the ‘Keys’ category.
Step 2: Control-Click on the private key associated with your iPhone Development Certificate and click ‘Export Items’ in the menu. The private key is identified by the iPhone Developer: public certificate that is paired with it.
Step 3: Save your key in the Personal Information Exchange (.p12) file format.
Step 4: You will be prompted to create a password which is used when you attempt to import this key on another computer.
Step 5: You can now transfer this .p12 file between systems. Double-click on the .p12 to install it on a system. You will be prompted for the password you entered in Step 4.