Changing the Navigation Bar: MFMailComposeViewController

Changing the Navigation Bar: MFMailComposeViewController

The iPhone 3.0 SDK introduced a number of cool new controllers, one of which was the MFMailComposeViewController class.

And although – in and of itself – it does so much, like much of what we run into in this developer life, it leaves some things greatly to be desired.

Like, “why in the heck does it ** have ** to put the subject line in the navigation bar as a title? Don’t they ** know ** I have a cool custom nav bar that they’re totally puking over?!?!?!

Don’t fret. There is a solution.

First, you’ll need to implement the following delegate in the .h file of the controller where you are implementing the mail composer:

MFMailComposeViewControllerDelegate

Next, you’ll need to implement some sort of event handler. Here’s mine:

-(IBAction)doEmail:(id)id {
if ([MFMailComposeViewController canSendMail]) {

  MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];

  controller.mailComposeDelegate = self;
  [controller setSubject:@"My Subject"];
  [controller setMessageBody:@"My Body" isHTML:YES];

  [self presentModalViewController:controller animated:YES];

  [[controller navigationBar] setTintColor:[UIColor greenColor]];
  UIImage *image = [UIImage imageNamed: @"custom_nav_background.png"];
  UIImageView * iv = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,320,42)];
  iv.image = image;
  iv.contentMode = UIViewContentModeCenter;
  [[[controller viewControllers] lastObject] navigationItem].titleView = iv;
  [[controller navigationBar] sendSubviewToBack:iv];
  [iv release];
 
  [controller release];
  }
else {
  UIAlertView* myAlert = [[UIAlertView alloc] initWithTitle:@"My App" message:[NSString stringWithFormat:@"You cannot send email at this time."] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
  [myAlert show];
  [myAlert release];
  }
}

Finally, you’ll need to implement a method to dismiss the email composer after you cancel or send.

// Dismiss email composer UI on cancel / send
- (void)mailComposeController:(MFMailComposeViewController*)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError*)error {
  [self becomeFirstResponder];
  [self dismissModalViewControllerAnimated:YES];
}

The bits that take care of the custom navigation bar (and incidentally, hiding the subject line title Apple insists on fobbing off on you) are in bold in the code above.

There are a few interesting details to note:

  [[controller navigationBar] setTintColor:[UIColor greenColor]];

Will tint the Cancel and Send buttons to whatever color you like; in this example, I chose green. Use whatever you like here.

  UIImage *image = [UIImage imageNamed: @"custom_nav_background.png"];
  UIImageView * iv = [[UIImageView alloc] initWithFrame:CGRectMake(0,0,320,42)];
  iv.image = image;
  iv.contentMode = UIViewContentModeCenter;
  [[[controller viewControllers] lastObject] navigationItem].titleView = iv;
  [[controller navigationBar] sendSubviewToBack:iv];
  [iv release];

The code above loads an navigation bar image (320 x 42 pixels for iPhone 2G, 3G, and 3Gs; 640 x 84 pixels for retina display), and sets the titleView on the MFMailComposerViewController navigation bar to the UIImageView I constructed with my custom navigation bar background.

And last but definitely not least, we must send the custom titleView to the back so that we can “see” the Cancel and Send buttons.

The subject line will now no longer appear in the title bar – which is why I did this in the first place. It was totally jamming my chi.

Give it a try. I’d be interested in your feedback on this solution.

When Your Baby Is The Ugly One

When Your Baby Is The Ugly One

This scenario plays itself out repeatedly:

Company A releases a great new mobile app. Initially, it runs on only mobile OS X.

Users of mobile OS Y decry how epic this FAIL is on the part of Company A, how clueless they are, and how they are totally missing the boat and losing their business.

Wash. Rinse. Repeat.

Trust me – companies don’t go out of their way to NOT service their customers and consumers.

These decisions are based upon market share, money on hand, time to market, and availability of manpower to build product.

In short, it’s business.

For the most part, this script usually translates as: Company A releases an iPhone app, initially. Users of Android, Blackberry, Palm, etc. are unhappy that they are being slighted. They think the company doesn’t value them.

In fact, the company is probably coping with a small set of developers, looking to get the biggest initial bang for their constrained development resources, and has every intention of getting their product on these other platforms, as time, resources, and money permit.

