The Future Of Mac App Store Installs
January 7th, 2011It’s only been one day since the launch of the Mac App Store, and the Mac developer and user communities are buzzing with consequences, both good and bad, of the store and how it operates.
One particularly vexing issue is the question of whether an app that is already on your Mac is “installed” or not in the eyes of the App Store application. Dan Moren of Macworld presents a great summary of the situation.
In a nutshell: if App Store thinks an app is installed, it’s impossible to buy it. If App Store thinks an app is installed, but it’s not really from the App Store, there’s a risk of repurchasing something that you already own a license for.
What this brings into focus is the very problematic nature of that small multi-purpose button the App Store, that allows for either buying an app you don’t own, or for linking to an app that you do own:
As it happens, the App Store user interface is implemented primarily in HTML. Using a surprisingly under-appreciated feature of WebKit, the omnipresent web inspector, I was able to look behind the scenes at some of the interesting HTML that supports this Buy/Installed button. For Black Ink’s button above, this is what I see:
<button version-string="1.2.3" is-rental="0" is-pre-order="0"
buy-params="productType=C&price=24990&
salableAdamId=402376365&pricingParameters=STDQ"
preflight="http://a1757.phobos.apple.com/us/r1000/ 057/Purple/e7/fb/12/mzm.gytejomu.pfpkg"
is-install-button="0"
large-icon="http://a1.phobos.apple.com/us/r1000/013/ Purple/74/8c/bb/mzi.wpgwhzjm.170x170-75.png"
is-update="0" item-name="Black Ink" adam-id="402376365"
is-free-download="0" bundle-id="com.red-sweater.blackink.macappstore"
metrics-leaf="1" metrics-loc="Buy" title="Buy, Black Ink: $24.99"
disabled="" its-bound="iTSBuyButton">
<span class="price"></span>
<span class="action">Installed</span>
</button>
Formatting XML, even with a cool app like MarsEdit, is still a huge pain. I’ve tried to make it readable here so you can enjoy some of the interesting tidbits in this markup. There are some tantalizing attributes like is-update and is-free-download, which might lead some of us to imagine whether a paid update may be a configuration away. There’s some hocus-pocus sale parameters which surely mean something to iTunes on the other end of the network connection, and there’s a link to the application’s pretty icon.
Wondering about that global web inspector trick? Any application that has the NSUserDefaults key WebKitDeveloperExtras defined to YES receives access to the sexy WebKit web inspector that is so awesomely utilized in Safari. You can define this for the App Store app by running this from the command line in a Terminal window: defaults write com.apple.appstore WebKitDeveloperExtras -bool true Make sure you quit App Store before you run it, then relaunch it.
But What’s Really Interesting…
All of this is fun to poke around at, but what I find fascinating is the preflight attribute, which points to a mysterious asset on the web. This “.pfpkg” file, which as it turns out is simply xar archive format, contains an interesting file called Distribution, an XML-formatted file that contains rules and attributes for how the application should be installed, how the App Store should locate an “Installed” app on the user’s Mac, etc. I’m not going to the trouble of color formatting this one, but have a look in a separate window:
View Black Ink’s Preflight Rules
I believe the format for this XML document is either completely or partially tied up in the way the Mac OS X Installer packages work. I have been lucky enough in my lifetime not to have to do all that much with installer packages, so I am not sure exactly how to parse the whole file. It’s clear however, that the file contains information about the application, its version and bundle identifier. It also contains similar information for each of the frameworks that ships with the application.
But the interesting stuff begins below that, where we see flags such as customize=no, and an alluring volume-check, which seems to be terminology from Installer-land that alludes to installers being able to determine whether the targeted volume is suitable for installation.
As you can see, the Black Ink preflight document is pretty boring. No, there is no customize flag. No, there are no interesting volume-check attributes, aside from the fact that this requires 10.6.6, like every other dang app on the Mac App Store. Yawn.
I decided to take a look at another application in the App Store. One that, if anything was going to be interesting, surely this one would be.
One of the things I keep reminding myself, when trying to deduce what Apple’s plans are for a variety of “would be nice” features in the App Store, such as upgrades, trials, etc., is “how does the current setup inconvenience Apple itself?” Many of Apple’s apps are shipped for free with the system and are updated for free along with OS updates. But others are not: iLife and iWork are sold in a bundle with no upgrade pricing, and other apps such as Final Cut Pro and Logic have complicated pricing, which perhaps explains why they aren’t on the App Store at all. But Aperture falls right in the middle: fairly straight-forward pricing, but it’s expensive enough that they offer reasonable upgrade charges for users who already own a license. Maybe there will be something interesting in these preflight rules:
View Aperture’s Preflight Rules
The file length alone indicates that something slightly more complicated is going on, and my eyes are drawn immediately to the JavaScript code in the middle of the document, and a function named shouldAllowPurchaseAndInstall(). Hmm, you mean there’s a choice? Usually what happens when you click “Buy” in the App Store, is you are prompted to login if necessary, and then you are warned that this is going to cost you money, it’s a big deal, etc. But as far as I can tell, a side-effect of clicking Buy in the App Store is that the aforementioned volume-check is also run on the target system, giving App Store one last chance to bail out of the process before something unfortunate is done.
In Aperture’s case, you can see by the nicely commented script that it takes care to only allows the Buy order to go through under certain circumstances. In making this determination, it checks all of the installed copies of Aperture on the system, looking for signs of App Store purchase such as the presence of a “_MASReceipt” inside the app. It also takes care to differentiate between different versions of Aperture, failing in some cases with a specific string that is presumably passed along to the App Store user.
If you’ve managed to follow along this far, you’re probably putting two and two together and realizing that the technology exists today for applications to avoid at least one of the problems mentioned above: the inadvertent redundant purchase that may happen when a user thinks it’s safe to buy an app, because “they already have a license.”
The preflight XML document may be documented in part or in full in the context of Mac OS X Installer Packages, but as far as I know, none of this is documented in the context of the Mac App Store. I do not know if any 3rd party developer has been invited to use this technique, or if it’s something we could just put into our installer packages somehow on our own, and hope for the best.
What’s most interesting about all this is that there is clearly an infrastructure in place for allowing a wide variation of behaviors, all centering around the multi-purpose Buy/Installed button in the App Store. I would like to see the volume-check options documented and made explicitly available to developers, so that we can help prevent unwanted redundant purchases on the part of our customers. I would also be curious to know if other hooks are in place or are planned to for example allow developers whose apps do show up as installed to second-guess that assumption and encourage the App Store to provide a “Buy” option to customers.
Where we’re going, only Apple knows, but I thought the details I discovered in this nook of the App Store app offer some interesting clues. I’m also interested in sharing this because I believe that the more we understand about the App Store install process, the better we’ll be able to offer meaningful enhancement requests to Apple. “Support paid upgrades” and “Allow variable behavior depending on installed apps” are fine feature requests, but if we are able to put them into the context of what Apple already knows is possible, they may be more likely to get implemented.
If anybody else has delved into the underbelly of the App Store and has observations to share, please do so in the comments, or with a link to your own blog article on the subject.
January 7th, 2011 at 6:50 pm
Yeah, it would be foolish for Apple to launch a service like this without at least thinking through these scenarios. What I don’t get is why they wouldn’t make them available to third party devs. Possibly, not all the kinks are worked out yet? For all the headaches the App Store is supposed to solve, it really is introducing a lot of new ones.
January 7th, 2011 at 6:59 pm
Nice research! So maybe users won’t have to trash their trial versions either before or after buying from the App Store for too long!
January 7th, 2011 at 7:19 pm
I’m curious why there is a string in German in the Aperture Preflight Rules. The string ‘Begrenzt_ist_aktiviert’ means ‘Restrictions Activated’ but it sounds much more serious in German.
Is this developed by Apple in Germany? Are there special use cases for apps sold in Germany (they have a law regarding DRM)? Or is this just a bit sloppy and rushed out the door?
January 7th, 2011 at 7:36 pm
@mare:
There are a ton of german developers working at Apple in Cupertino, so one of them might just have used his mother tongue.
January 7th, 2011 at 7:49 pm
I’m really curious if Apple is doing anything special with their Apps. I know that iWork has a ton of shared frameworks when you install of the disk, and GarageBand installs all of those loops into the App Support folder. Both of these violate App store terms, so did they re architect these apps or are they just blatantly disregarding their own rules?
January 7th, 2011 at 8:14 pm
I’m curious: how did you enable the web inspector for the App Store app?
January 7th, 2011 at 8:17 pm
Err, never mind; I skipped right past the very obvious instructions for enabling it. Durrr.
January 7th, 2011 at 9:18 pm
It would be really great if Apple would support paid upgrades from trial versions. Customers really like the “try-before-you-buy” model. Further, this model supports more sustainable price-points for applications that involve significant effort to develop.
January 7th, 2011 at 9:48 pm
At my day job, we enable games for the Mac. Games can have pretty wild system requirements, especially on the video card level. Hey, that spiffy ATI X1600 that you bought 4 years ago is a piece of junk now that probably won’t play the latest DragonAge you know!
So I’d like to see this expanded so we could preflight a system to tell the user “this game won’t run on this system, no need to press Buy”…
We can put this information in the info blurb, but most people barely know which kind of Mac they have (“it’s an iMac!” “Which one?”), they definitely don’t know what video card they have.
And that’s absolutely critical for games…
January 7th, 2011 at 10:37 pm
This is all standard stuff. The Distribution file is part of the regular .xar archive created by the PackageMaker application. The only thing we didn’t know ahead of time was that the preflight methods we defined would be run *before* the user was billed.
Now that we can see that is the case, we know that it’s safe for us to build these things into the installer package.
For reference, open PackageMaker. There are all sorts of validations available already, including hardware tests, etc. You can write your own scripts in straightforward JS too. This has been part of the OS X Installer system for a while now (since 10.4 I think).
January 7th, 2011 at 11:21 pm
There’s another piece to this I’m curious to learn about: how the buy button state is determined for Apple’s apps. If you run the App Store with an old version of iLife or iWork installed you’ll still get the option to buy even though the bundle IDs match. From what I can see the preflight archive isn’t downloaded until the user actually clicks the buy button, nor is there any additional JavaScript loaded in the store page, yet a check similar to to the preflight script is being run to support the paid upgrade.
January 8th, 2011 at 12:49 am
I believe Apple should provide upgrades for those apps that it’s now showing as installed. It avoids customer confusion and it’s a way for users to move their license to the Mac App Store which in turn means customers get used to only upgrading and purchasing in the Mac App Store. If a developer does want to keep separate version he would use separate bundle identifier for each distributions. Updating apps Apple never originally took a 30% commission on is costly, but no more than serving up free movie trailers and it does vastly more to improve the Mac experience.
January 8th, 2011 at 1:26 am
Am I the only who finds it interesting that apple is using html5 for this app, and not their own objc/cocoa…
January 8th, 2011 at 7:02 am
Neat trick with the Inspector, Daniel. As part of my investigation for TUAW (http://www.tuaw.com/2011/01/06/mac-app-store-by-the-numbers-almost-1-000-apps-on-day-one/) I went a different route and captured the raw HTML of every store category page with a proxy sniffer. This allows statistical analysis across all the Buy buttons in the store. If you think you can use this data for anything (for example looking for other anomalous Javascript), let me know.
January 8th, 2011 at 9:59 am
@Didier It’s not all that interesting. Apple uses HTML all over the place for UI in place of Cocoa. The email display in Mail, the chat view in iChat, the iTunes store. HTML, CSS & JS are a very good set of technologies for *displaying* content. If you want to display some data in a largely readonly way but with a custom appearance, then HTML is better than Cocoa. But when it gets to more complicated UI then Cocoa is used as it is more powerful.
Basically, it is using the strengths of one to cover the weakness of the other in both cases.
January 8th, 2011 at 11:17 am
Interesting read, coming from someone with absolutely no developer background, I’m just a user.
However, there is one thing that I find annoying with MAS (and Software Update) that I would like to see a solution for. I placed all the iLife apps into a folder that I put in the dock (Applications>iLife) obviously saving Dock space but still convenient. MAS showed iPhoto, iMovie and Garageband as available for purchase. Software Update would NOT show any of them available for update. Moving them back into the Applications folder solved both, but is a pain in the ass otherwise
It seems like this would be solvable with something like iTunes needing to have a song relinked.
January 8th, 2011 at 10:15 pm
I currently have Aperture 3 installed on my machine (as a trial version) but I have never activated the 30-day trial code Apple sent me, due to a lack of time to test. The Mac App Store thinks that Aperture is installed and therefore prevents me from buying it.
I’m not sure if activating the demo will lead to being able to buy the software once the 30-day trial is over. Another thing to test.
January 10th, 2011 at 4:46 pm
JD: You just need to make a folder of aliases. Create an empty folder, then Command-Option-drag the applications you want accessible from the Dock into that folder; drag the folder to the Dock. Viola! The originals will remain where MAS and Software Update expect to find them, but you can also access them from the Dock.
January 14th, 2011 at 10:11 am
The line of most interest to me as an Aperture user is this which points at an upcoming v4.0 of the product?
if ( system.compareVersions( info.CFBundleShortVersionString, “3.0” ) >= 0
&& system.compareVersions( info.CFBundleShortVersionString, “4.0” ) < 0 )
March 22nd, 2011 at 7:02 pm
10.6.7 no longer shows apps as installed that were not downloaded from the app store. When “buy” is clicked, a prompt is displayed saying you have it from somewhere else, with the option to re-buy it through the app store.