A Quick Look plug-in for Provisioning

As every iOS developer knows, when your provisioning gets messed up, your life becomes a living hell. I don’t even want to think about how many millions of man hours have been wasted getting broken projects working again.

The root of the problem is always the .mobileprovision files that are kept in your Library > MobileDevice > Provisioning Profiles folder. The file either references a certificate that has expired or a device that no longer exists. There can also be issues with the entitlements that are contained in the profile when Team and App IDs don’t match.

A large part of the problem is that this file is not directly readable in a text editor like all the other parts of our Xcode projects. The file is encoded in the Cryptographic Message Syntax (CMS) described in RFC 3852.

After doing a bit of research, I found that decoding the payload of this file format is very simple thanks to some helpful functions in Apple’s Security framework. And once decoded, these .mobileprovision files contain nothing more than Property List (.plist) with a lot of useful debugging information.

I had previously been using a Quick Look plug-in from MacMation, but that site’s gone offline and the plug-in no longer worked in Mavericks. I had originally thought the problems on Mavericks were due to the new code signing requirements, but the root of the issue was that the content type UTI changed from com.apple.iphone.mobileprovision to just com.apple.mobileprovision so Quick Look ignored the old plug-in.

Eventually, I decided to write my own Quick Look plug-in and add a bunch of new stuff that I had been wanting to display:

  • Developer certificates: Making it easier to verify that your keychain items match what’s in the profile.
  • Provisioning Profile UUID: When someone on the project team checks in a new Provisioning Profile in the Build Settings, the only information you have is that UUID of that new file. Showing the UUID lets you find the right match.
  • Entitlements: Checking the Push Notification environment, ubiquity container identifiers, and keychain access groups is essential for any app that uses Apple’s services.
  • Links: Whenever the provisioning is broken you spend a lot of time in various sections of the Dev Center. Why not make it easy to get there?

The results of a few days work can be found on GitHub. If you’re lazy like I am, just download the .qlgenerator file and pop it in your Library > QuickLook folder. To get Quick Look to recognize the new plug-in you’ll need to either logout or poke Quick Look from the command line:

$ qlmanage -r

While you’re at the command line, do this to allow text to be copied from any Quick Look plug-in:

$ defaults write com.apple.finder QLEnableTextSelection -bool TRUE
$ killall Finder

(Macworld has more info about this nice hidden setting. Being able to copy text from a PDF preview is pretty damn handy!)

The next time you’re stuck in the Fifth Circle of Provisioning Hell, this simple plug-in may just bring you back to life. Viva!

Mac App Store Receipts and Mavericks

The storeagent and I aren’t getting along too well these days.

We’re in the process of getting a new release of xScope ready for release. As a developer tool, we’ve been compatible with Mavericks for several months now, but there are some minor bug fixes that we’d like to get out before the new version of OS X ships.

As you might be aware, this is the first time I’ve done a build on Mavericks itself. Things haven’t exactly been smooth sailing.

Today’s revelation is how storeagent creates the /Contents/_MASReceipt/receipt file in Mavericks. It’s subtly different, and will confuse the heck out of you until you understand what’s going on.

For the past few days, I’ve been testing a beta release of the .pkg using the standard command:

sudo installer -store -pkg /tmp/xScope.pkg -target /

This version had a CFBundleShortVersionString of “3.6.2b1”. The installer and receipt checking code was working great.

Until I did the final build and used the version string “3.6.2”. I got this message after I double-clicked the app and entered my Test User Apple ID:

After checking the code signing, bundle IDs and all other parts of the app, I finally fired up the debugger and discovered that the receipt validation code was failing when checking receipt attribute type 3, the Application version field (in Table 1-1).

After decrypting and checking the receipt payload, the value was “3.6.2b1” not the version I just installed. Where did this old version number come from? Why did following the advice in the dialog and deleting the app not fix the problem. How come this old receipt kept showing up no matter what I did?

Receipts from older versions had never been a problem in previous versions of OS X, so there must be some new behavior in Mavericks. And it took me almost a whole day to figure out that new behavior.

