Trim iOS Screenshots, Made Easy

With every release of SaxoTrader, I have the trusted privilege of removing the status bar from the screenshots for the App Store.

I don’t have to remind you to remove the status bar from your App Store screenshots, do I? I still see them a lot on the App Store.

In any case, with SaxoTrader translated into 18 languages, 12 for the App Store, and with five screenshots for both iPhone and iPad, we’re talking 120 screenshots.

Normally I use Acorn and its bundled Crop Images Automator action. But this time I wanted to “outsource” the task back to the project owner who made the screenshots in the first place. However, he doesn’t have Acorn…

So I rolled my own stand-alone Automator action, wrapped it in a workflow, bundled into an application he can drag and drop the screenshots onto – whether generated in iOS Simulator (⌘S) or directly on the devices:

Trim Selected iOS Screenshots Automator Application

I chose to first develop a Foundation command line utility and then the action which embeds and uses the utility. The utility can also be used independently if desired (that’s what’s I’m doing). Ideally, it should double as an XPC service, but I managed to contain myself.

You’ve guessed what this leads up to: the source and compiled binaries are available on GitHub.

If you ever find yourself fiddling with various crop tools to get rid of the status bar on your App Store screenshots, and you should, you might find it useful. Whether you’re a CLI or GUI type of guy.

I had the privilege of giving my “Beyond Delicious” talk at this year’s very successful Danish App Awards. (Photo: Philip Alexander Helm)

I had the privilege of giving my “Beyond Delicious” talk at this year’s very successful Danish App Awards. (Photo: Philip Alexander Helm)

Using Build and Version Numbers and the Art of Injecting Them into Your App

Prompted by a recent article by generous Jeff LaMarche, I thought I’d post my process for generating build numbers and having them automatically written into in my builds so they can be displayed in an About view like this:

Deep Green Version Information

The principle I’m using is to write the version information to the generated app bundle in the build process in such a way that it doesn’t change anything in the source tree. This is because I want to avoid the situation where I have to make a new commit to the source repository after I’ve tagged and built the released version.

The shell script I’m using is very simple, runs as a build phase and uses agvtool and git under the hood. Contrary to Jeff, I don’t have any issues using agvtool, which integrates really well with Xcode.

Using the script to automatically generate version and build numbers in your app only really takes three steps:

  1. Download the script and store it within your source code tree.
  2. Add a call to the script as part of your build process.
  3. Bump build number and tag commits when desired.

Step 1 and 2 are done just once per Xcode project.

I’ve only run it in my own setup. It may not work for you. If it doesn’t, please let me know.

What Are Build Numbers Anyway?

Build numbers are unique references to specific builds, or versions, of an application. Where version numbers typically come in the form of two to three parts (the major and minor feature version numbers and possibly a bug fix version number), build numbers are sequential integers, typically incremented at each build that leaves the developer’s machine.

As I bring up the version information of TextMate, where I type this, it reads 1.5.10 (1631). The build number is 1631, the version number is 1.5.10. End-users are normally mostly concerned with the version number. agvtool calls this the marketing version and the build number just the version.

Subversion, being a centralized revision control system, maintains a globally unique revision number on the repository which can be used as the build number for a build of any particular snapshot of the repository. Git, on the other hand, is a distributed version control and therefore can’t compute a globally unique sequential number. Instead Git uses a SHA to identify a specific commit snapshot which isn’t very human readable.

Since I use Git, thank you very much, I’m relying on my simple script to manage the build and version numbers for me. The build number is tracked in the project itself (managed via agvtool), and the version number is managed using Git tags.

How to Use Build Numbers and When to Bump’em

Even though build numbers are “just numbers”, I prefer to decide when to generate a new one. In the process of developing an app I find it easiest for everybody involved to refer to these unique build numbers instead of a version number which may or may not change at every internal release. And the build number of each released version should be incremented by only one at a time so that everybody knows they haven’t missed a version somewhere in the process.

In other words, I want to increment the build number when I release a version, for either test or App Store, not just because I’m making a new commit (already uniquely identified by its SHA) or happen to compile using a certain configuration (as suggested in Jeff’s article).

The main reason I don’t want to automatically bump the build number each time I compile using a certain configuration is that it sometimes takes a few build attempts to get it right (most often because of the Provisioning Hell).

The Workflow Around a Release

