Underwhelming Android Experience

Ryan Heise summed it up nicely in Four Months With Android. I used an HTC incredible for 11 months. There are some great things about Android, but the negatives far outweigh the benefits for me. Android was just underwhelming. The UI and UX isn’t as nicely polished as iOS. Android apps, on average, just aren’t as well polished. Android reminds me of Windows of years past. Sure, it more or less works, but it’s just not that great of an experience.

Tagged ,

Will Hybrid Mobile Apps Prevail Over Native?

I’ve been wrestling with this question for some time, and I thought this post may help sort out my thoughts and opinions while giving you some important insight. Are hybrid mobile apps going to become the developer’s choice anytime soon? The debate can be pretty heated as companies choose one technology over the other.

Hybrid, the Unlikely Union

Let’s get the definitions straight before we begin. A hybrid app is one of those mobile apps that uses a native web view to display HTML, CSS, and JS “web” apps. They’re only sort-of “web apps” because they are run locally, though they often pull data from online sources via AJAX requests. So, you have this HTML/CSS/JS app running inside of a natively-compiled stand-alone web browser of sorts on your phone. One such example is PhoneGap. Because the logic bits of the app are written using web technologies, you can often develop once and deploy on multiple platforms, so long as you’re using supported markup. You’re killing multiple birds with one stone.

Hybrid is the Bee’s Knees

As I mentioned above, hybrid technologies are great for developing cross-platform apps. Seriously – since iOS, Android, and even some Blackberry devices are both running Webkit most, if not all, your html, css, js is going to work remarkably similarly on both platforms. It’s pretty enticing. From your and your client’s perspective it’s a pretty easy sell. For one round of development you have the potential to hit many more users. It’s pretty cost-effective. Pretty soon you’re singing the praises of your decision and you’ve decided that from now on hybrid apps are the bee’s knees.
Continue reading

Tagged , , ,

GeoLocation Near You

We at Pivotal Action were recently given a task for a client – develop a tool for a mobile API where admin can upload a list of retailers so that their mobile app users could find locations near them. It’s basically a “Find near me” utility.

This type of project is broken down into 3 parts: Upload & store geolocation data, find addresses near a given point, and display those locations either textually or on a map display. This quick tutorial will cover the first two parts.

Part 1, Getting Located

The goal of this part is to obtain and store latitude/longitude pairs for given addresses. I’m going to assume you can already get a list of addresses, whether for a spreadsheet/csv file, or other source. With a parsed address, you can obtain the lat/lng pairs from the Google Maps API. Just be forewarned that Google limits you to 2,500 requests per 24h period. That could be a problem for some applications, so you may need another provider like SimpleGeo.com

<?php
// Google maps API. rate limit to 2,500 reqs/24h
$url 		= 'http://maps.googleapis.com/maps/api/geocode/json';
$address	= urlencode($row['address']);
$city		= urlencode($row['city']);
$state		= urlencode($row['state']);
$zip 		=  $row['zip'];

$requestUrl = $url."?address=".($address.",".$city.",".$state.",".$zip). "&sensor=false";
// echo $requestUrl;

$crl = curl_init();
curl_setopt($crl, CURLOPT_HEADER, 0);
curl_setopt($crl, CURLOPT_RETURNTRANSFER, 1); 

// Set up the CURL request
curl_setopt($crl, CURLOPT_URL, $requestUrl); 

// Here we get the google result in JSON
$googJson = curl_exec($crl);

curl_close($crl);

$googArr = json_decode($googJson);
$status = $googArr->status;
$loc = $googArr->results[0]->geometry->location;
if( strtolower($status) == "ok" ){
	$tableData[count($tableData) - 1]['lat'] = $loc->lat;
	$tableData[count($tableData) - 1]['lng'] = $loc->lng;
} else {
	$tableData[count($tableData) - 1]['lat'] = 0.0;
	$tableData[count($tableData) - 1]['lng'] = 0.0;
}

//go on to save $tableData to your DB

?>

There are a couple key parts in there. First, you need to URL encode the address details. Second, the curl stuff is pretty standard – you can find similar versions all over the net. Third, the response data comes back as a JSON string, so you need to decode it into a PHP array to make it useful. My default value for lat/lng pairs is 0.0/0.0. There may be cases where Google doesn’t understand the address information or perhaps you’ve gone over your rate limit, so you have to accept more or less a throw-away response. The important thing is that you have your address coordinates saved (dare I say, cached) in your DB. You need this.

Part 2, Finding Yourself