It turns out that storeagent is doing some kind of in-memory cache of receipts that have been downloaded from iTunes. Since a network connection is needed to retrieve the receipt, keeping it around would prevent a little bit of network traffic. In previous versions, the receipt was presumably recreated each time it was requested, so you always had a fresh copy.

The workaround is fairly simple. It even gives me a bit of pleasure at this point:

$ killall -KILL storeagent

You’ll need to delete the app at this point and re-install it using:

$ sudo installer -store -pkg YourApp.pkg -target /

When you relaunch your app, you’ll see the Apple ID login dialog. Since storeagent is launched on demand by launchd, a new process will be started at this point. After entering your Test User credentials, a new, and valid, receipt will be written into the _MASReceipt folder.

One could imagine this caching of receipt data being a problem with apps that are downloaded from the App Store. If someone never reboots between two versions of the same app being “Ready for Sale”, it may trigger the same problem. I have no way to test this hypothesis.

For any Apple folks that might be reading, here you go: rdar://problem/15283740

Code Signing and Mavericks

The Change

Very simply put, you can no longer sign a bundle (like your .app) if any nested bundle in that package is unsigned. These nested bundles are things like helper executables, embedded frameworks, plug-ins and XPC services.

The result is that you’ll need to update your Xcode projects as soon as you start building on 10.9. It’s taken me several days to understand what these changes are, and with the help of Perry Kiehtreiber on the developer forums, I’d like to share what I’ve learned.

(Yes, I realize this essay is going to break the NDA, but since Apple is asking us to submit apps for Mavericks, I want as many developers as possible to avoid the utter confusion I faced earlier this week.)

The Effect

So what happens when you do your first app build on 10.9 using Xcode 5.0.1? If you embed a framework that’s unsigned, like the very popular Sparkle.framework, you’ll see a message during the final CodeSign build phase:

CodeSign build/Release/xScope.app
    cd /Users/craig/Projects/Mac/xScope
    setenv CODESIGN_ALLOCATE /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/codesign_allocate
    Using code signing identity "Developer ID Application: The Iconfactory"
    /usr/bin/codesign --force --sign D2A3FE1814B0BA31B1924F1C3C3B5C89643FBED5 --requirements =designated\ =>\ anchor\ apple\ generic\ \ and\ identifier\ \"xScope\"\ and\ ((cert\ leaf[field.1.2.840.113635.100.6.1.9]\ exists)\ or\ (\ certificate\ 1[field.1.2.840.113635.100.6.2.6]\ exists\ and\ certificate\ leaf[field.1.2.840.113635.100.6.1.13]\ exists\ \ and\ certificate\ leaf[subject.OU]\ =\ \"RYQWBTQRPT\"\ )) /Users/craig/Projects/Mac/xScope/build/Release/xScope.app
/Users/craig/Projects/Mac/xScope/build/Release/xScope.app: code object is not signed at all
In subcomponent: /Users/craig/Projects/Mac/xScope/build/Release/xScope.app/Contents/Frameworks/Sparkle.framework
Command /usr/bin/codesign failed with exit code 1

** BUILD FAILED **

The codesign command is reporting that “code object is not signed at all” and Xcode is adding the “In subcomponent” to tell you which framework is at fault (it could just have easily been HockeyApp or any other third-party framework you use.)

So how do you go about fixing this?

The Wrong Way

In the past, many developers have relied on codesign‘s --deep option to make sure the entire bundle is signed. Specifying this option in “Other Code Signing Flags” will get rid of the error during the build, but all you’re doing is just postponing the pain.

The reason is that --deep recursively signs the nested bundles. As it does this, it applies the parameters for the top-level bundle to all the nested bundles. Things like your app’s entitlements will cause the resulting bundles to not be valid.

In fact, if you try to download and install the resulting app, Gatekeeper will notify your customers that your app is damaged and can’t be opened, with a default button to move it to the Trash:

You’ll see the same thing if you check the binary using the command line:

$ spctl --verbose=4 --assess --type execute build/Release/xScope.app
build/Release/xScope.app: a sealed resource is missing or invalid

The Right Way

What’s the right way to make sure the embedded framework is correctly signed? The answer is to add another Build Phase to your target.