Apple’s ability to allow consumers to discover new applications is superior to what Android and Blackberry offer. I’m sorry. It just is. You can’t browse the Android Market or the Blackberry App World from your laptop to discover apps. You can with the App Store. Therefore, the chances for new consumers to discover, disseminate, and advertise your new app are greatly multiplied by releasing an iOS version, first.

Again, this is a business decision, not a straight-up fan boy love affair.

Yeah – it totally blows to have to wait for something the other cool kids are playing with now (hear that Twitter? Still waiting on “new” Twitter. Le sigh).

This is how I, as a cross platform developer, look at these platforms when trying to design and develop a new commercial product. I’m keeping “religion” (i.e., the relative merits of open source vs. closed source) out of this discussion in the main, aside from mentioning availability of sample code:

Apple:

Pros: Has maximum reach, best application discovery, best user experience with regard to UI and overall integration, highest quality store; customers spend actual money here. Best UI design tool of any of the mobile smartphone environments (Interface Builder) . Easiest to system test code, because you only have 3 basic iPhone models.

Cons: Strict curation can be an impediment to delivery. Wait times for approval have gotten better, but definitely adds friction to the process.

Android:

Pros: Easiest to ship, fastest growing smartphone OS. Lots of open source examples. No curation to get your app in the market, which means revisions and bug fixes happen in “internet time.” The ability to customize AVMs for creating device simulator configurations is the most flexible across all OS SDKs.

Cons: Horrible UI design tool. No application discovery, aside from third party websites. No curation in Android Market means anything goes. System testing is a nightmare, because you have a cross product of dozens of combinations of hardware and OSes that realistically won’t be fully exercised by small developers. The user experience across carriers is inconsistent – anyone who have ever implemented an application on Android that has to use the camera can attest to the variability in operation, quality, and performance. Fragmentation really doesn’t capture how fast this is getting worse rather than better (see: Verizon and Amazon creating their own market, see: carriers installing root kits to frustrate rooting, see: application filtering by carrier).

Blackberry:

Pros: Huge installed base of devices. Market leader in penetration inside of enterprises. Secure. Dozens of software simulators available for testing.

Cons: Worst SDK of any smartphone OS. SDK runs only on Windows (technology release now available for Mac OS X, but no simulators and it works only for directly attached OS 6 devices, which is one: the 9800 Torch). No UI tools, periodWorst developer community of any smartphone OS (no disrespect to the many fine BB developers I have met the past couple of years. But in the main, most of these guys – and they are guys – are usually company drones that I for the life of me can’t seem to find any actual apps that they have written. Prolly cause there’s only 9,000 apps in Blackberry App World, and unless you have a Blackberry Phone with a data plan, you’d never see ’em anyway). Multiple OSes, hardware form factors make unit and system testing impractical for rapid releases. Browser – with the exception of the latest OS 6 release – is the absolute worst of any smartphone. Research in Motion also doesn’t seem to really care about software, except for only the sense that it is needed to operate the hardware. They’re a hardware company first and foremost, and it shows in spades.

Your mileage may vary.

But since the majority of application release scenarios we see play out in the marketplace are iPhone First, Android Second, Blackberry when we get around to it, I don’t think my take differs from those actually doing cross platform development, rather than those opining about it.

Nobody likes to have their baby called ugly.

But when it is, it is.

Download and Play a WAV file… using Objective-C

Download and Play a WAV file… using Objective-C

A client had a question this morning about loading a WAV file over the web and playing it from within an iPhone app.

Turns out it’s not too difficult to do:

// Grab the sound we wish to play from across the web
NSData * data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@”http://www.dailywav.com/0510/worstSunburn.wav”%5D%5D;

// Load the data into an AVAudioPlayer object
AVAudioPlayer * theAudio = [[AVAudioPlayer alloc] initWithData:data error:NULL];

// Play the sound file
[theAudio play];

Easy, Peasy.

Big Time Bug in Facebook Connect for the iPhone

Big Time Bug in Facebook Connect for the iPhone

While working on a new app for a client in Orlando today, we uncovered a significant bug in the Facebook Connect classes from Facebook for the iPhone.

What’s the bug?

Well, if you’re one of the fortunate souls who have a FB user id larger than an int, FB Connect for the iPhone, as it comes from Facebook, will blow up.

Blow up REAL good.

Oh, it may authenticate. But just wait till you check the uid in the session.

HEY! It doesn’t match my real uid!