In my daily life as an Cocoa developer, I distinguish between three types of builds. These types are also mirrored by the three branches in the Git repository:

  1. Development builds take place all the time during the normal development workflow of coding, building and running. Code changes are committed to the development branch, and the build number is not incremented in this process (however, the version number will look different after each commit, see below).

  2. Test builds are intended for a larger audience, i.e. testers and other stakeholders, who’ll run the build on their registered devices. These builds are compiled from the test branch and tagged with the version number after the build number has been manually incremented.

  3. App Store builds immediately follow a successfully tested Test build. App Store builds only differ from Test builds in that they’re committed on the master branch and submitted to the App Store.

For more information on the repository layout, see my (very casual) talks on creating a smooth development workflow using Git and GitHub:

Each time I distribute a Test build, I go through the following process which introduces my custom version.sh script:

  1. Check out test and merge development into it (--no-ff).
  2. Update the change log, targeted testers, describing new functionality, changes and bug fixes in the release.
  3. Bump the build number: version.sh bump. This is basically the the same as running agvtool bump -all, but my script just generates a less noisy output.
  4. Commit the changes locally: git commit -a. Don’t push to a remote repository just yet as you may run into compilation quirks and need to fix those first.
  5. Tag the commit with the version number, e.g.: git tag -a v1.2.
  6. Archive (also builds) the target, using a distribution configuration, either from within Xcode or the command line with xcodebuild.
  7. Distribute the binary (you’re using TestFlight or similar, right?)
  8. Merge the test branch back into development (--no-ff).

You can leave out the test branch roundtrip (step 1 and 8) if you don’t care about having your Test releases on a separate branch.

Note that all of the above could be fairly easily automated, depending on how you do your change log update and distribution. I prefer to do it by hand because… I guess I just like to see this succeed little by little.

The key to the process here is the manually triggered build number update and tagging the commit which version.sh uses for setting the version number. And note that the only place we’re keeping track of and storing the build number is in the project itself.

Automating the Version Number Injection

Let me finally get to the issue I wanted to talk about in the first place: how to get the version number into your app.

version.sh does more than just bump the build number. It can also write the version number to the compiled app bundle — i.e. into the generated Info.plist file. If you add a Run Script Build Phase after compiling the target dependencies and before copying the bundle resources, for example, version.sh can write the version numbers to the generated app bundle like this:

Xcode Build Phase Script

Make sure to have version.sh stored on a path included in our $PATH environment variable or use the project-relative path to the script. In my case, it typically looks like this:

Work/Scripts/version.sh --set --plist-path \
  "${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}" --quiet

It’s worth noting that this will alter the Info.plist of the built app, not the Info.plist in your source tree. What this means is that your source tree won’t get dirty from this operation, and you won’t have to either reset or make another commit which would create a mismatch between the code you tagged and the code containing the correct version number. In other words, the version number is only stored in the Git tag. Only the build number is stored in the project as mentioned.

Reading the Version Number from Within Your App

Getting out the version information from the app bundle is very straightforward too. Just call the following:

NSDictionary *appInfo = [[NSBundle mainBundle] infoDictionary];
NSString *versionStr = [NSString stringWithFormat:@"%@ (%@)", 
    [appInfo objectForKey:@"CFBundleShortVersionString"], 
    [appInfo objectForKey:@"CFBundleVersion"]];

This will set the version string to something like @"1.2 (224)" as shown in the screenshot above.

More on the Script

It’s less than 160 lines of code, most of which is boilerplate, but I won’t list the script here. It’s hosted on GitHub in case you want to have a look at it. If you run version.sh --help from the command line, you’ll get the following output:

version.sh 1.0 by Joachim Bondo <osteslag@gmail.com>

Manages build and version numbers using git and agvtool.

Usage:
  version.sh [options]

Options:
      --terse              Prints the version number in the terse format
  -s, --set                Sets the version number using agvtool
  -p, --plist-path <path>  Write to the built Info.plist file directly
  -b, --bump               Bumps the release number
  -q, --quiet              Supresses output
  -h, --help               Displays this help text
  -v, --version            Displays script version number

Notes:
  - If no options are given, the current versions are printed
  - Specifying -s requires a --plist-path and uses the git tag

You should run the script from your project directory — you’ll get an error message if you don’t. Conveniently it’s is the default for running build phase scripts.

I use it mainly to set build and version numbers and write them to the generated app bundle as described above, but you can also use it to read out the current values, by simply invoking the script without parameters:

$ version.sh
Version: v1.2d6 (42)

Again, the build number is read from the project, the version number is derived from the Git tag by calling git describe --tags. When setting the version number in the app bundle, the script will remove any leading 'v' character.

A nice thing about using the Git tag is that if you make a development build, in-between any Git tagging, you’ll get a version number like v1.2d5-54-gbacc9a8. In this case the version is built on a commit identified by the shown (partial) SHA which is 54 commits after the last tagged version, v1.2d5. This works really well for Development builds.