If you’re embedding frameworks, you’ll have a “Copy Files” phase that moves things like Sparkle.framework into the Frameworks destination. Just after this Build Phase, add a Run Script with the following shell commands:

LOCATION="${BUILT_PRODUCTS_DIR}"/"${FRAMEWORKS_FOLDER_PATH}"
IDENTITY="Developer ID Application: The Iconfactory"
codesign --verbose --force --sign "$IDENTITY" "$LOCATION/Sparkle.framework/Versions/A"

This short script tells Xcode to sign the framework that’s just been copied into the build product. In this case, it’s using the Developer ID for Gatekeeper. If you were doing a build for the Mac App Store you’d use your “3rd Party Mac Developer Application” identity. Add a codesign command for every framework you use.

If you have other embedded code, such as helper executables, plug-ins or XPC services, you’ll need to sign them appropriately after copying them into your app bundle.

Updated October 18th, 2013: Another alternative is to set the code signing identity in the Build Settings of the frameworks you’re building from source. The trick here is that the identity of the framework needs to match the identity of the app itself. You can’t have have an App Store distribution identity for the framework and a Developer ID for the app. I found it much easier to explicitly re-sign the frameworks than to pass configuration settings from MyApp.xcodeproj to MyFramework.xcodeproj. It’s also easier to manage because the project changes are the same for binary-only frameworks (like Sparkle) and frameworks we build from source (like Chameleon).

The Checks

You’ll want to do a quick check of the build product before uploading it to either your website or iTunes Connect. The first thing you’ll want to do is check the signed bundle meets its designated requirement:

$ codesign --verify --verbose=4 build/Release/xScope.app
--validated:/Users/craig/Projects/Mac/xScope/build/Release/xScope.app/Contents/Frameworks/Sparkle.framework/Versions/Current/.
build/Release/xScope.app: valid on disk
build/Release/xScope.app: satisfies its Designated Requirement

If there’s a problem, you’ll see a message that the app “does not satisfy its designated Requirement”. To view information about the signed code or the designated requirements, you can use these commands:

$ codesign --display --verbose=4 build/Release/xScope.app
$ codesign --display --verbose=4 build/Release/xScope.app/Contents/Frameworks/Sparkle.framework
$ codesign --display --requirements - --verbose=4 build/Release/xScope.app
$ codesign --display --requirements - --verbose=4 build/Release/xScope.app/Contents/Frameworks/Sparkle.framework

If this is a build you’ll be uploading to your website, you’ll want to make sure it will be accepted by Gatekeeper (and not display the “damaged” dialog.) Use spctl to do this:

$ spctl --verbose=4 --assess --type execute build/Release/xScope.app
build/Release/xScope.app: accepted
source=Developer ID

If this is an App Store build, you MUST check the .pkg file that gets uploaded to iTunes Connect (see the next section and you’ll see why I say MUST.) If you use productbuild to create the package manually, you’ll already have a .pkg file to test.

For those of you who submit archives directly from Xcode, you can generate the .pkg file using the command line:

$ xcodebuild -exportArchive -exportFormat PKG -archivePath /path/to/your.xcarchive -exportPath /tmp/CHOCKS -exportSigningIdentity "3rd Party Mac Developer Application: CHOCK LOCK INK” -exportInstallerIdentity "3rd Party Mac Developer Installer:  CHOCK LOCK INK"

You can find the path to your .xcarchive by selecting it in the Organizer and then using the Editor > Show in Finder menu item. The command above will create a /tmp/CHOCKS.pkg. Yes, you now have CHOCKS PACKAGE IF YOU KNOW WHAT I MEAN

(A quick side note, if you use xcodebuild, it got a lot of love in Mavericks. Make sure to check out the man page.)

To check out CHOCKS.pkg, run the installer with the -store option:

$ sudo installer -store -pkg /tmp/CHOCKS.pkg -target /
installer: Note: running installer as an admin user (instead of root) gives better Mac App Store fidelity
installer: CHOCKS.pkg has valid signature for submission: 3rd Party Mac Developer Installer: The Iconfactory
installer: Installation Check: Passed
installer: Volume Check: Passed
installer: Bundle com.artissoftware.mac.xScope will be installed to /Applications/xScope.app
installer: Starting install
installer: Install 0.0% complete
installer: Install 13.8% complete
installer: Install 22.2% complete
installer: Install 47.6% complete
installer: Install 88.3% complete
installer: Install 100.0% complete
installer: Finished install

