• How my simple iPhone app made it to the top of the App Store

    Slightly more than a month back I wrote this little iPhone app (App Store link), almost a toy app really, to check the usage of my data plan with my local telco (Singtel). I wanted to scratch an itch and I also really didn't want to exceed my data plan - the fees are excessive.

    Anyway, I submitted it to the iPhone App Store for approval as a free app and named it Singtel Data Usage. No points for creativity with the name but I thought it'd be nice to know exactly what the app did from just reading its name. After one keyword rejection (which was unfounded but I wasn't going to argue with the app reviewers), it finally got approved a few days ago.

    Singtel Data Usage iPhone app screenshot

    Yeah that's what it looks like. I stole part of the design from another iPhone app - can anyone guess which one? I think I spent 80% of development time changing the design over and over again, tweaking font sizes, and agonizing over which icons to use.

    Thanks to folks on Twitter (I'm @chuyeow - do follow me if you're reading my blog), word got around and by the 3rd day of it being approved, my app was the Top Free app on the Singapore App Store. Going to take a time out for the vanity shot:

    A similar app, iBBOM, was approved around the same time but I believe I got a head start because of all the awesome people on Twitter who retweeted my tweet and the kind folks who gave glowing reviews on the App Store (thanks especially to Andy Croll for the 1st review). iBBOM actually looks much better than my app (I can't help tweeting about it) and works perfectly (only thing I don't like are the ads). I believe I couldn't have gotten to the top of the App Store without the guys and gals who spread the word on Twitter.

    On to the not so fun part of this post. Yet another similar app, SG BBOM, was pulled from the App Store by Singtel (the telco) recently so I'm expecting to hear from Singtel really soon. We shall see.

    In the meantime, if you own an iPhone and have a Singtel data plan, do check out my app (App Store link) and give an honest review on the App Store. If you've already downloaded it, I'd like to know what you think in a review as well. Thanks!

  • Blog redesigned

    After 5 long years of using the same old blog theme, which I'd handcrafted from scratch way back in 2004, I've finally got down to refreshing it to a more contemporary look. I've also updated the woefully outdated About page.

    Here's a before and after shot:

    Blog theme - before and after

    I think it's much better, definitely more modern and minimalist.

    The new blog theme is basically a heavily modified version of the
    wonderful and free Compositio WordPress theme -
    you can check out a demo of Compositio here to see how different it is.

    The only thing I kept from my old theme, which I affectionately called "Clover", was the same clover logo. I did that with the shape tool in Photoshop - it's a simple logo and no skill was required to create it, obviously!

    If you're reading this in a feed reader or one of those aggreggator-type sites, you can help me out by checking out the blog itself and giving me some good old constructive criticism.

  • Upgraded to iPhone OS 3.0 and running out of battery fast?

    After upgrading my girlfriend's iPhone 3G to OS 3.0 recently, I noticed that the iPhone's battery was getting depleted really quickly. I'd left it overnight with Wifi, 3G, Bluetooth, Push Notifications all off, and the battery went from 80% to a jaw-dropping OMGWTFBBQ 10%.

    I attributed it to the recent jailbreak (I've already removed the jailbreak trying to figure out this problem) at first. I only realized something was really wrong when the iPhone's battery started draining while it was charging via USB!

    Looking around on teh interwebs, I managed to solve it (easily!) by following the suggestions from this thread at the Apple support forums. Here's what worked for me:

    1. Go to Settings on your iPhone.
    2. Turn Notifications off. I'm not sure if this is necessary but did so just in case.
    3. Go to Mail, Contacts, Calendars and delete all your accounts (I deleted even Calendar accounts just in case). You may want to write down or backup your account settings first.
    4. Go to Fetch New Data (also in the same Mail, Contacts, Calendars settings) and make sure Push is Off.
    5. It's probably not necessary but you may want to restart your iPhone (power it on and off) here.
    6. Add back all your accounts. You can turn Push back on Fetch New Data now.
    7. You can also turn Notifications back on if you wish.

    It seems like the iPhone 3.0 OS update has a bug where email accounts with active push notifications were set to keep fetching new email even if push is turned off explicitly. Hopefully this post will help solve your battery problems, if not, you've gotta keep looking - the Apple iPhone Support forums is a good place to start.

  • A curl-ier Curb - better cookie support in Curb

    As of Curb 0.3.7, Curb comes with slightly better cookie support that makes it more "curl-like".

    It probably sounds like shameless self-promotion that I'm blogging about these changes since I'd contributed them. Well, yeah that's true, but I'm also doing so because I doubt these changes will ever be made known since Curb doesn't publicize any updates or changelogs.

    Curb is my current number 1 HTTP client for Ruby so the more love it gets, the better.

    Passing cookies as a string in Curb requests

    Curl veterans will probably know how to do this with the curl binary:

    curl -b "auth=abcdef; ASP.NET_SessionId=lotsatext;" example.com

    This sends a request to example.com with 2 cookies named "auth" and "ASP.NET_SessionId" (I hate those big-ass ASP.NET cookies btw). There wasn't a way to set this in Curb, so I looked up the libcurl C API docs and replicated the same option in Curb (commit on Github). An example:

    curl = Curl::Easy.new('http://example.com/')
    curl.cookies = 'auth=abcdef; ASP.NET_SessionId=big-wall-of-text;'

    Of course, the cookies will more often be retrieved/constructed rather than a literal like in the example above. In my case, I was proxying cookies while trying to wrap an API around a site that doesn't have one.

    Passing cookies as a file via the "cookiefile" option

    The second change is the new cookiefile option. This replicates curl commands like these:

    curl -b cookies-to-send.txt www.example.com

    with something like this in ruby:

    curl = Curl::Easy.new('http://example.com/')
    curl.cookiefile = '/path/to/cookies-to-send.txt'

    The cookies file looks like this (you can get a sample with the --cookie-jar option to curl, e.g. curl --cookie-jar cookies.txt www.wego.com):

    www.wego.com	FALSE	/	FALSE	0	lang	
    www.wego.com	FALSE	/	FALSE	0	user_country_code	SG

    Check out the commit on Github if you're interested.

    Why would I use these?

    Now you might be wondering how these 2 changes are useful - well, they are totally irrelevant to you if you're not expecting any cookie support in Curb. However, if you're accessing or scraping a site that uses cookie-based authentication, these changes allow you to keep your Curb client authenticated across sessions, even when doing HTTP POSTs (Curb doesn't send cookies properly in POST requests even if curl.enable_cookies is set).

    I've found these changes to Curb particularly useful since I vastly prefer Curb to most HTTP clients for its speed and lightweight implementation, and heavier scraper-type HTTP clients like Mechanize are a last resort.

  • Don't kill your app when using ActiveRecord in Rails Metal, release your database connections

    Rails Metal has been available on Rails since version 2.3 - it's old news. But if you haven't used it or heard about it, you can find out more about Rails Metal on the RoR weblog and on Jesse Newland's blog.

    So anyway, I am one of those laggards and only wrote a Rails Metal piece not too long ago for a Rails app on Wego.com in an effort to optimize some high volume requests. It looked something like this:

    class Adamantine
      def self.call(env)
        if env['PATH_INFO'] =~ ROUTE_REGEX
          location = Location.find(1) # Use ActiveRecord.
          [200, { 'Content-Type' => 'text/html' }, [location.to_json]]
          # Leave it to Rails to deal with the request.
          [404, { 'Content-Type' => 'text/html' }, ['Not Found']]

    Notice the use of an ActiveRecord model. It ran for quite awhile, almost 30 minutes, in production until I started getting notification emails about "Too many open database connections" to the MySQL server! The change was promptly rolled back and there was no cheezburger for me.

    dam it!

    As it turns out, Rails doesn't take care of certain things in Rails Metal pieces, including the releasing of connections back to the database connection pool. A bit of googling turned up this bug in Rails' bug tracker (see Josh Peek's comment about ActiveRecord::Base.clear_active_connections!).

    I rewrote the Rails Metal piece to always ensure it clears any active database connections with ActiveRecord::Base.clear_active_connections!:

    class Adamantine
      def self.call(env)
        if env['PATH_INFO'] =~ ROUTE_REGEX
          location = Location.find(1)
          [200, { 'Content-Type' => 'text/html' }, [location.to_json]]
          # Leave it to Rails to deal with the request.
          [404, { 'Content-Type' => 'text/html' }, ['Not Found']]
        # Release the connections back to the pool.

    Moral of the story: Don't forget to release your database connections if you're using ActiveRecord in your Rails Metal. Or even better, don't use ActiveRecord in Rails Metal - you're aiming for raw speed anyway right?

subscribe via RSS