PhoneGap UIControls ready to go

I’ve merged the results of my UIControls branch on github into my master branch. I think my little experiment went well, and I’d love to get feedback from people on how this new API works for you. I still have some great plans for it, but before I get ahead of myself, let me cover what I’ve done:

Changes:
• Refactored the command call API to allow for a richer set of arguments to PhoneGap commands
• Moved some commands around to more appropriate classes (e.g. Alert and Vibrate both moved to Notifications)
• Reorganized the XCode project so commands are clearly separated from PhoneGap infrastructure
• Renamed the Settings.plist PhoneGap config file to PhoneGap.plist, and created a new Settings.plist file that contains custom application-specific configuration.
• Made all PhoneGap commands inherit from a common base-class that auto-loads its own Dictionary of configuration from the main PhoneGap.plist file.
• Added UIControls command class that exposes tab bars and toolbars to JavaScript.
• Updated the demo to show off tabs and toolbars

All that looks like a big change, but almost all of it was infrastructure changes that were necessary to get UIControls to work. Previously, all PhoneGap commands were class method calls, meaning it was very difficult to maintain state between command calls. Now that commands are actually called on an instance of a given command class, it’s easier to maintain state. So when a tab bar is created, multiple calls can be made, each to construct different aspects of the UI. Without all this, the following example would have been much more complicated:

uicontrols.createTabBarItem(“toprated”, “Top Rated”, “tabButton:TopRated”);
uicontrols.createTabBarItem(“recents”, “Recents”, “tabButton:Recents”);
uicontrols.createTabBarItem(“more”, “More”, “tabButton:More”);
uicontrols.showTabBar();
uicontrols.showTabBarItems(“toprated”, “recents”, “history”, “more”);

The changes to the PhoneGap configuration were necessary because now, when a PhoneGapCommand subclass is constructed, it will look in the PhoneGap.plist configuration file to see if there’s anything pertaining to it. So if there’s a key in the dictionary with the same name as the class being constructed, it will use that as a local configuration dictionary influencing just that one class. That way, if you don’t use a feature of PhoneGap, or you have to configure a lot of options for a single type of command, these options won’t be cluttered alongside the standard global PhoneGap settings.

I created Settings.plist because of experiences I had in an application I’ve been creating in order to test my new UIControls branch changes. I found that I wanted to set compile-time options (for instance a “lite_mode” boolean) that influenced the way my app runs, without having to change HTML or JavaScript code every time. So instead what I have is a configuration plist file that is used exclusively in JavaScript for my application. I’ve added the excellent SB-JSON framework in to the PhoneGap project, and use that to pass these settings into the JavaScript application at start-up time. So all you have to do is read Settings.lite_mode, for instance, in order to read properties set in your plist file.

Oh, and finally, I’ve moved the JavaScript documentation to javascript/docs, since they were practically impossible for new users to find in the past. I’ve been working on creating DoxyGen docs of the PhoneGap code for use in XCode’s documentation browser, but I haven’t gotten far enough there to actually check anything in besides comments. I found instructions on how to generate XCode docsets from DoxyGen, but I haven’t gotten it working just yet.

So please, try out my PhoneGap updates and let me know what you think of it. I think the integration of the JSON framework will make things like Contacts much simpler to implement.

Before I go though, I want to give a little “wish list” of features I’m planning on adding in the near future. I’ll get to them whenever I can, since my own app development takes priority of course.

• Toolbar buttons
• Tabbar show/hide animations
• File support (read / write local files)
• Camera and photo library support (POST to a server, save to a local file, etc)
• Native “Flip / Slide” transitions (no more having to mimic them in CSS)
• 3rd party API integration, like AdMob and Medialets (I already have both of these done, but I’m in discussions with both companies to determine if the terms of their license allows me to redistribute it)

Native UI Controls in PhoneGap coming along nicely

They say a picture’s worth a thousand words. Frankly I think inflation has really taken its toll on the cost of words, but nevertheless here’s a quick view of what’s been going on in my UIControls PhoneGap branch on Github.

In that screenshot the UIWebView frame, aka the actual webpage content of the app itself, was automatically resized so the toolbar and tabbar has room to be shown. And yes, those are native widgets for the toolbar and tabbar.

Currently the toolbar doesn’t support showing of any buttons, but the tab bar is fully functional. What it doesn’t support (or at least, it’s not tested at all yet) is using custom images in the tab bar items. But that’ll happen shortly.

Next on my roadmap before this feature can be pulled into the main PhoneGap branch is adding buttons to the toolbar, and animating the tool and tab bars when they’re shown. Currently they just pop into view. I’d like it to be possible for it to slide or fade in instead.

Check back here, or subscribe to my feed, to stay tuned on my additions to PhoneGap.

More changes coming to the iPhone branch of PhoneGap

Last Thursday I went down to Nitobi after work for a couple of beer and a chat about PhoneGap before I had to go give a couple lightning talks at the Vancouver.pm Perl Mongers group. My hour chat with a couple of the Nitobi crew turned into over 2 hours, making me late for Vancouver.pm, but I think the effort was worth it. First off, they have good taste in beer. Second, I had an opportunity to do a little show-and-tell of my PhoneGap branch on Github. Not only did they like my changes, but I told them what my roadmap of features for PhoneGap includes, and I think they’re on board.

So to that end, I’ve started with the changes I said I’d work on. I cleaned up the console / debug logging code I recently developed, to allow for the main meat of what I’m working on: A flexible API for dynamically creating native UI widgets such as toolbars and tabbars. But before I can do that, I wanted to refactor the calling method that PhoneGap uses.

In order to make PhoneGap commands stateful, and to be able to pass a richer set of instructions to those commands, I’m refactoring the call API to look like so:

gap://Class.Method/arrayEl1/arrayEl2/…?dictKey=dictVal&…

The first command to a given class will construct it, passing the reference to our UIWebView to it as a constructor argument. All command classes now inherit from a new class called PhoneGapCommand, which stores the webview as an instance property.

So then the first, and all subsequent commands, are invoked with two parameters:

  1. (NSMutableArray*)arguments
    This is a list of arguments passed on the path component of the URI. They’re URL decoded for you, so any %-encoded characters will be expanded for you.
  2. (NSMutableDictionary*)options
    This gives you a dictionary / hash of the query string component of the URI. This is always passed, but if a command doesn’t supply a query string, the dictionary will be empty.

Calls from within JavaScript will take the first hash (object in JavaScript notation) it sees and will use that as the query string. All other arguments need to be strings / numbers, or else they’ll be dropped. This means you can pass your options hash as the first, or even the last argument in a PhoneGap.exec call.

The bulk of this code is almost done, so I’m excited to hear what people think about this. I’m just getting the existing commands working with this model before pushing back out to Git, at which point I’ll continue on and implement native UI toolbars / tabbars.

Update: I’ve updated my branch on Github with my latest changes. I think they’re great, but there are still some changes that need to be made. I got most of the API working, except for contacts. But since they weren’t working so hot to begin with, and someone else has stepped up to the plate to improve Contacts, I’ll let him merge his updates in to my new code. Next up: native UI controls!

iPhone Certificate Woes

Like many people before me, and I’m sure many more after, I’ve had an ungodly amount of difficulty with Apple’s iPhone certificate provisioning system. I personally think it’s a brilliant solution to a difficult problem, but unfortunately for us they made it a pain in the ass to deal with. I’ve only run up against a few basic issues with them, and thought I’d document my solutions to them here.

And before you say it, yes I know there’s already tons of people complaining about iPhone app certificates, and there’s plenty of pages describing how to fix them on the ‘net to go around. But it was like finding a needle in a haystack for me. There were too many hits on forums and mailing lists that gave bad advice, or weren’t relevant anymore due to updates in XCode and the iTunes Connect website. So I’m summarizing here what works for me, and I’ll leave it up to the reader to figure if it works for you.

Entitlements.plist

These aren’t to be used for Debug builds. This file is necessary for some sort of magic when you deploy an app on the phone for either distribution or release mode. A lot of documentation will explain how you have to create it and add it to your Info.plist file.

This is great, but if you’re trying to figure out why your Debug profile isn’t working anymore, don’t attempt to add the Entitlements file to that build profile. It just makes things come to a screeching halt.

Debug vs Distribution vs Release

This one is annoying, and keeps popping its ugly head up. Say for instance I’ve got my developer certificate that I’ve been using for debug builds. Then I want to test my app on a few phones, so I go about creating a distribution certificate for it. In the project settings pane I change the drop-down to the new certificate, hit build, and *bam* I hit a certificate signing error when it tries to install the app on the phone.

As many people on the ‘net have pointed out, XCode is dumb and doesn’t assign the certificate to the correct profile. Some people manage to play around with it enough to get it to work, usually involving lots of restarts of XCode, removing and re-adding certificates, etc. I find some of that works, but when I get frustrated I just drop to VIM on the console, edit my project.pbxproj file, and change my cert settings manually.

