So, in my first entry I discussed that I'm trying my hand at CFClient, mostly drawn to the idea of winning a $1000 gift card from Adobe.  Previously I followed Ram's YouTube videos and articles on setting up a Mobile project in ColdFusion Builder, installing his sample app, compiling that app via Adobe's cloud-based PhoneGap server, and installing it.

This venture was met with mixed success.  The PhoneGap shell app which allows one to test without needing to recompile after EVERY code change fell flat out of the gate for me.  I'm still waiting to hear back from Adobe on that.  I was able to compile and run the sample app, but couldn't get the file APIs to work.  I've sort of given up on that for now-- there's just not enough time to keep banging my head on that wall for the time being.

Weinre --> GapDebug

Using the Weinre server in ColdFusion was actually pretty easy. You just enable and start it in the administrator.  Then you  add ?inspect to your URLS in the PhoneGap shell, or create an "inspect build" when you compile.  This is basically like Chrome's debugging tools, just remotely for the page as it's running on the phone.  

Ray Camden told me in a Twitter conversation that Weinre was yesterday's stale bread and GapDebug is the new hotness.  Not being one to second-guess Ray Camden, I installed GapDebug but two things initially prevented me from using it:

  1. It's internal debugger runs on port 8080, which I also use for Railo.  This is easily changed under "Settings" > "Debugger" > "Network Settings".  Switch from System assigned port to User assigned port.  It typed in 8085 since I knew that port would be free on my system.
  2. GapDebug requires Android 4.4 or higher.  I had rooted my phone last year while out of the country to a modem that would unlock other SIM cards.  As such, my Sprint OTA updates were behind.  After download and reflashing the 1.4 GB stock ROM I was able to update to 4.4.2 and was till in business.  Note, even when I was on Android 4.3, GapDebug was still able to install APKs for me which was really nice.

Using GapDebug is pretty freaking simple.  I just open the debugger window from the icon in the system tray, plug in my phone and it shows up in the list.  At this point, I can click the little "down arrow" icon to install an APK directly on the device.  This works even if the app is currently running-- it just closes it.

I've mostly been using the Console part of GapDebug, which gives more information than Weinre did.  The biggie is JS line numbers and stacks.  Also, complex objects such as errors are displayed in a browsable manner instead of just "Object Object".

One thing I'm not totally sure about is if I need to create "debug" or "inspect" builds in CF Builder.  It appears that normal PhoneGap builds can be debugged via GapDebug, but I could easily be missing something.  The instructions also talk about some debugging bits I'm supposed to add to my PhoneGap's config.xml file, but since that's all abstracted away I'm not even quite sure how to view it, and Builder may just be adding it in there for me.  Please chime in if you know the answers to any of that.  For now, I'm just going to keep using it and pushing forward :)

My Entry

So I honestly had a hard time figuring out what the heck to create for my mobile app entry.  I couldn't think of anything very useful or "cool" that wouldn't take a l

ong

 time to write.  Of course, I wanted to try and use at least one or more of the client APIs-- since that was kind of the whole point.  With few examples of CFClient on the Internet, I really just wanted to play with each client API.  

So, with that in mind, I've set out to create a "CFClient Sampler" that will simply demo as many of the client APIs that I have time to implement (and can get working) before the deadline.  This seems like a win-win-win.  

  1. I get to play with all the APIs
  2. My blog entries and GitHub-hosted code will help the community in their future CFClient usage
  3. I'll win $1000

Ok, so I'm not sure about that last one.  Let just call it a "win-win-hopefully-maybe-win" for now :)  I'm currently accepting ideas for an icon-- I'm thinking something with boneless wings and cheese sticks :)

Getting Started

So, using a really stripped down version of the Expense Tracker app, I got a proof of concept going.  I figured the Connection API would be a good place to start.  It only has 3 possible calls:

  1. cfclient.connection.getType()
  2. cfclient.connection.onOffline()
  3. cfclient.connection.onOnline()

The docs are found here:

https://wikidocs.adobe.com/wiki/display/coldfusionen/Connection+Functions

And the Adobe-provided examples are found here:

https://wikidocs.adobe.com/wiki/display/coldfusionen/Using+the+Connection+APIs

