July 2008 Archives

Code Signing

| No Comments

I recently went through the process of making our applications signed which is something that’s new to¬†Leopard.

I just wanted to mention a few things that I came across and aren’t necessarily in Apple’s documentation.

Signing Frameworks

When you sign frameworks, you have to sign a specific version. So, let’s say your framework is called CSMail, you’d sign CSMail.framework/Versions/A. If you try and just sign the top level folder it will silently fail, as will CSMail.framework/Versions/Current (see “Symbolic Links” below).

Symbolic Links

Any symbolic links will be silently ignored and this extends to the path you give to the codesign command line utility. I think there’s actually a problem with symbolic links: you can add them to a Resources folder and it won’t invalidate the signature (whereas you cannot add normal files). I’ve reported this to Apple (rdar://problem/6050445).

Resources

Everything in the Resources is signed according to resource rules. You can see what the default rules are by signing something and having a look at the end of the generated CodeResources file. Here’s a bit from the default rules:

<key>^Resources/.*\.lproj/</key>
<dict>
    <key>optional</key>
    <true/>
    <key>weight</key>
    <real>1000</real>
</dict>

It should be clear that this means that all the .lproj folders in the Resources folder are optional which allows you to strip out unneeded localised files.

You can use your own rules if you need to; the resource rules file that you pass in to codesign is the same as the CodeResources file but with just the rules key. We needed to omit a particular file that might get installed in the Resources folder by an old version of our application when upgrading to a newer version. Using custom rules isn’t officially supported by Apple but I cannot imagine it will be broken for a while (as it would affect many Apple applications). Nevertheless, there’s no point using them unless you need to.

Helper Tools

Since helper tools should be separately signed, they shouldn’t be placed in the Resources folder, they should go in the MacOS folder if they’re simple tools or the Contents folder if they’re bundles.

When you sign helper tools (that aren’t bundles), you’re supposed to add an Info.plist to the executable although I’m not sure why you have to do it since you can specify an identifier as a parameter to codesign. Apple’s documentation shows a way to add an Info.plist file using the linker but I wrote a script that creates an object file from an Info.plist file. The advantage of doing this is that you can configure Xcode to run the script and it will properly track the dependencies whereas if you just add it as a parameter to the link command, modifying the Info.plist file will not cause things to be rebuilt. The script has the added benefit of expanding macros in the Info.plist file which we use to substitute things like the current project version.

The other issue we have is that we use the same helper tools for different variants of our main application. For example, we have iDefrag, iDefrag Lite, the demo version and a specific version for one of our customers. Each of those variants has a different bundle ID and we want to use that same bundle ID for the helper tools. Rather than have four different targets for each helper tool (we have 4 different helper tools so we’d end up with 16 different targets), I wrote a simple tool that updates the bundle ID within an embedded Info.plist file (source is here). One thing to watch out for is that it cannot increase the size of the embedded Info.plist file; you must make sure that the bundle ID only decreases in length. Also, it only works for 32 bit architectures since we have no need for 64 bit architectures at the moment.

I hope this helps someone.

Disabling Menu Items

| No Comments

Joel Spolsky recently posted an article about disabling menu items and this met with negative responses from John Gruber and Daniel Jalkut.

I think Joel has an interesting point. Whilst I agree with John and Daniel that it’s bad if you can’t tell if a menu item is disabled, there have definitely been cases where it’s not been clear to me why a menu item is disabled and some kind of indication would have been helpful.

A related issue came up with one of our products, iDefrag. In earlier versions we had a “Go” button on the toolbar that was disabled when it wasn’t possible to start defragmentation and the usual reason for that was that it was because you can’t defragment the disk you booted from. We got no end of support about this so we changed the button so that you could still click it but the button was displayed in red (rather than green) to indicate that it wouldn’t work. If you click the button, a message is displayed informing you why you can’t defragment and what to do about it.

Taking this approach for menus would mean that you would be able to click a menu item, but it would still be displayed differently. I’m not sure whether that’s a good idea or whether a different approach would be better, such as using tooltips to indicate what the reason is.

For what it’s worth, I think John’s comment:

This is why Spolsky is a Windows developer, not a Mac developer.

is offensive and incorrect. Just thinking about this issue makes it exactly the kind of attention to detail that all developers should aspire to.