In my last post I played with the Media API to add sounds effects to the Roll The Ball game and made an Adobe CF Soundboard. Today I'll be showing my work with the Geolocation API. I wish I had some more time to do something more useful, but the CF mobile contest is drawing to a close tonight and I this will be the last feature I have time to put in.
Breaking Up Is Hard To Do
CFClient also allows CFInclude tags, but ONLY with static values-- nothing dynamic. I ended up breaking up my CFClient code into a number of .cfm files in an includes/ directory and just including them all by name. Primitive, but effective I suppose.
include "/includes/notificationAPI.cfm"; include "/includes/accelerometerAPI.cfm"; include "/includes/connectionAPI.cfm"; include "/includes/contactAPI.cfm"; include "/includes/eventAPI.cfm"; include "/includes/mediaAPI.cfm"; include "/includes/rollTheBallGame.cfm"; include "/includes/geolocationAPI.cfm";
Also, after pouring back through the allowed CFClient code, I did find a note that mentioned:
Non-<cfclient> custom tags cannot be called from caller CFMs of <cfclient>. Also, a client-side custom tag cannot have server-side ColdFusion tags outside the <cfclient> tag. This is true for client-side included-CFMs too.
There's still some bugginess there. Try cfincluding an empty file and you'll get a null pointer exception on compilation.
Oh Where Is My Hairbrush
The Geolocation API is pretty straightforward. It comes with a few options out of the box that you can set in the same manner as the accelerometer API.
To enable it, one would normally check the "Geolocation" box under their project's PhoneGap features, but due to compile errors regarding the Media API, I had two switch to a hard-coded config.xml. I added the PhoneGap feature for Geolocation by adding the following line to my config.xml:
<feature name="http://api.phonegap.com/1.0/geolocation" />
Options are set into the options object and passed back in. Note, I made the mistake of copying some code from the docs which didn't have the correct casing "enablehighaccuracy" instead of "enableHighAccuracy" which didn't work at first. These options just pass through to PhoneGap, so I got to the point where I would just skip straight to those docs.
var geoOptions = cfclient.geolocation.getOptions(); geoOptions.enableHighAccuracy = $( '##highaccuracy' ).prop('checked'); cfclient.geolocation.setOptions( geoOptions );
With the Geolocation API, you can do a one-time query of the location, or you can register a callback to be notified anytime the location changes. The data that comes back is easy to use, though I had null values for things like speed and altitude. Perhaps because I was sitting at my desk? If I did much more of this, I think I'd look into a templating solution so I wasn't just concatenating strings of HTML together.
var geoData = cfclient.geolocation.getCurrentPosition(); $( '##geolocationData' ).html( '<b>Lat:</b> ' + geoData.coords.latitude + '<br> <b>Long:</b> ' + geoData.coords.longitude' );
The checkbox enables high accuracy mode which uses your phone's GPS. Otherwise you just get an approximate location based on the mobile network.
It's All In The Syntax
geoOptions.enablehighaccuracy = $( '##highaccuracy' ).is( ':checked' );
An exception has occurred in the processing of CFClient code : Invalid CFML construct found on line 14 at column 75.
Wut?? I was taken aback by the sheer helpfulness of the message, but once the shock wore off, it occurred to me that "is" is a CFML keyword even though I'm in script and I always use the script operators. When in Rome... Luckily, jQuery has another easy syntax that I was able to use.
geoOptions.enablehighaccuracy = $( '##highaccuracy' ).prop('checked');
I also found what I believe to be a bug in the Geolocation API (and yes, I'll be logging this). At first I had actually forgotten to save my config.xml file so the Geolocation API wasn't enabled. Instead of gettinga proper error message, the following message was thrown:
Uncaught ReferenceError: PositionError is not defined
It appears the error handling has its own errors. A quick glance at the code showed it was trying to build an access denied error.
Uncaught ReferenceError: WCamera is not defined
Uncaught ReferenceError: WAudio is not defined
The errors always seemed to reference an API I hadn't added to my app.
This next one was particularly interesting. I've been using PhoneGap's build server to create my builds via CF Builder and so far it's been one of the truly painless parts of the process (other than the inability to automated it). Something happened and I don't know what it is, but I now get the following error message EVERY TIME I try to create a build:
I had gotten this twice before. Once when I tried to actually compile a second project, and once when I changed the name of the app. However, I had done neither of those when it started happening every time. Literally the only way I was able to get the Geolocation code working was to delete my entire project from the PhoneGap build server between every compile and let it recreate itself again. I have no clue what caused this to start happening, but I probably would have played a bit more with Geolocation if it hadn't been for this. It kind of pushed the build process over the edge for me.
I did Google for a while and found that the unique key for an app is the app ID, which is shown on the build server site as well as in the PhoneGap status view in CFBuilder and in some of the messages in the console. However I can't figure out how or where the app ID is assigned. Of course, for normal PhoneGap users there's a config.json file where this gets set. I searched my entire hard drive and turned up no such file. I think this is another good reason for CFBuilder to expose a bit more of the underlying build process to me since it was sort of a blackbox sort of brick wall for me.
The "Finished" Product
I'm pleased with the amount of stuff I was able to play with, though I'm a little disappointed to have run out of time. Of course, not waiting until a couple weeks ago to start would have given me more time :)
There's a bunch more things that honestly are probably a better representation of what CFClient is good for that I haven't even touched.
- Remote proxies for server-side CFCs. I assume this works the same as the CFAjaxproxy stuff, which is one of the only "front end" tags I actually used and found useful in CFML.
- Nice client detection libraries (Part of modernizr.com)
- Client-side Custom tags (might help with my organization issues)
- Client side database queries (quite possibly one of the most compelling uses of CFML since cfquery is so darn nice
- Local Storage
- Camera API (I was kind of scared of this one after the issues I had in the Expense Tracker sample app)
- Compass API
- File API
- Splashscreen API
- Custom PhoneGap plugins (Like Couchbase Lite)
So much to play with, so little time. I'd like to say I'll continue playing CFClient, but to be honest, I've spent over 40 hours in the last two weeks on this project and it's taken quite a chunk out of my billable time. If I win, I'll be compensated for a bit of that, if not I'll have had a fun, expensive experiment :) I will gladly accept any pull requests for sure from anyone who wants to contribute to this community sampler app.
I might post some overview thoughts on CFClient, but for the most part I'll let my readers make their own decisions on whether it looks like something that will help them make mobile apps. I will happily answer questions though. I'll be cutting a new 1.0 release of my code on GitHub to officially submit. As usual, all the Git tags that correspond with each blog entry can be found here:
And the final release that matches the code talked about in this blog can be found here, including a pre-compiled APK file for you to install on your Android device:
Want to read more in this series? Pick one of the links below:
- My First Foray Into CFClient
- My CFClient Proof Of Concept and GapDebug
- CFClient: The Agony & The Ecstasy -- Making It Purty
- CFClient: We Have Contact, Let's Notify!
- CFClient: Tuning Up The Accelerometer Gets Things "Rolling"
- CFClient: Sounding Off And Mozzarella Sticks
- CFClient: What's Your (Geolocation) Vector, Victor?