If I’m really in a bind and I can’t get XCode to do what I want, I change my debug certificate to use the one I want for distribution and then drop into VIM. From here I can copy and paste the certificate lines it put in there to represent my distribution cert, and I copy it to my distribution or release build section. Then I change my debug cert back to my developer certificate.

Removing old certs from your system

Sometimes you just need to rebuild a cert. You might have made a mistake, or more often you have another phone you’d like to test your distribution build on. This means going into the iPhone Developer Portal and adding a device to the certificate. This means that the cert will now be different, and you’ll need to download the new provisioning profile.

Ah, but you already have that cert in XCode and, as you might have guessed, XCode isn’t smart enough to replace the old cert with the new one. You’ll just get two certs that will fight it out, and will always lose. So go into the XCode organizer and delete your old certs. You add the new cert, it compiles and signs itself, but when you try to install it on the phone it falls flat on its face.

You can go into the Organizer, select your phone, and remove provisioned apps and provisioning profiles from there. Or you can go onto the phone itself, and go to Settings -> General -> Provisioning, and you can delete your certs manually. Once that’s done, you might want to give XCode a restart for good measure and then add the new certificates from the iTunes Developer Portal.

Wildcard Certificates

I haven’t tried this myself personally, but when I started writing iPhone apps I was under the false impression that a more specific certificate was a good thing, as opposed to using wildcard certificates. But I’ve seen tons of references on the web of people recommending using them, and “You’re just asking for trouble if you create different certs for each of your apps”.

All I can say is…Whoops! I already released two apps to the appstore, and I don’t think I can change my certificates after the fact. Plus, I’m not sure if suddenly switching to wildcard certs for the rest of my apps will be a bad thing. Either way I’ll be doing this for my next app. If I only have 2 apps that will give me certificate pain when I maintain them, then so be it.

PhoneGap and JavaScript

I’ve been working on some pretty fun changes to PhoneGap recently, which hopefully will be merged into the main branch soon. (Brock? Any word on that? It’s now 12 days, and counting) In my branch of PhoneGap I added console logging support, I implemented queueing of commands so they don’t walk over each other, and finally (and perhaps more importantly) improved the JavaScript build system and infrastructure.

PhoneGap’s JavaScript Structure

PhoneGap is broken up into several different .js files, each of which implements a part of the PhoneGap API. And with recent changes to PhoneGap’s Objective-C code, the implementations of those commands are divided nicely into their own separate classes. Additionally, there’s platform-specific implementation hooks of those APIs which make the necessary calls in to the native code that implements those commands. At build time, a Rakefile is used to compile these together into one single “phonegap.js” file that can be included into your application.

But in the main branch currently there’s a number of bugs that prevents this system from working. The JavaScript files were being loaded in a bad order, causing prototype methods to be overwritten instead of extended.

I’ve hacked something together to improve on this, but this is really just a stop-gap measure. Really what should happen is an actual JavaScript framework should be adopted to help with class loading, extending classes, and implementing interfaces.

JavaScript Frameworks FTW

I’m a big fan of MooTools, so most of my day-to-day web work is in that framework. But really, most libraries solve the basic problem of “Here’s a base class, I want to either add to it, or subclass it to add more behaviour”. You never know how much you rely on something like that until you have to do without.

I found myself in the uncomfortable position of having to implement prototype-based inheritance by hand, and not in the fun way. This brings me to the main reason for this post, besides the subtle prod to Brock.

I want to see a client-side library that works well for light-weight apps, but still provides capabilities to extend classes, find elements using CSS selectors, provide helper functions for performing CSS-based animations, and provide event binding and closure-wrapping support.

I started toying with JQTouch, and while it’s certainly intriguing, it doesn’t solve some things just yet.

  1. It’s still based on the stock jQuery, which is still pretty large, weighing in at 56KB
  2. jQuery’s event object doesn’t support any of the iPhone’s touch and rotate/scale event properties. You can get at it by saying “event.context.”, but at that point why bother? The native event object is just fine.
  3. It doesn’t address some basic issues I have such as function binding

So far I’ve managed to resolve my above issues with PhoneGap’s JavaScript API for the time being, but long term I think there’s some definite needs for the iPhone platform in general. We need to lose the platform-independant thinking of the standard frameworks (“Am I in IE? Am I in Opera?” needs to go). We need to have something that improves upon the already excellent CSS-based animation support of WebKit, and provide more abstract behaviours. And finally, we need to provide capabilities that let us define class-based applications with rich event and callback binding support.

The reason we’re developing applications under PhoneGap is because we want to build apps faster than we could if we developed in native Objective-C. So we need to have a JavaScript library that doesn’t get in our way, and actively solves the problems with JavaScript that WebKit doesn’t already solve.