Outtro

Despite this rather long post, I hope to have demonstrated how to use this simple script to easily generate and inject build and version numbers into your iOS and Mac OS X apps.

What’s a Quality App?

Deep Green 1.2 was released last week. I had been working on it for more than a year — although not full time. Over a period of six months, I had two simultaneous full-time assignments: rewriting the Moodagent API and developing Saxo Bank for iPhone.

During that six month period, I didn’t code much Deep Green. However, I did spend time reworking the graphical design with The Iconfactory. That it took four months just to get the shapes of the pieces right, tells something about the amount of details crafting a great app entails.

For app buyers I think it’s important to understand that Deep Green is what I call a quality app. And what I mean by that is not just that it’s well done, good looking etc., but that it gives users a lot value for their money over time. In terms of App Store pricing, Deep Green isn’t cheap. But even if you bought it in 2008, you’ll still be able to run it on any of your current iOS devices, also the ones that didn’t exist at the time. And at no extra cost.

I see lots of developers who not only take the easy and tempting solution to offer separate apps for iPhone and iPad (instead of one universal), but also adjust the price up and down, back and forth every so often to “optimise” revenue (or whatever). And to whose benefit? Certainly not the loyal users who bought the app early, at a higher price.

As a user I really don’t like to see an app I just bought now being offered at a lower price. I feel I made a bad decision buying the app. I regret the purchase. I also feel bad about buying an app I’ve already bought, just because I wish to run it on my iPad as well as my iPhone. Not only do I have to manage several versions of the same app, I have to pay for it again.

As a developer I really don’t want my users to feel the same way.

Deep Green has been $7.99 from the very beginning (except for the short introductory price at $4.99 in December of 2008), and it’ll stay that way. If anything, price will go up as more features are added. So regardless at what point you choose to buy Deep Green, you’ll never find yourself in a situation where you regret not having postponed the purchase.

That’s a quality app.

To celebrate my new avatar on Twitter and elsewhere, showing a recent me, I thought I’d post the full photo here. As you can see, I’m old enough to have appreciated what Bill Atkinson did, while he did it.

To celebrate my new avatar on Twitter and elsewhere, showing a recent me, I thought I’d post the full photo here. As you can see, I’m old enough to have appreciated what Bill Atkinson did, while he did it.

Let There Be Dark

I’ve been an avid IR_Black theme user for quite some time now, both with Xcode and TextMate. Used together with the most beautiful monospaced programmer’s font known to man, Inconsolata, writing code has never been a greater visual pleasure. I find the dark background and the aesthetic font rendered in this palette of pale colours extremely tranquil. And with the recent Golden Master of Xcode 4, I’m experiencing a new level of programming pleasure. Because as the programmers among you will know, the process of writing the code itself is as rewarding, if not more, as reaching the end-goal with the code. Right?

However, the problem is that IR_Black hasn’t been ported to Xcode 4 yet. At least not “officially”. Todd Werth, who seems to be the originator of the theme, hasn’t even made it available for Xcode. The version I’ve used for all this time is this one by David Zhou and is also the earliest reference to IR_Black for Xcode I’ve been able to find. But it’s for Xcode 3 only.

So here’s my attempt at IR_Black for Xcode 4. It’s using Inconsolata at 16 pt which is quite large, but works extremely well on my 27" iMac. You can easily change the font settings from within Xcode > Preferences > Fonts & Colors.

Enjoy.

Leave Your Mac in Peace, Lock with Ease

I currently work in an environment where it’s good custom to lock one’s computer when leaving the desk. Not because we don’t trust our co-workers, but as a general security measure. And because this is a bank, security is always on the agenda. And because it’s a bank, everybody uses PCs running Windows. As second nature, they slap at Windows-L on their keyboard to quickly lock their PCs while getting off the desk.

So what am I, the only lucky guy with a Mac (required to develop iOS apps, thank you very much), supposed do? I have to send the mouse on the longest travel, over multiple screens, to the far upper right corner in order to select Login Window… in the user menu. By the time I release the mouse, I’m the only one left in the office, while everybody else is stripping the lunch buffet.

There’s no apparent way to assign a keyboard shortcut to the menu item without using third-party software, such as Daniel Jalkut’s excellent FastScripts, but I’d rather not have a another background process running just for this. I know I can assign a Hot Corner in the Screen Saver preferences pane, and have the screen saver prompt for password on wake, but I all too often invoke it accidentally. How I envy the Windows users their Windows-L shortcut. Well, you guessed it, not anymore…

