Make web apps act more native

With a simple trick you can make a web-based app look and act more native on an iPhone or iPod Touch.

Adding the following tags to your <HEAD> will make your application open in full screen and hide Safari’s toolbars. In addition, if you add it to your home screen, it will appear to open without Safari and no page will be added to Safari.

<meta name="viewport" id="viewport" content="width=device-width,user-scalable=no,minimum-scale=1.0,maximum-scale=1.0" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />


The following tags, which should also be added to <HEAD>, will provide an icon for the home screen and a splash screen to be displayed when it opens.

<link rel="apple-touch-icon" href="http://example.com/webclip.png" />
<link rel="apple-touch-startup-image" href="http://example.com/startup.png" />


The first application I’ve seen which uses this trick is Fever.

ICHC Update

Good news: there will be an ICanHasCheezburger app update sometime after the holidays. This isn’t the fabled Three20 based version 2.0, but a minor update which simply changes the feed URL. However, by doing so, it should fix most of the crashes.

Our application uses a ‘scraped’ feed generated from the site content rather than the site’s own RSS feed. We do this because the standard RSS feed only has a limited number of items and must be loaded in its entirety. By scraping the site, we can create multiple pages with unlimited items, which load a lot faster since it only loads 10 or fewer items at a time.

The feed scraper was originally developed by the folks at ICHC for their dashboard widget. I later modified it to support all of their sites and change the output from JSON to simplified XML. Unfortunately that feed scraper has a major flaw. It uses regex pattern matching to parse the HTML, which is a Very Bad Thing. The script can easily get confused by changes to the site and often produces invalid data. It also hasn’t included videos since a format change at the site broke it.

Last night I started hacking at it with PHP’s XML parser and DOM commands and came up with a much more robust script that uses element classes to identify valid items and to avoid outputting bad data that could crash the application. I’m also hosting it on my own server at DreamHost, so I can easily fix it myself instead of having to go back and forth for fixes as we do now.

Unfortunately a few Viddler movies still won’t play, since they must be explicitly enabled for downloading on the site.

Lack of Manpower May Kill VLC For Mac

Via Slashdot:

plasmacutter writes “The Video Lan dev team has recently come forward with a notice that the number of active developers for the project’s MacOS X releases has dropped to zero, prompting a halt in the release schedule. There is now a disturbing possibility that support for Mac will be dropped as of 1.1.0. As the most versatile and user-friendly solution for bridging the video compatibility gap between OS X and windows, this will be a terrible loss for the mac community. There is still hope, however, if the right volunteers come forward.”

VLC is one of my favorite applications, so I’d hate to see it die. Unfortunately I have too many other things going to take on another project, especially an unpaid one, or I would get involved.

ICHC Crashes

I’ve been receiving a lot of reports of ICHC crashing recently. I’ve never been able to duplicate any of those crashes myself, but from looking at the crash logs available in iTunes Connect I have an idea of what’s crashing them.

The crashes seem to occur when restoring the last viewed item results in an index out of range. We use a scraped feed (which is hosted on one of ICHC’s servers) that returns pages of 10 items each, to reduce the load time. I’ve seen a few instances where items, usually videos, are missing from the scraped feed, and in that case it returns a page of fewer than 10 items. If you happen to have been viewing item 10 the last time you quit and the next time you end up with only 9 items, it will crash.

I’ve put in some error handling for that case, but if you’re experiencing that crash, I’d like to have you test it before I submit the update, so email me your device ID and I’ll add you to my beta list. Note that Apple can take several weeks to approve an update, so even if I submit it right away, it may be a while before the update becomes available.

This will be the last update to this version. I’m doing a major rewrite for version 2.0 using Three20, the framework used in the FaceBook app. This will be a free upgrade.

Before I do much on v2.0, I’m finishing a new application I plan to release first. More about that in the next few weeks.

How 1Password extension loads in 64-bit Safari in Snow Leopard

Kevin Ballard explains how 1Password is able to load an extention into Safari when running in 64-bit mode:

When Cocoa was introduced, one of the behaviors that every Cocoa application automatically acquired was the loading of Input Managers. These Input Managers were intended to allow developers to extend the text input system of OS X in ways that the system did not provide by default. However, these Input Managers were really nothing more than Cocoa bundles that got loaded by every single Cocoa app at launch. This means that it was very quickly abused to become a general plugin mechanism for applications that do not natively support plugins (such as Safari). In recent OS updates, Apple has been deprecating this mechanism, and now in Snow Leopard it’s completely gone for 64-bit apps.

Luckily, the smart folks who make 1Password came up with a solution for their upcoming 1Password 3.0 (which is in public beta right now).

AppleScript is a rather old technology, first introduced in System 7. It is a human-readable scripting language that can control any application that implements support for it, along with a slew of system functions. Under the hood, it sends Apple events to actually talk to each process.

