CounterMarch Systems

use your brain


We used to blog more before twitter came along.

PhoneGap 1.x, Google Analytics, and XCode 4.2

So I was working on a PhoneGap app for the Lehigh/Lafayette Challenge and realized it might be wise to include an analytics package so we'd have something to work from for next year. A quick Google search yielded me this blog post on including Google Analytics in a PhoneGap app.

The problem is, the instructions are outdated...and the package docs on github are also out of date. Commence headdesk. Bang. I don't know the first thing about Xcode or Objective-C, so this was quite an adventure!

Here's what you need to do to use this in an iOS PhoneGap app (jQueryMobile 1.0RC2, PhoneGap 1.1, Xcode 4.2) so that the plugin works with the PhoneGap 1.x plugin architecture. Guaranteed to work as of right this second with these versions. I'm sure it'll break again soon :-)

  • Go get the code from the PurpleCabbage Github site
  • Drop GANTracker.h, GoogleAnalyticsPlugin.h, GoogleAnalyticsPlugin.m, and libGoogleAnalytics.a in the Plugins folder in your Xcode project. Right click on Plugins, Add Files to , select 'em, make sure "Copy items into.." is selected, and click "Add".
  • Modify GoogleAnalyticsPlugin.h to comply with the new plugin architecture
  • /* OLD VERSION - will not work */
    #import <Foundation/Foundation.h>
    #import "PhoneGapCommand.h"
    #import "GANTracker.h"

    @interface GoogleAnalyticsPlugin : PhoneGapCommand<GANTrackerDelegate> {

    }

    /* Replace all of that with this */
    #import <Foundation/Foundation.h>

    #ifdef PHONEGAP_FRAMEWORK
    #import <PhoneGap/PGPlugin.h>
    #import <PhoneGap/NSData+Base64.h>
    #import <PhoneGap/JSON.h>
    #else
    #import "PGPlugin.h"
    #import "NSData+Base64.h"
    #import "JSON.h"
    #endif

    #import "GANTracker.h"

    @interface GoogleAnalyticsPlugin : PGPlugin<GANTrackerDelegate> {

    }

  • Drop the GoogleAnalyticsPlugin.js file in the www folder for your project. I put my stuff in a subdirectory (assets/js) just to keep things neat.
  • Don't forget to include it in index.html with a script tag!
  • <!-- google analytics -->
       <script type="text/javascript" charset="utf-8" src="assets/js/GoogleAnalyticsPlugin.js"></script>
  • Now setup your app startup scripts to initialize the GA code too
  • /* Wait for PhoneGap to connect with the device */
    function onLoad() {
    document.addEventListener("deviceready", onDeviceReady, false);
    }

    /* PhoneGap is ready to be used! */
    function onDeviceReady() {
    window.plugins.googleAnalyticsPlugin.startTrackerWithAccountID("UA-YOUR-GOOGLE-SITE-CODE");
    /* i like to throw a startup event in there just to know how many launches we get */
    window.plugins.googleAnalyticsPlugin.trackPageview("startup");
    /* other startup code here */
    }
  • You'll probably also want to track every jQuery Mobile "page" view too. I just hooked in to the 'pageshow' event. You can track pageviews (which I'm clearly faking here) and "events" (better explained here).
  • $(document).ready(function(){   
       /* track page views */
       $('div').live('pageshow', function(event, ui){
          var pagename = $(this).attr('id');
          window.plugins.googleAnalyticsPlugin.trackPageview(pagename);
          return true;
       });
    });
  • This will save you some hair pulling: the Android PG/GA plugin uses a js method named "trackPageView". The iOS version is named "trackPageview". Yeah...case sensitivity strikes again. Save yourself hours of screaming by watching for that.
  • Now we have to make PhoneGap aware of the plugin. This is the undocumented part.
  • In your /Resources/PROJECTNAME.plist file, open up the Plugins area and add a new item. The name is "googleAnalyticsPlugin" (which is the name of Javascript object). The value is "GoogleAnalyticsPlugin" (which is the name of the Obj-C object). This took a ton of trial and error.
  • Last step: allow the app to reach external hosts. You could list each one individually, but I wildcarded it for this project. Under ExternalHosts in that same PROJECTNAME.plist file, add a line, and set the value to "*". You can see it in the screenshot above.

So from this point forward, you should be able to see pages being logged in Google Analytics from your mobile app. Hope this helps!

PhoneGap, FileTransfer, and ColdFusion

I like PhoneGap. Really. But I bashed my head on this for a while so if this saves you the headache, you're welcome!

The app I am working on uses the Camera API to capture an image and then submits it to a back-end service for inclusion in an online photo gallery. Pretty simple.

When you capture the image, you have two choices for how to handle the data:

Camera.DestinationType.DATA_URL
Camera.DestinationType.FILE_URI

The problem with DATA_URL is that the cameras on mobile devices are getting to be too darn good. That DATA_URL is a Base64 encoded string that can very quickly run you straight out of memory. Therefore, you are strongly encouraged to use FILE_URI instead which is simply a pointer to a file on the device file system.

How do you then get this file moved up to the server? Use the File API's FileTransfer object.

var imageURI = PATH_TO_FILE_AS_GIVEN_BY_CAMERA;

var options = new FileUploadOptions();
options.fileKey="file";
options.fileName=imageURI.substr(imageURI.lastIndexOf('/')+1);
options.mimeType="image/jpeg";
/* ColdFusion barfs if you don't set this */
options.chunkedMode = false;

var params = new Object();
params.formfield1 = 'send other data along for the ride';
   params.formfield2 = 'using more fields like this';

options.params = params;

var ft = new FileTransfer();
ft.upload(imageURI, "http://YOUR_URL_HERE/SOME_FILE.cfm", win, fail, options);
/* don't forget to create functions for win and fail conditions */

The key line here is options.chunkedMode = false;. From what I could tell by reading Ben's blog post , ColdFusion simply can't handle chunked form data. Two hours of searching and evaluating alternatives...and then I noticed this option.

So...lesson learned. Base64 will not only drag your app down but probably crash it as well. FileTransfer (sans chunks) is the way to go.

How I got started with ColdFusion

Steve Bryant had a great idea that the entire ColdFusion community should post about how they got started with ColdFusion on the same day. Count me in!

I started my first job after earning my computer engineering degree as a software test engineer in the summer of 1999. If only I knew how boring that would be! Three months in to that job I went to my boss and asked to be put on a different project - it was that bad!

A couple days later he took me down to the first floor of our building and introduced me to Sam Raimond. Sam was an interesting guy - he had an insatiable curiosity for all new technology. While he wasn't really a programmer, he would mess with just about any new piece of software that came out. In the late 90s, there was an awful lot for him to play with!

Sam was the project manager for the document management system (DDCS) used by a rather large organization up the street from us - NASA. DDCS was a combination of IIS, WebDBC, and Xerox DocuShare running on some ancient Gateway servers - far from sexy, but absolutely mission critical. My boss knew I could build websites, though I hadn't done anything more than HTML and some really basic javascript. Sam didn't seem bothered by that. He handed me the box with ColdFusion 4 server in it, told me he didn't know CFML, and that he was pretty sure nobody else in the company knew it either. My new project: take the four programs that comprised the DDCS system and rewrite them in ColdFusion. Challenge accepted.

The first module took me three months to build. The second, third, and fourth combined took three weeks. Even if we had set out an aggressive rebuild schedule we wouldn't have expected this to come together so quickly. Needless to say, ColdFusion made a lot of people we reported to very, very happy!

I learned how to do this by spending lots of time on the (at the time) Allaire forums and regular attendance at both the DC and Baltimore ColdFusion User Groups. Sam was insistent that we never miss a meeting of either group, even though I was extremely reluctant to go at first. The thing is, once you meet the CF community any reluctance to go as a "newbie" falls away quickly. I remember being immediately put at ease by the friendly people who were there. Some of the stuff people presented was amazing! I'd always come back to work with a whole bunch of ideas and even less time to build them.

One thing I've never forgotten is that it was because of the welcoming, fanatical ColdFusion community *and* the power of the platform that I have been able to enjoy the career that I do. Macromedia recognized the value of the community when they acquired Allaire and Adobe saw it too when they bought Macromedia. No matter the corporate parent the server has seen tremendous improvement from one version to the next with a corresponding jump in the number of things that developers can do easily. I've made a pretty darn good living and a few really great friends thanks to my ColdFusion skills and intend to continue using it as long as the platform keeps evolving (I'll keep the friends regardless).

Interesting footnote: I've known Rob Brooks-Bilson for (omg) 10 years now. Today, thanks to his "How I got started" post, I learned that our first projects were both conversions from WebDBC to ColdFusion. Ironic, indeed.

Philly Merge Conference: July 15th, Philadelphia

Got an entrepreneurial itch? It's almost impossible to avoid if you're in the business of creating things. The creation part is simple (relatively speaking)...but building a business around it? Not quite as straightforward.

Philadelphia is home to a rapidly growing entrepreneurial technology culture. That excites those of us who work in tech in the Philadelphia area, and we want to help it grow by creating a conference for people with a dream to meet people with the means to make that dream a reality – whether that need is for business support or technical development skills.

This conference is called Philly Merge and will be held on Friday July 15 at Jon M. Huntsman Hall at the University of Pennsylvania. By bringing together local developers with entrepreneurs we intend to share success stories, establish a forum for peer education, strengthen the local developer network, start new businesses and have fun while doing so. The entire purpose of the conference can be simply stated as "get started."

We'll have sessions on topics both legal and technical, financial and inspirational -- ending the day with a panel of VC folks who will share with us what they're looking for in both a company and a pitch. We've stocked the speaker list top to bottom with local people who "get" Philadelphia, have done these things themselves, and know what it takes.

It's our belief that you'll finish the day with a feeling of "I can do this" - and you'll have a great idea of what it's going to take to get started. For us, this is a "get started" effort too - we'd appreciate your support, feedback and participation!

So why not sign up today? It's only $29!

Register Today! 


Philly Merge is sponsored by Wharton Computing, Adobe Systems, Future Media Concepts, Chariot Solutions and CounterMarch Systems

Fun with Twilio, Part 2 (The Results!)

Last week I wrote up a summary of a project I threw together that leveraged ColdFusion and Twilio to enable the reunion crowd to vote for their favorite performance.

Well, everything went off without a hitch on Saturday! In fact, I spent an hour on Friday night changing how the system worked to cater to both smartphone and "dumbphone" users. I promised a writeup on how it worked and what the results were, so without further delay...

Promotion

We printed up about 1000 stickers - just plain old Avery mailing labels - with two ways to cast your vote. First was via SMS to the number printed on it. The second way was for those "in the know" who understood what a QR code was.

The parade commentators plugged the voting in the warmup before the parade started, between acts and again at the very end. This definitely helped our cause - there was nothing else to pay attention to during those times, so the exclusivity of the promotion really stood out.

We handed out the stickers to as many spectators as we could along with each of the reunion classes while they were lining up for the parade. After a quick explanation of what was at stake (a new award!), some classes eagerly set to work with their phones. They loved that there was something to do while they were waiting for the parade to start.

This was the extent of the promotion. For an app that came together really quickly, there wasn't time to get word out in advance -- and honestly it wasn't necessary. This was a very "event specific" thing that required no prep on the part of the participants.

How It Worked

There are two ways to cast a vote: SMS or using the QR code. The original idea was to use the QR code to launch your text messaging app with the appropriate class year already entered as the body of the message (we'd print unique stickers for each class). You can't do that on iOS - only Android. We then realized that was dumb - if you were going to text, it's easier to just do that rather than fiddle with a barcode reader. There had to be something nicer for the barcode crowd.

So Friday night around 11:30 I sat down with Dreamweaver CS5.5, jQuery Mobile and ColdFusion to toss together a really quick web-based mobile app. One hour later it was skinned, released and running. One hour!

Results

All told, reunion attendance was around 1000 people. There were unregistered spectators and probably some unregistered guests floating around too. Out of this crowd, we collected more than 1200 votes! Roughly a tenth of them were submitted using the mobile app. The URL was not public, so the QR code would be the only (easy) way in. At a couple cents per SMS, this was good, cheap fun - and nothing went wrong.

Lessons Learned

  • PEOPLE LOVE TO PARTICIPATE! Everybody wanted to know the results before they were announced. They were really amused when I pulled out my phone and showed them the graph of results...up to the second
  • QR codes look really scary to people who don't know what they are
  • QR codes CAN be safely dressed up! I took advantage of an excess of error correction code built in to the QR structure and "Fireworks-ed" in the Lehigh shield. It looked less intimidating.
  • Make sure auto refresh was active for your Twilio account (thankfully mine was...though my heart stopped when I got an email in the middle of the parade from them!)
  • The alumni band will, upon finding out they lost, make plans to hack the vote next year. Bring it.
  • Do not send an acknowledgement for every vote - you'll hit a limit pretty quick.
  • Call-to-vote? Entirely possible with Twilio. Might be fun to add it just for fun!

One key enhancement for next time: Screens at the reviewing stand showing the real time voting totals. With ColdFusion, Blaze DS and Flex this is maybe another hour of work.

The Award!

The result was a decisive win for the class of 1976. Their re-enactment of Rocky was entertaining, colorful and energetic...and they certainly weren't shy about voting for themselves!

For their efforts, they were the inaugural winners of the Stephen C. Rittler '99 Reunion Parade Fan Favorite Award!

Fun with Twilio

With the rush to build full-fledged mobile applications for smartphones, sometimes we forget that there are still a lot of people on...shall we say...dumbphones. So what do you do when you want to interact with as many people as possible? You drop down to the lowest common denominator: voice and SMS.

Lehigh University's annual reunion features a parade of classes through the heart of campus. Every class does a performance for a theoretically impartial panel of judges who take the reaction of the crowd into account during their voting. Awards are given, like the "Best Alumni Band Award" (given to the one and only Marching 97 alumni band) and the Petty Flag (for the overall best performance). This year, we wanted to add more crowd interaction to the mix.

The idea was to bang out a quick "vote via SMS" app so everybody watching the parade could vote (as many times as they like) for the class they thought did best. The powers that be have decided to add an award based on the results too.

Enter Twilio! The best part: it's stupid simple to build this kind of app using their REST API. First thing was to sign up for a number - it's only $1/mo. I then set the "SMS request URL" to a page on my server.

Then on the page I pointed it to, I set up code to handle the text that was being sent in. The entire message is passed in in form scope as the "body" attribute with all the other attributes (sender phone number and their account locale information) sent along too.

<cfif structKeyExists(form, "body")>

   <cfset classYear =    reReplace(form.body, "[^0-9.]", '', 'all') />

   <cfif classYear is not "">
      <!--- add to vote total --->
      <cfset v = entityNew('vote') />
      <cfset v.setVote(classYear) />
      <cfset v.setFrom(form.from) />
      <cfset v.setFromCity(form.fromCity) />
      <cfset v.setFromCountry(form.fromCountry) />
      <cfset v.setFromState(form.fromState) />
      <cfset v.setFromZip(form.fromZip) />
      <cfset v.setTimestamp(now()) />
      <cfset entitySave(v) />
</cfif>
</cfif>

Then, I send an acknowledgement message to the sender:

<cfhttp url="https://api.twilio.com/2010-04-01/Accounts/{REALLY_LONG_ACCOUNT_ID}/SMS/Messages" method="post" username="{YOUR_USERNAME_IDENTIFIER}" password="{YOUR_ENCODED_PASSWORD}">
         <cfhttpparam name="From" type="formfield" value="XXXYYYZZZZ" />
         <cfhttpparam name="To" type="formfield" value="#form.from#" />
         <cfhttpparam name="Body" type="formfield" value="The class of #classYear# thanks you! Feel free to vote as many times as you like." />
      </cfhttp>

That's it! Already they're thinking of other uses for this kind of tool. I'll be sure to post again on Monday with the writeup on how it went.

Presentation: Moving from Verity to Solr

I gave a talk at last night's Philly CFUG meeting on making the migration from Verity to Solr in ColdFusion 9. Adobe has made it known that CF9 is the last release of ColdFusion to contain Verity and that Solr is the way forward.

I'm glad that's the case! Solr is amazingly powerful, fast and extensible. What has been exposed in CF9 barely scratches the surface of what it can do. That's not a bad thing - the Adobe team should be commended for making the transition as simple as possible by using the same tags, attributes and data structures. You'll find (as I did) that the migration is relatively straightforward provided your codebase isn't a real mess. 90% of the effort will go in to adjusting any code that builds formatted search criteria in Verity-specific terms into something that's Solr-compatible. Collection maintenance is left essentially untouched.

If you'd like, you can grab the slide deck and simple examples - with one disclaimer: the code is for example purposes only and should not be held up as an example of ideal coding practices :-). Special thanks to Ray Camden and Scott Stroz for their blog posts on Solr - their work was great background for this talk. Also - thanks to Adam Tuttle and the Philly CFUG for inviting me to speak!

Mobile Apps for Alumni Engagement Presentation

On Tuesday my colleague Chad Davis and I had the wonderful opportunity to present at the CASE District 2 meeting on the topic of "Your Alumni are Moving onto the Mobile Web. Are You? : Mobile Apps for Alumni Engagement." Chad is an Associate Director in the Lehigh Fund at Lehigh University, responsible for the annual giving efforts of Lehigh's 15 youngest classes, a demographic that is increasingly difficult to maintain contact with through traditional means. Embracing mobile technology appears to us to be an ideal means for connecting with this demographic, so there was plenty for us to collaborate on for this talk.

The session description:

In this session we will boldly go where email, Facebook, Twitter, the alumni website and an online community simply can't: directly into the pockets of alumni.

Mobile devices and near-ubiquitous internet access have made immediate information access not only possible but widespread. A well-designed mobile application will open up new opportunities for alumni to connect with both the institution and each other regardless of where they are at the time -- including solutions for special events and targeted micro-campaigns. We'll talk about the strategic use of the "small screen", location-based services and ideas for their use (home and away venues), and tools for building and supporting these applications.

Chad's case study on the Lehigh/Lafayette Challenge was especially well received. That campaign integrated print, email, Facebook, Twitter (a TON of Twitter) and (most interestingly) "text-to-give" functionality. The results were off the charts (over $14k fundraised in a week, a bunch of first-time donors, amazing buzz) that completely contradicts the thesis of the author of this CASE Currents article (login required) that mobile giving isn't a good fit. Lehigh proved it a success through a consistent, well-messaged, and extremely cost-effective effort.

To those of you who were in attendance, we thank you for choosing our session! We were especially happy to introduce some of you to Angry Birds and sorry for the sleep that you're likely to lose in the coming weeks.

Key takeaways from our talk:

Do not just repurpose what you have

You will not get the installation, utilization and feedback that you expect if all you do is pump RSS into a mobile skin. Make it faster and easier for your alumni to interact with the institution and you'll reap dividends for a very long time.

Everything should prompt an action

An engaging application is one that does things. Your app must be functional in order to be useful and as we discussed, only the truly useful apps find a home on the first screen of your moblie phone. If you're not there, you might as well not exist.

"Mobile app in a box" is a lousy shortcut

Several vendors are offering a single "mobile app in a box" solution that is practically useless when held up against an "actionable" standard. I see the attraction - "yes, we're now mobile!" - but the app won't get reuse beyond the intial installation if it doesn't do things that benfit the user. Reading campus news and looking at an event calendar is not substantive engagement - you're wasting your precious resources going down this road.

Segment and target aggressively

A single campus-wide mobile application will contain too much irrelevant content for too many people. Alumni don't care about campus bus schedules (unless they're on campus for reunion), students don't particularly care about regional club activity, faculty don't care about which alumni recently got married and so on. Build niche, targeted, relevant, useful and functional apps and you'll find happy users.

Mobile Web is the way to go

While performance isn't the best, getting something out there that works and can be iterated on quickly is key. Mobile web apps give you that because they can be built using the same skillset that your current web development staff have. Pure native apps bring with them a host of issues including app store approval, the need for completely different development skills for each platform and the cost that inevitably follows. "Near-native" using PhoneGap, Appcelearator, Sencha and others are coming along strong to bridge the gap.

Your campus (and alumni experience) is unique

Every campus is special because the relationship is personal. When I meet with universities to talk about projects, we talk about "emotional resonance" and finding ways to tap in to that to meet institutional objectives. Your mobile presence, whatver it is, should be deeper, more meaninful, more representative of what your institution is all about than just some colors and branding. Do something novel and the alumni will find their way to it. Who doesn't want to be proud of their alma mater for being innovative and inspiring? Seek that out.

Links and our slide deck

Our slide deck (which is fun, but not nearly as fun as the narration that goes along with it): Mobile Apps for Alumni Engagment (pptx) | Mobile Apps for Alumni Engagment (pdf)

Links to mobile/social/mashup services that were mentioned in our talk:

Thank you again to those who attended and to those who subsequently review the content of the presentation. I'll be more than happy to do a webinar for any school who is interested in thinking through the mobile app landscape and visit onsite once my leg is no longer broken!

Chad and I are happy to answer any other questions you have and help you find your way as you begin to evaluate mobile application opportunities.



CASE Mobile: Our first jQuery Mobile + ColdFusion app

Our first mobile application built with jQuery mobile went "live" today at the annual CASE/NAIS conference in Chicago, IL and by early accounts it's a success!

The purpose of the app is to make relevant conference information available to attendees at all CASE events year-round. Conference attendees will particularly enjoy the ability to submit their session evaluations from their mobile devices right away without having to handle the traditional paper forms. Session information is available as is a venue map. Conference organizers can also send out "alerts" that pop up within the app itself, notifying attendees of upcoming sessions, room changes or other important information. The "app" works on all Apple iOS, Android and Blackberry (OS6 preferred) devices and semi-gracefully degrades for use on older devices -- all with no additional development effort thanks to jQuery mobile.




Built on a tried-and-true combination of Adobe ColdFusion, Mach-ii framework, ColdSpring framework and SQL Server for backend data storage, the app is expected to serve tens of thousands of unique users every year. Taking on jQuery Mobile as our front-end framework was not without some risk; it's still in alpha (we used Alpha 2) but the rapid development and cross-device capabilities of the framework far outweighed the immediate concerns. We'll be keeping a close eye on this and upgrade as new releases are made. Testing was done on a Motorola Droid 2, Blackberry Torch, an iPad and an (ancient!) iPhone 3G without issue.

Want to talk about how we might be able to help you implement a cross-platform mobile application? Email Steve at srittler@countermarch.com.

Client Feedback

It's always nice to get a note like this from a client:

Struggling to find the words to describe how absolutely AWESOME this is! You ended up designing something 10x better than I could've imagined.

Thanks, Mura CMS, for making it so easy for me to make my client so happy. I was able to put my time towards meeting their needs instead of implementing a CMS to drive it. This reminds me I'm way behind on blogging about the 5 sites we have up and running on this outstanding open source, ColdFusion-powered CMS.

More Entries

About the blog

7 years of outstanding software development

CounterMarch Systems is a professional consulting firm specializing in Adobe technologies with a special focus on higher education.

2771 Red Oak Circle
Bethlehem, Pennsylvania 18017
610.280.3455
Contact Us