The big bug is this – the FB Connect code uses library methods meant for integer values… all the while preaching to everyone the importance of Facebook User IDs being 64 bit values; in other words, in Objective-C parlance, long longs.

Too bad, ’cause with FB Connect for iPhone what this turns out to be is “do as I say, not as I do.”

Here’s where the busted code exists in the FBConnect code, and what needs to be done to correct:

FBSession.m

in the -(void)save method, replace the line that has [defaults setInteger:uid] forKey:@"FBUserId"] with the following:

[defaults setObject:[NSString stringWithFormat:@"%qi", _uid] forKey:@"FBUserId"];

in the -(BOOL)resume method, replace the line that has FBUID uid = [defaults intForKey:@"FBUserId"] with the following:

long long uid = 0;
NSString * uidString = [defaults objectForKey:@"FBUserId"];
if (uidString!=nil) {
NSScanner* scanner = [NSScanner scannerWithString:uidString];
if([scanner scanLongLong:&uid] == YES) {}
}

For all the razzing I’m giving Facebook here, really the broken parts of the classes are centered around moving data in and out of the settings bundle. Yeah – the uid’s are integers – big ass integers, to be sure – but the int functions for the settings bundle are no good for long longs – you got to convert them into NSStrings, and then back to long long again (%qi in sprintf-speak) when using the bundle functions.

Hope this helps those of you trying to explain why your iPhone apps work most of the time with Facebook Connect.

Sometimes, it really isn’t you – it IS the software (with apologies to Nick Burns, the Computer Guy).

In Which I Detail The Differences Between the Android and iPhone SDKs…

In Which I Detail The Differences Between the Android and iPhone SDKs…

I’ve had the pleasure of working on two side-by-side streams of development for the same app on two different platforms since January 1 – the new TweetPhoto applications for the iPhone and for the Android (see screen grabs below).

TweetPhoto for the Android
TweetPhoto for iPhone

First of all, let me say that from a developer perspective, I’m one of the most platform agnostic people you’ll find anywhere.  My philosophy is that money is green, spends the same anywhere, and if someone wants to build something on their favorite platforms of choice and needs someone to develop for them, then that platform is now my de facto “favorite development environment ever.”

Fact is, if one sticks around long enough, you outlive whole sets of tools, operating systems, and methodologies.  That certainly has been true in my career; while I lovingly still have my IBM 360 yellow book and can still recognize a fair subset of Hollerith on sight, it’s almost as embarrassing as watching The Who play the Super Bowl to talk about it.

Wandering sidebar aside, the past six weeks have given me a fantastic opportunity to compare iPhone and Android, side by side, on the same problem set and see how the two environments stack up.

The verdict?

There are things about each SDK I really like… and there are things I really dislike equally.

In fairness, my experience on the iPhone SDK is much more extensive than on Android.

Even so, putting together the exact same feature set on the two platforms points out where one platform shines over the other in terms of ease of implementation and execution.

All of the opinions below are 100% subjective and are my own.  If you have a contrary opinion, fine.  I don’t care.  Call a talk show or write your own post.

Development Environment

For the iPhone, you really only have one choice for developing apps – XCode.  For Android, I chose to use Eclipse and the Android plugins for Eclipse.

The Apple experience is tight, feels integrated out of the box, and just works.  The iPhone emulator is fantastic and works almost like the real thing.

Eclipse, since it is the Swiss Army Knife of Java Development, is not as integrated – out of the box – as XCode with regard to it’s Android implementation.  The Android Eclipse plug ins work great and are powerful.  I really dig Eclipse’s “Quick Fix” feature for including imports I need and recommending ways to fix broken code.  What I don’t dig is starting and re-starting the various emulators when trying to debug a running Android app.  Which I did tens of times each day when Eclipse lost full connection with the emulator I happen to be running.

Even so, I found the tools for controlling the features of the emulator (or should I say, emulators – you can configure an emulator AVM for each targeted device type and OS level you want) on Android to be much more powerful than the control one has – or doesn’t – over the iPhone emulator.

In a nutshell, someone proficient with Eclipse and who is a half-way decent open source / Java developer – who has never developed a mobile app – will be able to jump in and crank out working code quickly.  Apple, especially to a newcomer to Objective-C, is a pretty tough slog for the beginner.

Honestly, it took me about six weeks before I really felt a mastery over Objective-C.  From a standing start to finished app, it took me under three weeks to develop a professional grade Android app.  Enough said.