So, first things first-- you have to add "connection" as a "feature" to your app first or it won't work.  Two things about this:

  1. There is a nice UI in CFBuilder which basically just dynamically generates the config.xml file, but why can't CFBuilder just do this for me?  When it compiles the app, can't it just look and see if I'm using the "connection" API, and if so just add it?
  2. If you forget to add this feature, the error you get will make no sense.  The "cfclient.connection" object will exist, but it will have no getTypes() method on it.  Enabling the connection feature will make the method magically appear.  It took me a few minutes to figure that one out.

Right click on your project, and choose "properties".  Then under "ColdFusion Mobile Project", choose the "PhoneGap" tab and click "New...".

Choose "Feature" on the left.  Then check the "Connection" box and hit "OK" twice.

For my app, I just included jQuery and jQuery Mobile and a super simple body:

<h1>CFClient Sampler</h1>
<h3 id="connectionOnlineStatus"></h3>
Your internet connection is: <span style="font-weight: bold;" id="connectionType"></span>
<button id="btnRefreshConnection">Manual Refresh</button>

 

In Ram's example, he had an app.js file that just bound all the UI elements to "CFClient functions" in his CFM file.  Honestly, I'm not sure I see the point in that since everything inside your CFClient tags essentially IS JavaScript.  It will compile to JS, it will have access to JS objects, it IS JS.  Ignore the fact, that you can use some CFML syntax in there.  I went ahead and just bound by DOM elements in my CFClient block.  

For now, I'm not even using an include-- it's all just the in the index.cfm.  I wanted to get it working first, and then see about how to abstract it back out later.  The code outputs your current connection type-- none, wifi, 3g, 4g, etc.  There are also two listeners-- one that fires any time your device goes offline and one that fires when it comes back online.  Notes:

  • The docs say getType() returns a number.  Wrong, it returns a string such as "3g", "4g", "none".  Perhaps this changed at some time. Use the "pseudo constants" cfclient.connection.UNKNOWN, cfclient.connection.ETHERNET, cfclient.connection.WIFI etc to avoid hard-coding.
    Note, the docs are wrong there. The constant names are Connection.UNKNOWN, Connection.ETHERNET, Connection.WIFI, etc
  • My device sometimes goes offline for a second when switching off of wifi
  • My device will go online several times in a row without ever going off when switching naturally between 3G, 4G, and Wifi.  I'm sure that's working as designed, just something to keep in mind.
  • The refresh button, in theory, is unnecessary since the callbacks should always keep the UI up to date.
  • The try/catch is because errors seem unintelligible if I let them go uncaught.  Logging the error object seems to be a much better way to debug them.
<cfclient>
	<cfscript>
		try {
			// When user clicks the manual refresh button
			$(document).on("click","##btnRefreshConnection", function(){
				loadConnectionDetails();				
			});
			
			// Display the connection type
			function loadConnectionDetails() {
				$("##connectionType").text( cfclient.connection.getType() );				
			}
			
			// I'm fired every time the device goes offline
			function onConnectionOffline() {
				loadConnectionDetails();
				$("##connectionOnlineStatus").text( 'Offline' );
				$("##connectionOnlineStatus").css("color","red");
			}
			
			// I'm fired every time the device goes online
			function onConnectionOnline() {
				loadConnectionDetails();
				$("##connectionOnlineStatus").text( 'Online' );
				$("##connectionOnlineStatus").css("color","green");
			}
			
			// Bind the functions to call when the devices connection state changes.
			cfclient.connection.onOffline( 'onConnectionOffline' );
			cfclient.connection.onOnline( 'onConnectionOnline' );
			
			
			
		} catch( any e ) {
			console.log( e );
		}
	  	
	</cfscript>
</cfclient>

Here's some screenshots of my simple, yet effective CFClient Sampler app so far.  

That's it for today.  My code is on GitHub and I will be creating a tag and release for each blog post.  View this tag (0.1) here:

https://github.com/bdw429s/CFClient-Sampler/tree/0.1

You can also download the APK file and try it out on your Android phone here:

https://github.com/bdw429s/CFClient-Sampler/releases

And as always, my code comes with no warranties and will probably publish all your inappropriate photos to a public instagram account.


Want to read more in this series?  Pick one of the links below: