Disclaimer: there are aspects of the App Store approval process I find utterly appalling, particularly the stealth “no competing with Apple” unwritten rule.
Nevertheless, here’s a mental exercise for you. Consider the user-facing download-to-own software stores offered by the game consoles: Wii Ware, XBox Live Arcade, and PlayStation Network.
In what way is any Apple App Store policy more onerous than these stores’ developer policies?
Here are some links to help you research:
- To become an Authorized Developer for Wii, WiiWare and/or Nintendo DS/DSi
- WELCOME TO MICROSOFT CASUAL GAMES!
- SCE DevNet (almost utterly opaque… see also Developing for PS3 PlayStation Network (PSN))
Once we get past the much more expensive licensing, the pre-vetting of both product ideas (Microsoft: “Email mcg@microsoft.com with a description of your game and your contact information. We’ll send you a content submission form.”) and developers (Nintendo: “the authorization for Wii/WiiWare or Nintendo DS will be based upon your relevant game industry experience.”), and the fact that these platforms generally reject entire classes of applications (anything that isn’t a game)… I think it’s interesting to compare the anger and fury vented over the App Store, and consider that almost nobody is railing against these stores, even though they’re much more closed than Apple’s platform, and may collectively reach more users.
We might also do well to note how closed mobile development was before the iPhone. I know I’ve told this story before, but in a JavaOne conversation with O’Reilly people about how to get Java ME books moving, I said that everyone with an interest in ME (myself included) had figured out that getting your apps to end users was effectively impossible, and that with the network API often disabled for third-party apps, there wasn’t much point in writing ME apps anyways. My suggestion for an ME book that would move copies would be one which provided “the names, e-mails, and phone numbers of all the carrier and handset executives you’d have to go down on in order to get your apps on their phones.”
So, I spent first five months of this year on a grueling, panic-driven-development project on Mac OS X. As my longest single Mac engagement, I’m afraid this can’t help but wear down my enthusiasm for the platform.
It doesn’t help that what I was working on was well into the edge-case realm: our stuff needed to silently update itself in the background, which gets into the management of daemons, starting and stopping them at will. This isn’t bad in theory, but getting it to work consistently across 10.4 through 10.6 is grueling. An always-on daemon sets a RunAtLoad property in its /Library/LaunchDaemons plist in order to come up immediately and stay up. Uninstalling and/or replacing such a daemon is tricky, as launchd keeps track of what daemons it has loaded and thinks are still running. The worst thing to do is to just kill the process… instead, you need to use launchctl to load or unload the daemon as needed. And, as a root-owned process, you need to perform this launchctl as root. Oh, and you’d better not delete the plist before you unload the daemon, since launchctl takes the path to the plist, so doing things in the wrong order can leave you with rogue daemons you can’t unload. And if you don’t unload the old daemon, a new launchctl load does nothing, as launchd thinks the original daemon is still running.
Now throw in some user agents. These are like daemons, except that they run for each user at login, and are owned by the user. So to uninstall or update, you need to launchctl unload as each user. Which is possible with sudo -u username in a shell script, unless you’re on 10.4 and you get the user list from /usr/bin/users, as the 10.4 version truncates user names to 8 characters, breaking the sudo.
Oh, and who’s doing these unloads? A script in an .mpkg installer. Which is a whole ‘nother bundle of fun, given how fabulously broken is Package Maker, Apple’s utility for creating .pkg and .mpkg installers. Package Maker crashes frequently, doesn’t consistently persist (especially when source-controlled) settings for file ownership, and creates broken installers when invoked by the command-line utility /usr/bin/packagemaker, making it utterly unsuitable for use in Makefiles or other automated build processes. IMHO, Package Maker is as big an ass-muffin as I’ve ever seen come out of Cupertino, at least since that quickly-pulled iTunes 2 release that reformatted the host drive.
Working with all these taped-together technologies — desperately trying shell script voodoo in an .mpkg post-install step to make things right — eventually wore me out. And granted, this is an edge case: most Mac apps can be distributed as app bundles without installers, and most installers can require the user to restart if it’s making radical changes like installing or updating daemons (not an option for me because the installer runs in the background, called by another daemon). Still, it’s enough to make you long for the “curated”, locked-down walled garden of the App Store, whose distribution and update system really does work remarkably well.
With the Mac all but expelled from this week’s WWDC, some pundits are happy to declare the death of the Mac. That’s a silly overstatement, but it is sensible to accept that after a decade of improvement and marketing, the Mac is a mature platform, likely secure at its 10%-or-so market share. What else would we want Apple to do with the Mac? I’d like to see things fixed and cleaned up, dubious legacies cleared out and things set right. And Apple has done that. Problem is, the result is not Mac OS X 10.7, it’s iOS 4.
But then again, if the iPad replaces the laptop for some number of users, this is a brilliant way to grow Apple’s share — nibbling away at traditional computers cannibalizes the Mac somewhat, but chows away mostly at Windows.
Suffice to say I’m very happy to be re-orienting myself to iPhone/iPad/iPod-touch development. It’s got the feel of a somewhat clean start, based on proven technology, but not burdened by old breakage. Now I’ve got some catching up to do to adapt to all the changes in iOS 4.
- Fanaticism consists in redoubling your effort when you have forgotten your aim.
- George Santayana, Life of Reason (1905) vol. 1, Introduction
A few weeks back, I asked the Twitterverse “When did user-facing Linux become completely and officially irrelevant? Seems like a fait accompli, doesn’t it?”. With the OSS community’s reaction to the iPad, I’m now sure of it.
And by reaction, I’m of course thinking of the response by the FSF’s John Sullivan to Steve Jobs’ much-discussed Thoughts on Flash. Sullivan’s piece is a straightforward “pox on both your houses” take, damning Apple and Adobe alike for not adopting the One True Faith of Open Source Software.
I had allowed myself to hope that the OSS community would take the hugely successful launch of the iPad and the flight of developers to the iPhone OS platform, even with Apple’s cravenly self-serving App Store policies, as an opportunity to take a good, long look in the mirror. With iPad sales now already estimated at over a million, you have to wonder how soon use of this nascent platform will exceed that of desktop Linux, if it hasn’t already. What should the open source community think of this profound preference for the unfree over the free? I would think they’d see it as a very public, and very obvious repudiation of the party line, suggestive of an urgent need for some soul-searching and time to re-examine how the OSS community is engaging the world at large.
Sullivan’s piece, sadly, shows no such self-awareness. It’s the usual total detach from real people that we’ve come to expect from True Believers. Indeed, the last third of it is the all-too-familiar zealous denunciation of all proprietary software, calling on readers to adopt Linux and Ogg Theora.
Seriously, Ogg? They’re still clinging to the “everything should be in Ogg” kick? OK, let’s ask the people who should know on this one, content professionals, to see if they buy in at all. DV magazine’s website logs 0 hits in searches for Theora and for Ogg, StreamingMedia.com’s 11 hits (versus 248 for H.264) are largely related to codec politics and not mentions in training articles or product reviews, and legendary retailer B & H assumes the search term theora is a misspelling of “theory”. No matter how many essays and insults the zealots spew forth, they seem unable to generate any inkling to know or care about Theora among video professionals.
In effect, the FSF’s position is to tell the world “screw you for not wanting the stuff we produce”, oblivious to the fact that the marketplace of ideas is very clearly telling them “screw you for not producing the stuff we want.”
The quote at the top of this article was often cited by Chuck Jones in describing the character of Wile E. Coyote, who was never afforded a moment of clarity to reconsider his hunting regimen, the inherent dangers therein, and the prospects for a way of life that didn’t involve falling off cliffs every 30 seconds. I fear the OSS community is so wrapped up in their own self-righteousness, they are similarly immune to equally-needed moments of humility, clarity, and perspective.
At the beginning of the month, I spoke at 360iDev in San Jose. I’d wanted to do a go-for-broke Core Audio talk for a long time, sent in an ambitious proposal, and got accepted, so this was destined to be it. Now I just had to come up with something that didn’t suck.
Luckily, there was another Core Audio talk, from Robert Strojan, that did a high-level tour of audio on the iPhone, with two deep dives into OpenAL and Audio Units. So that got everyone ready.
I called my talk Core Audio: Don’t Be Afraid To Play It LOUD (from a caption in the liner notes to Matthew Sweet’s Girlfriend), and went with the no fear angle by focusing almost entirely on audio units. The idea being: you’ve seen these low-latency audio apps that do crazy stuff, you know it must be possible, so how? The answer is: you involve yourself in the processing of samples down at the audio unit level.
Click through the 170+ slides — it’s not that bad, I just expanded all the Keynote “builds” into their own slides — and you’ll get the basic grounding in the stuff you always have to do with audio units, and the Remote I/O unit in particular. Stuff like finding the component, getting an instance, setting properties on the input and output scopes to enable I/O and set an AudioStreamBasicDescription, things you will get as used to as implementing init and dealloc in an Obj-C class.
The big win is the examples, which came together in a hideous mess of two spaghetti code files that I’m embarrassed to say are now in the hands of all the attendees. One reason for the blog entry you’re reading is to present cleaned up versions of the five sample applications from the session.
In the past, I’ve done an audio unit example that produces a sine wave by cranking out samples in the callbacks. It’s sort of like the hello world of audio in that it gets you down to the nitty-gritty of samples without too much pain, but it doesn’t play to a crowd all that well. FWIW, the second chapter of the Core Audio book writes a sine wave to a file, again to get you thinking about samples as soon as possible.
But for this talk, I decided to do a set of examples that work with audio input. That way, we got to play with the mic and the speaker — bus 1 and bus 0 for you folks who already know this stuff — and get some halfway interesting audio.
The first example goes through the drudgery of creating and initializing the Remote I/O unit, and connects bus 1 output to bus 0 input to do a pass through: anything that comes in on the mic goes out the speakers. I used to do this with an AU Graph and AUGraphConnectNodeInput(), not realizing it’s easily done without a graph, by just setting a unit’s kAudioUnitProperty_MakeConnection property. With that, I could speak into the simulator and get audio out over the PA (or into my device’s mic, but I used the simulator because it shows better).
Well, yay, I’ve turned the iPhone simulator into a mediocre PA system. What’s next. The key to the good stuff is to be able to involve yourself in the processing of samples, so the next example replaces the direct connection with a render callback. This means we write a function to supply samples to a caller (the Remote IO unit, which needs something to play). In the basic version, we call AudioUnitRender() on the IO unit’s bus 1, which represents input into the device, to provide samples off the mic.
Still boring, but we’re getting there. Instead of just copying samples, example 3 performs a trivial effect by adding a gain slider, and applying that gain to every sample as it passes through.
Now we can apply any DSP that suits us as samples go through the render callback function. In example 4, we apply a ring modulator to the samples, which combined a 23 Hz sine wave with the input signal from the mic to create a reasonably plausible Dalek voice.
Dalek voice demo:
I was pretty much over time at this point, but the last example is too much fun to miss. To show off other units, I brought a multichannel mixer unit into play. On bus 0, it got a render callback to our existing Dalek code. For bus 1, I read an entire LPCM song into RAM (which is totally bad and would blow the RAM of earlier iPhones, but I couldn’t get the damned CARingBuffer working), and provided a render callback to supply its samples in order. The result, infamously, is “Dalek Sing-A-Long”:
Dalek-sing-a-long demo:
Anyways, great conference, great speakers, great attendees. Thanks for reading, and here’s the code:
Last weekend was the Voices That Matter: iPhone Developers Conference in Seattle, put on by Pearson, who’s publishing our Core Audio book. However, co-author Kevin Avila handled the Core Audio talk for this conference, so I took on two topics that I had fairly deep knowledge of, thanks to my work on Road Tip.
Core Location and Map Kit: Bringing Your Own Maps
This talk starts with a basic tour of Core Location’s more or less straightforward means of getting information about your current location, getting updates as the data gets better (i.e., GPS kicks in) or you move. Then we got into Map Kit and how to get map images of any given location. The sample app for this takes a list of Apple Store locations, which I converted from CSV to a plist and stuck in the app bundle, and shows you the nearest store to a given start location. Each time you hit a + button in the nav bar, it drops the next closest store as a pin on the map and re-scales the map so that all pins are visible.
This is where it gets good. Starting from a canned location at my house, the closest Apple Store is here in Grand Rapids. The next two that come up are outside Detroit (Ann Arbor and Novi). The fourth closest store is in Milwaukee. The comedy is when you see this on the map — Milwaukee is close only if you ignore the fact that going there would involve driving 100 miles straight across Lake Michigan. Since ferries across the lake are slow and expensive, and run only in Summer, you would probably drive through or around Chicago to get to Milwaukee… and go right past 7 Apple Stores in the process.
This is a common mistake to make — I forgot to show in my slides that the apple.com retail store finder does the same thing. Still, as-the-crow-flies distance calculations, paired with map images, can be a problem. Map Kit doesn’t know anything about roads, bodies of water, geographic features, political borders, etc… all it does is serve up images, and provide a touch UI to interact with them.
The last third of the talk is about “bringing your own maps”, meaning integration with third party map data providers to get some navigational intelligence into your app. The final code sample uses the MapQuest directions web service to get actual driving distances to the first few hits, and to keep the list of locations sorted in order by driving distance. This not only keeps me from going to Milwaukee, it even smartens up the earlier results: being right on I-96, the Novi store is now my second closest result, and as it turns out, even Indianapolis is a shorter drive than going around the lake to Milwaukee.
- Slides (on slideshare.com)
- SimpleCoreLocationDemo.zip
- AppleStorePOIMapper.zip
- MQAppleStorePOIMapper.zip
In-App Purchase: Best/Worst Thing Ever
My second talk was on In-App Purchase. In many ways, it covered the same hard-earned experience that I covered in An In-App Purchase Brain Dump. I spent a little time on both the iPhone Provisioning Portal (to set up an AppID, authorize it for I-AP, and provide enough of an app submission to create purchase objects, without actually going into the review queue), and on iTunes Connect (creating purchase products). The sample app simulated an online social game, minus the game, in which users might be able to purchase digital goods like virtual clothes for their avatar. The example offered a tabbed UI with a blank view for the game, a table of purchased objects, and a table for the store. When you tap “store”, the app collects the available products with a call to Store Kit, and tapping one of them kicks off the purchase. If the purchase goes through, the item is added to the inventory page.
Of course, this is easier and demos better because it uses non-consumable products, which have always been the best-understood and best-supported class of I-AP products. I did weigh in against the still-broken subscriptions, and how they have to be restored to a user’s many devices, even though restoreCompletedTransactions doesn’t support subscriptions, and nothing in Store Kit gives you a key you can associate with the user to save the purchase on your own server.
Erica Sadun talked with me before this session and mentioned an interesting workaround. Get your user to purchase a non-consumable item, and persist its transactionId. When they purchase subscriptions, log the purchase and this other transactionId on your server. Then, when they restore on another device, they’ll get this non-consumable back and its transactionId, which you can then use to query your server for subscription purchases. Depending on the nature of your app, and how well you hide the clunkiness from the user, this could be a very viable workaround.
That said, I still think I-AP subscriptions suck and hope that Apple deprecates them soon.
The last part of the talk covers of doing commerce without I-AP, which is more viable than you might think. If you’re already selling digital goods from a web store, you can continue to do so, and make your iPhone app a rich client to your web-vended content. In this case, you’re already doing everything that I-AP offers, so there’s no reason to give Apple a 30% cut. For example, the various e-bookstores within Stanza don’t use I-AP — they go out to websites for O’Reilly, All Romance Books, etc., to complete the purchase. This might not be allowed for an iPhone-only app, but where the goods are available in multiple forms, it only makes sense for Apple to allow an iPhone app to be a rich client to such a store’s goods.
My final example is streaming anime: Crunchyroll sells premium content subscriptions on their website, and their free iPhone app lets you use the same login to get the same content. By contrast, The Anime Network has premium subscriptions on their website and via I-AP in their paid iPhone app, and credentials aren’t shared between the two. Worse, the iPhone app offers fewer videos for the same price. Their use of I-AP is bad for them (they’re paying Apple to process payments they’re already capable of handling), and bad for their users. WTF?
- Slides (on slideshare.com)
- VTMPurchaseDemo.zip
Coming next: my 360iDev slides, and the much-anticipated cleaned-up Core Audio sample code
I just got back this morning on a red-eye from 360iDev (sorry, no link; not practical to do lots of HTML editing on the iPad, which I’m typing this on) and wanted to get a few thoughts out before I collapse from sleep.
It was so nice to get back into the world of iPhone OS, as I’ve been working on a day-job contract on the Mac, with far too much exposure to the broken parts of that platform, principally the installer technologies. The cleanups and relative lack of legacy entanglements make iPhone a more pleasant platform to develop for.
The conference organizers did a bang up job of getting top tier speakers and attendees. In a final panel, the speakers were nearly all people whose apps I used: Doodle Jump, Air Sharing, and so on.
It was also nice to run into my co-author on the iPhone book, Bill Dudney, his predecessor in iPhone evangelism, Matt Drance (who, in an ironic life swap, has replaced Bill in the Pragmatic Studio seminars), MapQuest’s Carl Edwards, Double Encore’s Dan Burcaw, and three fellow members of the Ann Arbor CocoaHeads group: Tom Hoag, Dan Hibbets, and Henry Balanon.
I did a highly ambitious talk on Core Audio, using all of my 80 minutes to get deeply into audio units, applying a ring modulator effect to captured samples from the mic, and mixing it with samples from a file to produce a “Dalek sing-a-long”. I need to clean up the example code, and will likely do a post on it sometime in the future. Still, this was the kind of conference where such an advanced talk would be well received. After Denver and San Jose, it will be interesting to see where they take this conference next.
The business sessions were at least as good as the tech sessions, maybe better. Harbor Master’s Natalia Luckoynova offered a lot of vital real world lessons about making a go of the app store in her talk, and Dan Burcaw’s tales of the enterprise rang all too true.
I’m not a fan of panels, but a wrap up panel on the iPad started well, and probably would be fondly remembered had they wrapped up at the scheduled time rather than going 40 minutes over.
I don’t really have a conclusion, so I’ll end with an observation: Word Press on the iPad offers no way to scroll through the list of category checkboxes. So I will have to save this post as a draft and finish up after getting back to a full-blown computer. Or maybe use my iPhone and the mobile site. Yeah, irony.