Getting Apps to Devices

The whole process of getting certificates, creating provisioning profiles, and the whole Apple approval process is pretty daunting to a newcomer.  Remembering back to when I first started to developing iPhone apps, and the time it took me to get up and sprinting, Apple’s setup is a pretty damn big barrier to entry.  Heck – I still run into provisioning and certificate problems switching between developer accounts when developing for multiple customers on the same development system.

Without going through the Apple App store, your only option is to use Ad Hoc provisioning, which limits you to 50 devices per Ad Hoc provisioning profile and you have to collect device UUIDs to make it work.  Factor in having to distribute new profiles each time a new device is added to keep everyone in sync and it quickly can become a real pain, especially if many QA testers are involved in a project.

For Android, you basically sign a .apk file and you’re off to the races.  You still have an approval process to get on Android Market – the analogue to Apple’s App Store – but there is absolutely nothing standing in the way of you distributing your app on your own without Google standing in your way.

Advantage to Google on this.  It’s worlds easier to get an app out and onto devices under Android than iPhone.

SDK Feature Comparisons

OK.  Getting the nuts and bolts of making apps for each platform behind us, let’s take a look at how coding for each device stacks up.

Documentation: Android’s documentation is there… but woefully lacks useful examples in a place handy to the API call I want to make.  My least favorite sentence to read in any discussion / support forum of any ilk is “well, if you check the sample apps, you’d see…” You know what?  I don’t have time to read every line of every sample application.  You want to see an easy to use document with ready-to-use sample code should be done?  Look at the PHP.net site.  It should be that easy to see how to use API calls.  Apple is not much better in this regard, but on the whole the iPhone is documented much better than the Android developer site.  But I’m not a huge fan of either, truth be told.

And while I’m screeding here (is that the proper pluperfrect subjunctive?) let me just say that it’s a good thing that Google exists, because I had to Google a shit-load of example code from about a hundred different places for stuff that should have been trivial to find – but wasn’t.  Like camera operation.  See the next section.

Using the Camera: The iPhone has a well documented interface for using it’s phone, and for selecting photos from it’s library – the image picker.  Android doesn’t have a pre-packaged all-in-one interface for doing this.  There is a bare bones example of how one ties into the camera, and a poorly documented – as in I had to find the solution in the wilds of the interwebs – of how one browses the camera’s gallery for photos already taken.

Let me go on the record as saying that in terms of overall code, it took a lot less code to do camera operations under Android than it did under Apple to do the same task – but that for Apple, it took me maybe two hours to get right while under Android it took me the better part of a weekend to find the right solution, and found somewhere other than on the Android developer site.  The image gallery code turned out to be like two lines of Java to implement, but is almost criminally under-documented.

Screen Design: Apple – hands down – has a better screen design tool in Interface Builder than the screen design tools available under the Android SDK.  I wound up doing most of my screen design using the underlying XML for each screen anyway.  Having said that, creating screens to display suitably for portrait or landscape mode under Android is ridiculously easy when compared to what you have to do under iPhone.  And before someone says, “well, it just works under iPhone as well”… child, please.  Only if you finagle each design element individually under Interface Builder, subclass the tab controller, capture device orientation for subviews that don’t respond to the “should change orientation” messages.  By a mile, this is something that Android did very well compared to Apple.

Maps: this is something that Google failed miserably at, in my very humble opinion.  Under iPhone, you add a MapView and it works with just a little additional setup for scaling and setting your location.  I got my first MapView in an Apple app working in like 10 minutes.  On Android, you have to get the MD5 fingerprint of your keystore (where the certificate you sign your app is stored) and apply for a Google Maps key.  And not just one key, but two keys – one for your debug keystore and one for your production keystore.  Which means that you have to manually change your keys between the debug key (so you can see your maps on the emulator) and between the production key (so you can see maps on real devices).  This is a total pain in the ass and is one more thing to forget before staging an app going out the door.  All in all, it took me an hour before figuring this all out and getting my first map working on Android.

Permissions: Android has many permissions that can be set, many of which you don’t know you need until you try and run your app and have it fail inexplicably.  For example, internet access is disabled by default (on a mobile device? yeah.  I know).  While I understand the beauty of this type of control, and that they are being safe rather than sorry, having to accidentally discover which permission is keeping my app from working is a not so pleasant experience.  The iPhone SDK really doesn’t have anything like this in terms of hobbling application capabilities on such a wholesale scale (push notifications being the one notable exception).

