Home > iOS, Mobile Development, Objective-C, PhoneGap > PhoneGap Tutorial Series – #5 Third-Party Plugins (NativeControls)

PhoneGap Tutorial Series – #5 Third-Party Plugins (NativeControls)

 

Extending the PhoneGap API – Third-Party Plugins (NativeControls)

 
Continuing on down the path of using third party plugins, today we will look at a little more complex example and use the NativeControls plugin to display a UIActionSheet to allow the user to select whether they want to take a photo using the camera or pick one from the photo library by utilizing the PhoneGap Camera API.

If you haven’t read my previous post on Third-Party Plugins (ChildBrowser) you may want to peruse that to understand the structure of a plugin and how to go about installing one before continuing on.
 

Native Controls Plugin

The NativeControls plugin provides access to several native controls that are commonly used in iOS iPhone development. The plugin for the controls provides access to varying levels of functionality:

  1. UIActionSheet – provides a slide up control with one to many buttons, the plugin allows the creation of the actionSheet, adding of buttons, and a delegate to respond to a user selection
  2. UIStatusBar – the plugin provides the ability to hide the standard status bar
  3. UIToolBar – provides a toolBar control with one “refresh” button, the plugin support for controlling the toolBar is currently somewhat limited
  4. UITabBar – provides a tabBar control with with one to five buttons, the plugin allows the creation of the tabBar, adding buttons, button actions, positioning, and show/hide capabilities


 

How to Use the Native Controls Plugin?

Just like with the ChildBrowser plugin, there is a JavaScript file that must be included on the HTML page. After inspecting that Javascript, you will see that near the end of the file there is a reference to the PhoneGap.addConstructor so this particular plugin “installs” itself when you include the NativeControls.js on the page.

PhoneGap.addConstructor(function() 
{
	if(!window.plugins)
	{
		window.plugins = {};
	}
    window.plugins.nativeControls = new NativeControls();
});

The following is an excerpt from the nativeControls.html in the HelloPhoneGap project. The code demonstrates how to use the nativeControls plugin to create and display an actionSheet and how to react to a user selection in order to exercise the PhoneGap Camera API.

<script type="text/javascript" charset="utf-8" src="phonegap.0.9.4.min.js"></script>
<script type="text/javascript" charset="utf-8" src="NativeControls.js"></script>
<script type="text/javascript" charset="utf-8">
                var nativeControls;                    
                function onBodyLoad()
                {
                    document.addEventListener("deviceready",onDeviceReady,false);
                }
                /* When this function is called, PhoneGap is ready to roll */
                function onDeviceReady()
                {
                    phoneGapReady.innerHTML = "PhoneGap is Ready";
                    nativeControls = window.plugins.nativeControls;
                }
                function showCameraOptions()
                {
                    var buttons = ["Take Photo", "Choose From Library", "Cancel"];
                    var delegate = nativeControls.createActionSheet(buttons, null, 2, null);
                    delegate.onActionSheetDismissed = function(index)
                    {
                        if (index == 0)
                        {
                            navigator.camera.getPicture(onPhotoURISuccess, onFail, {quality:5,destinationType:1,sourceType:1,allowEdit:false});
                        }
                        else if (index == 1)
                        {
                            navigator.camera.getPicture(onPhotoURISuccess, onFail, {quality:5,destinationType:1,sourceType:0,allowEdit:false});
                        }            
                    }
                };
                function onPhotoURISuccess(imageURI) {

                    var myImage = document.getElementById('myImage');
                    myImage.style.display = 'block';
                    myImage.src = imageURI;
                }
               function onFail(mesage) {
                    alert('Failed because: ' + message);
                }  
                </script>
            </head>
    <body onload="onBodyLoad()">
           <button onclick="showCameraOptions();">Display Photo</button> <br>
           <img height=200 width=200 id="myImage" /> 
    </body>

 
There are a number of things to take note of here:

  1. line 2 – NativeControls.js is included after the phonegap.js file
  2. line 13 – shortened reference to window.plugins.nativeControls is created
  3. lines 15-19 – function showCameraOptions() creates the action sheet and assigns a delegate function for when the user selects an option
  4. lines 19-30 – defined anonymous function to get a photo depending on whether user opts for the camera or the library
  5. lines 31-39 – onSuccess and onFailure functions defined for the camera API

 