Scripting additions are bundles that provide additional functionality to AppleScript, generally by installing Apple event handlers or doing Apple event data coercion.

The thing about scripting additions is that they will be potentially loaded by any process on the system. Generally, they get loaded into a process that attempts to use an AppleEvent that the scripting addition handles.

The ability to load a scripting addition into a target process simply by sending it an Apple event is the key mechanism that allows us to restore the old Input Manager functionality. And this is exactly what 1Password does. 1Password includes a scripting addition that handles the ONEP/Load Apple event with a context of “Process”. This handler takes a single argument, the path to a given bundle, and it loads that specified bundle into the target process. The last component is a background daemon called 1PasswordAgent. This daemon sends the ONEP/Load Apple event to Safari immediately after Safari is launched, causing Safari to load the 1Password WebKit plugin.

This actually sounds a lot cleaner than the input manager hack. I hope Apple doesn’t disable this in the future. Hopefully it will also provide a mechanism for 1Password to work in Opera & Google Chrome.

Easy way to add sound effects to your app

Every game needs sound effects. A free gem called cxfr makes it easy to create retro video game sound effects and export them for your game. You start with one of their presents like pickup, laser, explosion, hit, jump, or random and adjust the sound to your liking using sliders. You can then export your sound as a wav file to use in your Mac or iPhone applications.

Changing app store ratings

I finally discovered the trick to change the ratings for ICHC, so hopefully Apple can review it now. As long as there’s a valid binary, iTunes Connect won’t let you change the ratings. If you reject the binary, you can go to edit information and change the ratings BEFORE you upload a new binary. Once you upload that new binary, the ratings are locked out again.

I set the ratings to infrequent/mild for all items, which still only results in a 12+ rating, not the 17+ rating Apple requested. We’ll see if Apple approves it now.

Fast image loading with Three20

I get a lot of complaints about the slow swipe action in ICHC, as a result of loading each image the first time they appear. Although I added caching in version 1.5, I chose to do it that way to minimize the memory usage and avoid low memory crashes.

I’ve been looking at ways to improve the speed and one of the best options seems to be to rewrite it using Joe Hewitt’s Three20 framework. As a proof of concept, I wrote a simple test program which loads a pre-defined set of images. The scrolling & image loading performance is excellent.

Note this is just a proof of concept. I haven’t figured out all of the details of how to implement it in the actual application. The major hurdle is that I need to handle mixed photos & videos in a single stream, while the photo browser only handles photos.

Of course there won’t be any new updates until Apple approves the updates that have been in review for over a month, as well as the new updates I submitted a week ago with.

I Can Has Video

As you’ve probably noticed, movies rarely work in I Can Has Cheezburger app (as a work-around, you can open the web page and click the video to play it).

The reason it doesn’t work is the movie URL returned in the feed, which is something like http://www.youtube.com/v/cxLG2wtE7TM won’t work when passed directly to a UIWebView or sent to youtube to handle. If you look at the ICHC web page containing the video, you’ll see an embed tag containing that movie URL, which a webview is able to handle correctly.

I came up with a very simple way to make videos work reliably: I create a HTML string with an EMBED tag containing the movie URL. Instead of opening the movie URL directly using UIWebView loadRequest:, I open the HTML document I built with loadHTMLString:. You’ll now have a clickable movie thumbnail, which will open in the standard YouTube player without exiting the application.

Rewriting code without fear

Over the last few days, I’ve been rewriting some major pieces of ICanHasCheezburger.app to simplify and clean up the way I handle movies. Currently I use a single image view, which is set to a ‘play’ image for movies, which then open in the browser when clicked. I’m changing it to swap between the image view for displaying images and a web view in which I open movies.

In addition, I’ve cleaned up and simplified the way I deal with the RSS feeds I obtain the images from. Previously, I had a single FeedController class, which stored the entries obtained from a CXMLDocument as an array of CXMLNodes. To display an image, open the web page, or play a movie, I had to query the FeedController for an element of the current item.

To clean it up, my FeedController now uses an array of FeedItem objects, with properties such as permalink, image URL, movie URL, and title. I now pass a FeedItem to my root view, which uses it to decide whether to display an image or movie without having to go back and query the FeedController.

I found it to be a lot easier & cleaner to use NSXMLParser, so I can create a FeedItem for each RSS item directly rather than have to manipulate the CXMLDocument, extract each CXMLNode, and create a FeedItem for it.

Until now I’ve never used XCode’s Snapshot feature. Since I use Subversion, I figured I could simply check out an earlier revision. Before I started rewriting all of that code, I saved a snapshot. It shows exactly what has changed since the snapshot and makes it very easy to revert if something goes wrong. It’s very similar to checking in to Subversion or reverting to an earlier revision, but it’s a lot faster and more convenient. I find it very liberating to be able to make a major change like this and not have to worry about messing up, since I can easily go back to the way it was.

Snapshots