Now, sign out of the App Store and launch the app that was just installed in your Applications folder. If everything is OK, you’ll see the prompt for your Apple ID and a receipt will be written in the app’s _MASReceipt folder.

But not always.

(For more information on testing installer packages, check out the Testing section in my Mac App Store Guide.)

The Suckage

After being installed for the first time, some apps never get a receipt when they are launched on Mavericks. The app starts up, sees that there’s no receipt in /Contents/_MASReceipt and signals that it’s missing by exiting with a 173 code. Normally, storeagent will recognize this and prompt for an Apple ID. After valid credentials are provided, the receipt is written and the app is launched again.

Several developers, myself included, have noticed that after exiting with a 173, only the following is logged in the console:

Oct 17 11:59:03 Myrtle.local storeagent[72031]: Unsigned app (/Applications/Twitterrific.app).

If this happens to you, it seems your only course of action is to not validate the receipt. Your code will launch fine if you never return a 173. Which, of course, sucks because it’s then trivial to pirate your the app.

For any Apple folks that might be reading this, check out the Radar: rdar://problem/15254213

Updated October 18th, 2013: Developers that are doing their builds on 10.8 also need to watch out for this problem. As a workaround, I tried building the product on 10.8.4 using Xcode 5.0. The resulting .pkg exhibited the same behavior at launch time as the one created with the Xcode GM on Mavericks.

The Workarounds

Xcode sometimes has problems generating a valid designated requirement. When you check the designated requirement, you might see this:

$ codesign --verify --verbose=1 build/Release/Twitterrific.app
build/Release/Twitterrific.app: valid on disk
build/Release/Twitterrific.app: does not satisfy its designated Requirement

$ codesign --display --requirements - build/Release/Twitterrific.app
Executable=/Users/craig/Desktop/BugReport/Ostrich/build/Release/Twitterrific.app/Contents/MacOS/Twitterrific
designated => anchor apple generic and identifier Twitterrific and (certificate leaf[field.1.2.840.113635.100.6.1.9] /* exists */ or certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = RYQWBTQRPT)

If you look closely, you’ll see that the identifier used for the requirement is incorrect: it should be com.iconfactory.Twitterrific, not just Twitterrific. The workaround for this bug is simply to set the identifier explicitly in your Build Settings. In our case, we added --identifier com.iconfactory.Twitterrific to Other Code Signing Flags.

Updated October 18th, 2013: It looks like this bug happens when you precompile your Info.plist. Thanks to Chris Liscio for verifying that problem. Make sure to dupe it, if you’re affected!

As to why you’d want to precompile your Info.plist, there are two good reasons.

The End

There you have it: a short summary of my last three days of confusion caused by new Gatekeeper requirements, issues with Xcode and bugs in Mavericks. Hopefully, this essay will save you some of that same agony.

Cheap as in Computing

There’s a good case for an iPhone that costs less. But with this lower cost, developers fear that device specifications will suffer:

As someone who’s actively working on an iOS 7 update, I’m noticing a definite pattern emerging: we’re removing a lot of shadows, gradients, and transparency. A lot of views that were previously required to make an app look at home on iOS 6 are no longer needed.

The visual simplification of iOS has led directly to a simplified implementation. As every developer knows, the less work your app does on a mobile device, the better it performs. It’s a lot easier now to make an app that feels fluid and uses less CPU and GPU resources.

While everyone focuses on what Jony Ive has put on the screen, he’s also made the hardware under that screen able to do more with less. And yet again, Apple’s tight integration of hardware and software is going to kick everyone’s ass.

Updated August 14th, 2013: A lot of Twitter followers are saying, “But what about the live blurs? Aren’t those CPU/GPU intensive?”

Yes, they are. And you should also note that access to those features is strictly through private API. An iPhone 4 turns off blur, an iPhone 5C could do the same if necessary.