Application Manifest: Under Android, each screen (or Activity) has to be explicitly declared in the Application Manifest – more or less a map of your application’s permissions and activities – or your app will bomb when you try to invoke that screen.  I would say that this is the cause of most accidental crapping out that happens when putting apps together for the first time – forgetting to put a new screen into the manifest.  Under iPhone, you typically run into a similar situation by trying to load the wrong type of view controller into an improperly defined variable – but it’s not really the same thing.  Under iPhone, you know you need to load a view a certain way, and if you’ve defined the view it should work.  it’s not at all intuitive that you have to remember to add your new screen class to the application’s manifest file.  Or else.

Overall verdict: each SDK excels or fails because of the elements upon which they are built (amazing grasp of the obvious duly noted).

Because Objective-C is, at its heart of black hearts, just C with some objects bolted on, everything basically has to be built from scratch, especially tying UI elements together.  Because Android is Java based, and most of the screen design and integration “just done” for you, the time from zero-to-application running is much smaller under Android than under Apple.

My one huge complaint about Android is that a developer has to manually bring several pieces together to do anything productive, whereas with Apple it’s download and code.

In truth, if you’re a Java developer, you’re gonna be right at home with Android and curse the Apple fan boys.  If you’re an Apple fan boy, you’re gonna poo-poo the open source dweebs who have to support all of the forks that the Android environment will be challenged with as set makers try to differentiate features between their competitors.

And if you’re a developer like me, who’s just trying to pay the mortgage, feed the kids, and keep tuition current, you just hope to stay even.

Underline Text on the iPhone

Underline Text on the iPhone

One of the least talked about feature deficiencies of Apple iPhone SDK Font Handling is the inability to underline text.

You know – like you see in every web link on every web page on the internet.

Yeah.  That.

For me, where I need this the most is when I’m trying to create a link on one of my text sections or display elements, that will invoke a web URI and go off to do some work.

There isn’t a way to style underline fonts included with the iPhone, and Apple doesn’t make it easy at all to include custom fonts without a great deal of pain and gnashing of teeth.

What is one to do?

Well, I don’t know what the rest of you guys do, but this is what I did.

I created a button class (UnderlineButton) that subclasses UIButton and implemented my own drawRect function to draw the underline myself.

This isn’t rocket science, but works quite nicely.  The button should probably have a number of init functions to do things like set underline stroke width and color, but I needed a quick and dirty solution and had about 30 minutes to write, test, and deliver.

The code below is what I wound up with (UnderlineButton.m follows; UnderlineButton.h is simply a stub class that contains only @interface UnderlineButton : UIButton {}).


//
//  UnderlineButton.m
//
//  Created by David Hinson on 11/24/09.
//  Copyright 2009 Sumner Systems Management, Inc.. All rights reserved.
//

#import "UnderlineButton.h"
@implementation UnderlineButton

- (id)initWithFrame:(CGRect)frame {
  if (self = [super initWithFrame:frame]) {
    // Initialization code
    }
  return self;
}
- (void)drawRect:(CGRect)rect {
  [super drawRect:rect];
  CGContextRef context = UIGraphicsGetCurrentContext();

  CGContextSetRGBStrokeColor(context, 62.0/255.0, 62.0/255.0, 62.0/255.0, 1.0);

  // Draw them with a 1.0 stroke width.
  CGContextSetLineWidth(context, 1.0);

  // Draw a single line from left to right
  CGContextMoveToPoint(context, 0, rect.size.height);
  CGContextAddLineToPoint(context, rect.size.width, rect.size.height);
  CGContextStrokePath(context);
}

- (void)dealloc {
  [super dealloc];
}

@end

To use the button in an actual application, you would do something like the following:

  CGSize constraintSize, offset1;
  constraintSize.width  = 300.0f;
  constraintSize.height = MAXFLOAT;

  NSString * btnText = @"My Button Text";

  UnderlineButton * myButton = [[UnderlineButton buttonWithType:UIButtonTypeCustom] retain];
  offset1                    = [btnText sizeWithFont:[UIFont systemFontOfSize:16]
                                constrainedToSize:constraintSize
                                lineBreakMode:UILineBreakModeTailTruncation];
  myButton.frame = CGRectMake(20, 164, offset1.width, offset1.height);
  [myButton setTitle:btnText forState:UIControlStateNormal];

  [myButton setTitleColor:[UIColor darkTextColor] forState:UIControlStateNormal];
  [myButton setFont:[UIFont systemFontOfSize:16]];
  [myButton addTarget:self action:@selector(doButtonTouch:)
            forControlEvents:UIControlEventTouchUpInside];

  [cell myButton];
  [myButton release];