One way of getting around this limitation is to create a general Service and assign it a global keyboard shortcut. And one easy way of creating a Service is to use Automator, the totally under-appreciated automation and scripting tool under Mac OS X (more posts on this over time). Automator can execute all kinds of actions, including scripts: AppleScript, Python, Shell, etc., so all we need to do is to figure out how to invoke the Login Window command. A little bit of searching the net found me this gem:

/System/Library/CoreServices/Menu\ Extras/User.menu/Contents/Resources/CGSession -suspend

So we can create a simple workflow like this:

Now, save the workflow as Login Window, for example. The workflow file will be stored in your ~/Library/Services/ folder and will be available in the Application > Services submenu in all applications. With this installed, we can now assign it a global keyboard shortcut. Go to System Preferences > Keyboard > Keyboard Shortcuts and click the Services item in the list to the left. Scroll to the bottom of the list to the right and open the General element. Assign your new service a shortcut as described:

That’s it. Now hit your shortcut, and you’ll be rewarded with the turning cube effect revealing the login window.

Update: @wmdmark suggested to me on Twitter to use the built-in ⌃⇧⎋ (ctrl + shift + esc) shortcut to activate the screen saver. With the password locking option activated, this will also lock the Mac and, as an added bonus, prolong the life of your screen. Thanks.

Not So Lickable

2007 was the last year Apple offered a dedicated WWDC session where the attendees could ask questions about anything Mac OS X to a panel of Apple people (I forget the name of the session). This was the year when Mac OS X Leopard was released, and we’d been given a preview DVD at the conference. Mac OS X was getting rid of its pinstripes (what was left of them going from Panther to Tiger) and brushed metal windows, but gained the unified window and a generally cleaner and flatter look.

At the session I took the microphone and begged Apple to let the no-longer-so-lickable Aqua scroll bars, checkboxes, radio buttons, popup menus, progress bars etc. follow the new direction in the final Leopard release. Of course Apple couldn’t comment on it, but I’d hoped at least they’d carry over the more matching iTunes controls. But as we’ve seen, even Snow Leopard is still chained to the antiquated Aqua controls.

If you take a look at a few recent software releases, Twitter and Reeder, you’ll see that the developers have gone through the trouble to avoid Aqua and adapt a more modern look (Apple’s App Store app to the left):

So now even mainstream Mac software is departing from the old design. It can’t even wait till the next Mac OS X release, Lion, due Summer 2011, which Apple previewed at its Back to the Mac event in October. At the event the media was quick to pick up on a possible new scroll bar design, a design that Apple later notably left out of the screenshots on its Lion page.

All this just to say that like it took Apple years to come out with mice and trackpads that finally got rid of the one-too-many button design (while others kept squeezing in extra buttons everywhere), I hope Apple is coming up with a well thought out solution for the scroll bar. And the iOS design is indeed a very good place start…

Let There Be Light (More Easily)

I often find myself adjusting the brightness of my iPhone screen. The Auto-Brightness switch just isn’t the magic bullet. When using the iPhone in darkness, for example, I have to manually dim the screen to the lowest setting.

Wouldn’t it be nice, and much more relevant, if we had a brightness slider in the task switcher instead of yet another way to adjust the volume?

We currently have the hardware volume buttons, and they’re plenty handy. We even have similar controls on our earphones. But there’s no easy way to adjust the brightness, like on the iPad.

You have to exit the active app, flick to the home screen page containing the Settings app, open it, navigate to Brightness, and after adjusting (on a different screen than the one that prompted you to make the adjustment in the first place), and finally go back to the your app.

So, Apple, please give us the brightness slider at our fingertips. I know you’re reading this (but just in case, I filed a bug).

I’ll Be Back Shortly

In a recent test by Royal Pingdom, Tumblr came out as the most unreliable blogging service when compared to Google’s Blogger, WordPress, Typepad and Posterous. So I chose Tumblr.

In the process I signed up for a Typepad trial which was a far from pleasurable experience. Not only did I have to leave them my credit card details even just for a trial, it was a mess to get out of the service again. Their Knowledge Base was outdated and gave misleading information. After more than an hour of frustrations, I could deactivate the account with the help from their support staff.

It’s not that I run a mission-critical blog here, let alone provide any essential knowledge whatsoever, so any downtime won’t bother me much. And it didn’t take long before I got acquainted with this message, and on more than one occation:

However, I like Tumblr’s simplicity and beauty. These are values I treasure and try to achieve when doing what I’m best at, designing and developing software.