(If you look closely at the blur behind a toolbar, you notice that there’s some kind of sub-sampling of the screen image. Because this implementation is private, the algorithm could also be adapted for other devices.)

There’s also the question of all the new dynamics in the UI (like bouncy messages.) The highest costs in a GPU, both with computation and hardware components, is with dealing a lot of textures. The math for a physics engine is relatively easy to handle.

AMBER Alert Usability

If you live in the State of California, you got an AMBER Alert last night just before 11 PM. If you have an iOS device, you saw something like this on your lock screen:

Or like this in Notification Center:

And if you’re like most people, you had no idea what it meant. Considering it’s a broadcast to locate missing children, that’s a bad thing. Let’s examine the usability of this alert and think about how this system can be improved.

Updated August 6th, 2013: Lex Friedman has written a great summary of AMBER Alerts at Macworld. Among the revelations: the text of the messages are limited to just 90 characters!

First Impressions

In our household, there are many iOS devices. At the time of the alert, we were in the living room with two iPads and an iPhone. The alert’s sound is designed to get your attention, and that it did!

Both my wife and I gave each other that “what the hell is wrong” look as I grabbed my iPhone from my pocket. Turns out we weren’t the only ones who were frightened by the sound:

My wife’s first question as I looked at my phone was “Are we having a tsunami?” (we’ve had these kind of emergency broadcasts before.) I replied with, “No, It’s an AMBER Alert”. To which she replied, “What’s that?”

And therein lies the first problem: I had no idea.

Unlike all other notifications on my iPhone, I couldn’t interact with the alert. There was no way to slide the icon for more information or tap on it in the Notification Center to get additional information. Through a combination of Google and my Twitter timeline, I eventually figured it out:

But I was also seeing a lot of people on Twitter whose response to the confusion was to ask how to turn the damn thing off. And since AMBER Alerts aren’t affected by the “Do Not Disturb” settings, a lot of people went to Settings > Notification Center so they wouldn’t get woken again in the future.

That’s exactly what you don’t want to happen when a child is abducted.

Alert Text

In looking at the message itself, it’s hard to tell what it’s about. Starting an alert with an acronym may make sense to the government, but there’s wording that could resonate much effectively with normal folks:

It’s also hard to tell if this is a problem with “Boulevard, CA” or a “Nissan Versa”. And where is Boulevard? And what does a Nissan Versa look like? Who do I call if I see license 6WCU986? In summary, this notification provides more questions than answers.

This one image has answers to all of these questions and more. Why can’t I see that image after tapping on the notification?

The Alert Sound

As I mentioned above, the sound definitely let us know that something was wrong. But we were sitting comfortably in our living room. A friend of mine was driving at the time and probably listening to music from their iPhone on a car stereo. Being startled at high speed is dangerous:

Unlike the devices that existed when the AMBER Alert system was first introduced in 1996, our iPhones and iPads do a lot more than calls and texts. Music and video are immersive activities and hearing a loud horn can be a cure that’s worse than the disease.

Also, we’re all conditioned to immediately look at our phone when the normal alert sounds are used: a simple ding would have gotten just as much attention.

Do Not Disturb

And what the heck is up with this crazy sound happening if Do Not Disturb is turned on? Dammit, it’s my phone and I get to tell it what to do. Stupid Apple!

Well, take a look at your government first:

And if you want the details, it’s only going to cost you $205 to download:

Bottom line: these bugs aren’t going to be easy fixes.

(And if you think getting woken up because of an AMBER Alert is such a terrible thing, why don’t you explain your pitiful situation to this boy’s parents.)

File A Radar

Even though these bugs probably aren’t Apple’s direct problem, I’m still going to file a bug report. If you have a developer account, please feel free to duplicate that Radar.

Apple is in a very unique position to address these issues:

  • It has direct access to millions of customers and their mobile devices.
  • It employs many people with a deep understanding of how mobile devices are affecting our lives.

This is clearly a problem where cooperation between Apple, the Department of Justice, and the public can improve a system where everyone benefits. Better usability with AMBER Alerts is case where “think of the children” isn’t a trite platitude.