The doButtonTouch method will perform whatever it is you want to do; in my case this invoking another method to slide in a UIWebView to show drill down content.

Summary: Underline Text. Nothing there to make it natively easy, but workable solutions can be cobbled together.

But I will be the very first to say “it shouldn’t be this hard.

You’d think with all my video game experience that I’d be more prepared for this

You’d think with all my video game experience that I’d be more prepared for this

Well.

I finally got “bit” by the current Apple mania for ferreting out private API calls in App Store iPhone Applications.

You’d think with all my video game experience that I’d be more prepared for this (props to Toy Story 2).

Anywho, these are the two lines of code that got my submission smacked out of the park:

[[UIApplication sharedApplication] terminate];

and

[NSHost currentHost];

Doesn’t look like much, does it?

Still, verboten all the same.

In the case of the terminate function call, all I’m trying to do gracefully end the application in the event that network connectivity is not available.  There is a simple workaround here, and that is to instead use the C Language exit(0) call.  Easy-peazy, lemon-sqeazy.

The second “offending” call, [NSHost currentHost], is simply a call to get the iPhone’s current IP address.  The workaround here is to do something else, like this.

In any event, both of these changes were minor.

But frustrating.

Was I in the “wrong” for using them?  In the view of Apple, absolutely.  And in view of what I agreed to as an iPhone Developer publishing apps on the App Store, again, absolutely.

But, believe it or not, I don’t memorize every API call and know right off the top of my head whether it’s official or not.  Shocking, I know.

And, since the app that was being submitted has been in the App Store for over a year (as have these forbidden calls), it wasn’t like I was trying to sneak in some neato feature available only to Apple by using private calls.

Long story longer, I can easily correct these transgressions – and have done so – in about 15 minutes time.

The bad news is that the app sat in the approval queue for ten (10) days just to be rejected.  An app that has passed numerous times before.  And now must be resubmitted and waited upon.  Again.

Another seven-to-fourteen visit to the purgatory of App Store Approval.

If you think you’re gonna sneak some hidden feature in, reconsider.

Unless, of course, you have all the time in the world to resubmit offending apps.

An Open Note to Mobile Ad Networks – Show Me The Money

An Open Note to Mobile Ad Networks – Show Me The Money

It seems like once every couple of weeks I’m complaining about the see-saw nature of mobile advertising rates.  Of late, the rates have been what I consider to be abysmal (sub $4 to low $3 CPM).

This is particularly frustrating if you’re serving up between 500,000 and 1,000,000 impressions per month.

And seemingly, just as often, I’m approached by competing ad networks wanting me to switch to their platform.

They always want to talk about how they can pick and choose between several publishers and that their tech is superior.

You know what I want to know?

How much am I going to get paid.  Period.

Seems harsh, but here’s what I’m supplying and risking for switching to any ad publisher: my (or more properly, my app’s) reputation and traffic.

If they are only offering what I’m getting today – or less – what’s the point of even talking?

Today the cycle repeats.  I have an ad network calling to make their pitch, and I can almost predict the spiel.

Mr. Ad Network cubicle guy, you REALLY want my business?

Pay me a signing bonus for switching to your network.  Pay me for the time I have to take to integrate your ad client into my software, unit and system test it to make sure it doesn’t blow up under load, and bake it for 2-3 weeks in the App Store approval queue.

But please, don’t come to me expecting me to switch because you have the best brokering system since bartering began.

Show Me the Money.

iPhone Application Sketch Book

iPhone Application Sketch Book

Cheap Gas! New Features

Cheap Gas! New Features

In addition to the “Tweet ‘Em!” button, I’ve totally revamped the SOAP client, so it should be faster getting data from GasBuddy.com (I had been using a proxy to assist with the SOAP calls, but bit the bullet and moved the SOAP client entirely on the handset – so, remove the intermediary proxy means a more responsive app).

I also optimized the scrolling so the UI experience should be a lot better… plus I prettied up some of the plain jane buttons.

I’m very hopeful this release gets approved quickly, because I really think people will dig the twitter option.  A lot.