Putting It All Together

So there is actually quite a bit going on here and I think it may be helpful to see a diagram that explains how all this actually works. If you haven’t read my post about PhoneGap Project Structure and Internals you may find it helpful for understanding the following interactions in more detail.

The diagram has several areas that I’d like to call your attention to:

  1. nativeControls.showTabBar() – executing a call to a third-party plugin
  2. PhoneGap.exec(…) – executing PhoneGap API to run a command
  3. PhoneGap.runCommand(…) – ultimately changing the document.location on the UIWebView
  4. PhoneGapDelegate – document.location change causes the UIWebViewDelegate (aka the PhoneGapDelegate) to intercept the request
  5. PhoneGapDelegate – request is inspected and forwards to the appropriate PhoneGapCommand
  6. PhoneGapCommand – executes requested operation and then notifies the UIWebView by executing the JavaScript onSuccess or onFailure callbacks

The gist is that every time you execute a PhoneGap API function or a function from a third-party plugin it will ultimately end up changing the document.location of the webView which will be intercepted by the webViewDelegate and then forwarded on to the appropriate PhoneGapCommand class.

Once the command has completed it will typically turn around and execute [webView stringByEvaluatingJavaScriptFromString:jsCallBack]; to call either the provided onSuccess or onFailure js callback functions.

In the example with the ActionSheet and the Camera, we are actually running through the loop between the JavaScript runtime and the Objective-C runtime twice, once for showing the ActionSheet and getting the user response, and once for showing either the camera or the photo library to get a photo.
 

Where to get the Code?

The plugins used are from Jesse MacFayden (aka @purplecabbage on twitter). The original source code for the plugins can be downloaded from github here: https://github.com/purplecabbage/phonegap-plugins.git

If you are using PhoneGap 0.9.6

You can get the entire source for my sample project “HelloPhoneGap” from github here: https://github.com/hutley/HelloPhoneGap

If you are using PhoneGap 1.0

You can get the entire source for my sample project “HelloPhoneGap1.0” from github here: https://github.com/hutley/HelloPhoneGap1.0

That’s all for now – stay tuned for the next post on creating your own PhoneGap plugin.

  1. Andy
    April 4, 2011 at 4:46 AM

    Amazing tutorials! Fantastic that you’ve put this series together so far!
    Having loaded up your HelloPhoneGap project I am noticing that the TabBar is positioned a little higher than native apps. I’ve had this problem in my own projects too. Is this a known issue?

    Cheers once again

  2. kyle
    April 8, 2011 at 8:09 PM

    Hi these are great thank you, is there any chance you could do one in how to record and store audio through phone gap, if possible.

    Thanks again, keep up the good work.

  3. Preet
    May 10, 2011 at 1:02 AM

    Is there any way to display 2 splash screens by giving time duration while loading iPhone app in phonegapdelegate.m. Because my app is quite heavy and takes 12-15 secs to load. Could you please give some code sample.

    • May 11, 2011 at 9:52 PM

      Yes there is – you could put up an activity indicator or an action sheet — both of which are demonstrated in my HelloPhoneGap app BUT the better question is why is your app so slow? Are you loading up heavy JS frameworks? Downloading a lot of data? Could your users be better served by you rethinking your strategy?

  4. Preet
    May 12, 2011 at 5:04 PM

    Hi, Thanks for your reply. My app is heavy because it contains lots of images and and info. I am using Jquery Mobile with Phonegap. I have tried several otions but still it takes long time to load. Could you please explain me how to display 2/3 splash screens with code sample as I am not sure where it has been described, Thansk

  5. Jason
    May 22, 2011 at 5:42 PM

    Why would I be getting
    Result of expression ‘window.plugins’ [undefined] is not an object.
    When I try to use NativeControls in Xcode 4 using Phone Gap 0.9.5 – I’ve copy and pasted your example and it doesn’t seem to like it – putting the .m and .h files in the Plugins folder doesn’t seem to work, I have to put them in Users -> Shared -> PhoneGap ->Frameworks ->PhoneGap.framework->Headers for it to work and not error when compiling, but it doesn’t load the tab bar due to the error above – any ideas?
    Cheers
    J

  6. Pranath Fernando
    June 1, 2011 at 6:10 AM

    Hi Hiedi,
    Thanks very much for you’re post. I’m having some trouble getting native controls to work with the new version of phonegap i’m building 0.9.5.1 (I had native controls working fine with an earlier version of phonegap). I noticed a difference between the way you’re hello phonegap example project is built and the way the default phonegap project is created, e.g. you’re example project includes Phonegaplib as an xcode project *within* you’re hello phone gap project. When you create a default phonegap project with the latest version of phonegap – it does’nt construct it like yours it seems to include phonegap as a framework and with a different structure – its this relevant ? There is a top level plugins directory in this new layout and i have added native controls there but it does not seem to work ! Would appriciate any thoughts – thanks P.

    • June 8, 2011 at 10:44 AM

      Please post your project somewhere and I will take a look.

      • Pranath Fernando
        June 8, 2011 at 12:05 PM

        Hi Hiedi,
        Thanks for getting back – i did actually manage to sort it out. So while the default project structure the latest version of phonegap makes is different to yours (i.e. phonegap lib as a static lib) it does now seem to work out of the box. I think the problem was more with getting nativecontrols and other plugins working with this static lib – so using this as an include seemed to sort it so in the top of say NativeControls.h rather than:

        #import “PhoneGapCommand.h”

        You need:

        #ifdef PHONEGAP_FRAMEWORK
        #import
        #else
        #import “PhoneGapCommand.h”
        #endif

        Which will then deal with either case.

        Also i needed to delete the reference to the .plist file (but leave file) in the new project structure.

        Thanks anyway for you’ve very helpful articles !

  7. Pranath Fernando
    June 8, 2011 at 12:06 PM

    Sorry a typo there ! the correct include code is:

    #ifdef PHONEGAP_FRAMEWORK
    #import
    #else
    #import “PhoneGapCommand.h”
    #endif

  8. Pranath Fernando
    June 8, 2011 at 12:10 PM

    No its not a typo, wordpress is ignoring less/more than brackets ! maybe it thinks they are tags ? ok i’ll have to write in pseudo-code so the include is:

    #ifdef PHONEGAP_FRAMEWORK
    #import (less than bracket) PhoneGap/PhoneGapCommand.h (more than bracket)
    #else
    #import “PhoneGapCommand.h”
    #endif

  9. James Burns
    December 5, 2011 at 11:13 AM

    Hiedi:

    Appreciate your blog.

    I’ve been trying to implement NativeControls in an iOS PhoneGap app, and while it works in portrait orientation, when the device is rotated (in the simulator, simulating a 4.3 device), the toolbar redraws, but the toolBar items (the buttons) disappear. All I see is a black bar.

    Here’s how I’m building and calling NativeControls:

    function onDeviceReady()
    {

    nativeControls = window.plugins.nativeControls;
    nativeControls.createTabBar();

    // settings
    nativeControls.createTabBarItem(
    “settings”,
    “Settings”,
    “/www/settings_settings.png”,
    {“onSelect”: function() {
    showSettings();
    }}
    );

    // email tab
    nativeControls.createTabBarItem(
    “email”,
    “Email”,
    “/www/tabs/email.png”,
    {“onSelect”: function() {
    emailIt();
    }}
    );

    // twitter
    nativeControls.createTabBarItem(
    “twitter”,
    “Twitter”,
    “/www/tabs/tweet.png”,
    {“onSelect”: function() {
    showTweet();
    }}
    );

    // about
    nativeControls.createTabBarItem(
    “about”,
    “About”,
    “/www/tabs/about.png”,
    {“onSelect”: function() {
    showAbout();
    }}
    );

    // Compile the TabBar

    nativeControls.showTabBar();
    nativeControls.showTabBarItems(“settings”, “email”, “twitter”,”about”);
    nativeControls.selectTabBarItem(“settings”);

    //start everything else
    init();

    Do you experience this problem? Do you have a solution?

    Thanks in advance.

    • December 6, 2011 at 10:20 AM

      The black bar you see is actually the space where the tab bar should be but it is actually positioned off the screen when in landscape mode. As of now the tab bar as its implemented does not handle rotation. I don’t have time at the moment to fix it but you could take a crack at it – I’ll fix it at some point when I have time…

  1. No trackbacks yet.

Leave a comment