Now how are you supposed to find these stores that are near you, at this moment, without having to use a lame web form or other manual means? You’re going to use the Haversine, aka Great Circle  Formula. Don’t click that link unless you really want to be confused. Here’s the gist – the globe is a big sphere, and we know from high school and/or college trigonometry classes that you can figure out lengths and distances on geometric objects. Some guy long ago (whose name was not Haversine) sat down and figured this out for us. What we get as a result of running these maths is the distance between to points on earth, using lat/long pairs. The caveat is these are as the crow flies, not driving directions. What I’m going to show you below is some SQL you can use to find the N closest points within a given distance. This will work on MySQL, and I’m assuming other SQL-compliant DBs. YMMV.

// scale:  MILES - use 3959 ;  KM - use 6371 (mean radius of the earth)
$scale = 3959;
$sql = "SELECT name, address, city, state, zip,  ( "
. (int) $scale ." * acos( cos( radians(".(float) $loc['lat']
. ") ) * cos( radians( lat ) ) * cos( radians( lng ) - radians("
. (float) $loc['lng'].") ) + sin( radians(". (float) $loc['lat']
. ") ) * sin( radians( lat ) ) ) ) AS distance FROM "
. $tablename ." HAVING distance < ". (int) $distance 
. " ORDER BY distance LIMIT 0 , ". (int) $limit . ";";

(Thank Pavel Chuchuva on Stack Overflow for the SQL [answer here]). You only need a couple parameters to get this chugging along and giving you a list of distances, closest to farthest from the point you are feeding it. Along with your address information, you’re also provided a distance in miles (using 3959 for measurement in Km).

Now you can use these results to display distances to your users. Let Google be your guide for implementing Part 3.

Tagged , , ,

Quiet NSLog() in Release Builds

On the heels of the previous post, here’s a little snippit I picked up from Marek Bell to quiet NSLog() output in release builds.

Add this to your {MyApp}-prefix.pch file

#ifndef __OPTIMIZE__
#    define NSLog(…) NSLog(__VA_ARGS__)
#else
#    define NSLog(…) {}
#endif

The reasoning behind using __OPTIMIZE__ is that it’s set only on release builds of your app, not in debug versions. It’s very simple and allows you to use NSLog() instead of having to come up with your own version.

Tagged , ,

Quiet the Console – PhoneGap / iOS

I have a confession – I’m a console logging junkie. I just like to see what’s going on. While that may be great for development, at some point you’ll have to quiet the logging down for production. Really – doing enough logging will slow everything down each time you’ve inserted a console.log() into your code.

Silencing the output to XCode’s debugging console wasn’t immediately obvious. Overriding console.log() in JS by setting it to an empty function worked in the browser for development, but as soon as I loaded the app onto the actual simulator, we were back to square one. Enter the PhoneGap DebugConsole prototype. Override it.

Insert this anywhere after your phonegap.js file loads. It’ll keep things quiet as long as DEBUG = true…

if(DEBUG == true){
    DebugConsole.prototype.log = function(message, maxDepth) { }
    DebugConsole.prototype.warn = function(message, maxDepth) { }
    window.console = new DebugConsole();
}

There you have it

Tagged , , ,

PhoneGap + XCode4

There’s been a bit of confusion surrounding changes to XCode4 and PhoneGap. Right now the big ones are 1) Where did my PhoneGap user templates go!? and 2) How do I submit my PhoneGap-based app to Apple? Let me help you.

1) You want to create a new PG project, but you’re not seeing the XCode templates when you go through the new project menus. Check out Shazron’s blog @ Nitobi for a command-line script to get you a new project up and running. It’s not as sexy as the XCode template, but it will do.

2) You can’t compile your app for submission to Apple? That was a little more tricky to track down. See this thread on the Apple Dev Forums for a bit of an abstract view of what’s going on. I’ll save you the details. Follow these steps to XCode bliss.

  1. Select the PhoneGapLib.xcodeproj entry in your files list:
  2. Make sure the “All” tab is selected:
  3. Look for the “Deployment” section and scroll down until you see the “Skip Install” parameter. Set Skip Install to YES:
  4. EDIT: Make sure to verify your target device…
    Make sure you have the “iOS Device” option selected in the schemes drop-down:
  5. Go over to the “Product > Archive” menu. XCode will do its compile magic. Open the Organizer to see the app and the listed archives when the compile is complete. At this point, make sure you are ready to upload the app to iTunes Connect. Bonus: we get to skip the Application Loader app from now on!
  6. Select the archive and click the “Submit” button. XCode will ask for your credentials. Log in and select the appropriate app and distribution profile from the list. Submit. If all goes to plan, you’ll get a message of approval. Finished.

That was easy. Now you can navigate the XCode4 waters with PhoneGap.

Tagged , , ,

Catching Android’s Back Button in PhoneGap

This little bit of code is going to be useful to those of you developing a “singe page” app inside of PhoneGap. This applies to Sencha Touch (big fan), but doesn’t as much to jQuery mobile and jQTouch, as it’s a multi-page/navigation based event framework (it uses the app’s url string to do things like move around to different link anchors). This is really important on these single page apps because the Android hardware back button will send the PhoneGap app to the background. You need some way to intercept it so you can start building your own history management mechanism. Sounds fun, right? It’s actually not that hard.

On app initialization, add an event listener for Android’s back button, and the callback to handle it. PhoneGap takes care of the interface between Android and your app.

document.addEventListener("backbutton", backKeyDown, true); 
function backKeyDown() { 
     // Call my back key code here.
 	alert('go back!');
}

That’s enough to get you started, and it should be pretty apparent if it works or not.

How about history management? It will depend on the app and what makes sense, BUT you’ll probably want to create a history array, and pop off some value that directs the app each time you hit the hardware back button. Here’s another idea: change the destination of the back button depending on the view. I personally like the idea of the latter because apps built on Sencha Touch are going to have easy tie-ins through predefined listeners JS Objects that define screen elements like buttons.

Tagged ,

Mobile Platform Detection on the web

I had a use case recently where I need to determine whether the client browser was a desktop/laptop/etc or a mobile device that supports tap events in JS. This will be useful to people who are dynamically binding different events to elements.

var tmpElem = document.createElement('div');
tmpElem.setAttribute('tap', 'return;');
clickEvent = (typeof tmpElem.tap == "undefined") ? 'click' : 'tap' ;

You would use it like this

$('.showDetails').bind(clickEvent,function(e){
      display(e, $(this).attr('info'));
      console.log( clickEvent + " " + $(this).attr('info'));
      //would look like "Click fooBar"
 });

Tell your Mac to say “Anything” (and record it)

I don’t quite have the voice acting skills that people care to listen to on a pre-recorded message, so I was faced with a challenge when I decided I wanted one for our hosted virtual phone system over at PhoneBooth. I had a vague recollection that Apple provided recordable speech synthesis / text-to-speech (TTS) capabilities in the command line, so I went searching. Bingo. The app is called say.

This tutorial will show you how to use a Mac’s TTS capabilities to record text to an audio file, and then convert it to an MP3 for use with PhoneBooth, or any other application you might want to use.

Try this out from the command line (open Applications > Utilities > Terminal )

say "Hello world."

To save it to a file:

say "Hello world." -o greetings.aiff

Or to read the text from a file,

say -f script.txt -o greetings.aiff

PhoneBooth requires either wave or mp3 for its auto attendant scripts (e.g., “Press 1 for sales, 2 for billing,” etc.). Some voices support exports to wave (see the say documentation: man say), but the default in 10.6 doesn’t seem to – it creates an audio file, but produces no sound. The next step involves using lame to convert the file to a mono mp3. You will need to install lame using Fink or Mac Ports first. If you don’t have lame installed you can also use iTunes to do the conversion for you, but your tutorial more or less stops here without lame.

lame -m m greetings.aiff greetings.mp3

Finally, upload greetings.mp3 to PhoneBooth. Finished. For the curious, the -m m option tells lame to encode the mp3 to mono.

For the super-efficient folks out there, put it all into one line (and open when finished):

say -f script.txt -o greetings.aiff; lame -m m greetings.aiff greeting.mp3; open greetings.mp3

NB: If you wish to make your spoken text flow more naturally you can add [[slnc 300]] between sentences, increasing or decreasing the number for longer or shorter pauses. Apple has much more detailed documentation for the brave.

Tagged ,

If your site goes down, does it make a noise?

I don’t go to my brochure site very often. It’s there for the curious client who needs the reassurance that I know what I’m doing. Considering I haven’t made any significant changes in quite some time, I had no reason to go back, but apparently I should have. At some point my .htaccess file went missing, which was pretty good to foil even the best attempts to view pages other than the home page. I have two questions: 1) How long were all these links broken – that I didn’t even notice it, and 2) Nobody said anything – why?

Regardless, everything is fixed now. Typing my name into Google or Bing will fetch either this blog or the brochure site in the top 2-3 positions. If you haven’t been yet, check out mistercameron.com .

Cue deriding comments.

Follow

Get every new post delivered to your Inbox.