Rss

Archives for : inapppurchase

App Rejections Are a Lousy Way to Communicate Policy Changes

Following Twitter reports from earlier in the week, MacRumors and TechCrunch now report that Apple is rejecting apps that use the unique device identifier (UDID), by means of the -[UIDevice uniqueIdentifier] call.

This in itself is not surprising: iOS 5 deprecates the method, adding “Special Considerations” that advise developers to create a one-off CFUUID to identify a single install of the app on a single device.

So far, so good. I even had a section of my talk at last week’s CocoaConf Chicago that talked about CFUUIDs and the need to migrate any UDID dependencies to them now.

The problem is the timing. Apple’s established pattern has been to deprecate a function or method in one major version and, at the speediest, remove the call in the next major version. Many developers, myself included, expected that we had until iOS 6 to get off of the UDID.

But instead, without warning, the app review process is being used as an immediate death-penalty for the uniqueIdentifier call.

This is a problem because we’ve all had about six months to get off of UDID, and while that’s surely enough to get a simple app migrated — indeed, I have cases where switching it out is a 5-line fix — it is not necessarily the case that everyone can be expected to have already done this.

The real problem isn’t with developers; it’s with whom we develop apps for. Our clients don’t know or care what a UDID is, nor are they aware of a single line in Apple’s documentation saying “stop using this”. Sure, it’s our job to be on top of it. But let’s imagine apps with long development cycles — big apps, or academic apps that rev for the new school year in the Fall and are largely dormant the rest of the year. It’s entirely plausible and reasonable that developers of these apps have “get off UDID” as a high-priority item in their bug trackers, but are waiting for budget and approval to start working. And what if it’s not a simple process? What if an app has some deep dependency on access to the UDID, both in the app and on a server somewhere, meaning that two different teams are going to need to deal with losing access to uniqueIdentifier, and will need to come up with a plan to migrate user records over to a new id scheme?

Well, they just lost their chance.

Captain Hindsight is in full effect in the MacRumors forums, loudly asserting that developers should have known this was coming, have had plenty of time, etc. I get that it’s the natural defensiveness about Apple, but it gets worse… because this isn’t the only case of Apple using app rejections to carry out policy changes.

Thanks perhaps to my many posts about in-app purchase, I recently heard from a group of developers who’d gotten a galling rejection. They have an app with a subscription model, and used the new “auto-renewing subscription” product. This product is far superior to the original subscriptions that I have repeatedly described as broken, as they cannot restore between a user’s devices, and do not carry state to indicate what was subscribed to and when. Auto-renewing subscriptions fix these problems, and the In-App Purchase and iTunes Connect guides had (seemingly until a couple weeks ago), clearly disparaged use of the old subscriptions in favor of the new auto-renewing subscriptions.

So imagine the surprise of my colleagues when their app was rejected for using auto-renewing subscriptions. The reason given was that they were using it for a different business plan like a data-plan model, and auto-renewing subscriptions are, according to the reviewer, reserved only for content subscriptions like Newsstand magazines. I have never seen anything to this effect in any Apple I-AP documentation. Nevertheless, the developers had to switch to the shitty, broken, old subscriptions.

In both of these cases, we see Apple breaking with their own documentation or with long-established practice with no warning, and instead using app rejections as a tool to communicate and carry out new policies. This is wretched for developers, who get caught scrambling to fix problems they didn’t know they had (or didn’t expect just yet).

It’s also terrible for Apple, because the aggrieved developers initially control the message as they flock to blogs and Twitter, leaving it to loyalist commenters and bloggers like Gruber and the Macalope to mount a rear-guard gainsaying defense. To see Apple — of all companies! — not controlling the message is astounding.

All it takes is clarity. If they’re going to make such a major change, they’ve already got our attention via e-mails, the developer portal, and many other channels. They could and should clearly state the what, why, when, and how of policy changes. “We’re getting rid of UDIDs, because they constitute a privacy risk. We’ll reject any app that calls -[UIDevice uniqueIdentifier] as of March 23, 2012.” Not that hard. They’ve done it before: a few years back, Apple required streaming media apps to use HTTP Live Streaming if they streamed more than 10MB of data — this was communicated via announcements on the developer portal a month or so before its implementation, and nobody got caught by surprise, nobody complained.

Apple has developed a reputation for capriciousness in its app review process, and a cavalier attitude towards its developer partners. It’s not undeserved. As Erica Sadun once cleverly put it, “Apple is our abusive boyfriend.”

In-App Purchase Fanboys

I’ve blogged a lot about in-app purchase recently, and I’m finding that every time I tweet about it now, someone parrots back this “Apple is bringing customers to you, so be grateful” line. It’s a response that’s taking hold among Apple apologists, and I don’t think it’s nearly the counter-argument that its adherents think it is.

This argument is something that Daring Fireball’s John Gruber comes back to, notably in his Dirty Percent blog entry (more on that in a bit). But there’s a nice counter-argument in Josh Benton’s To the Victor Goes the Pricing Power (a title that parallels my own arguments that Apple is rent-seeking). Benton writes:

But if someone searches for and downloads The New York Times app — after the Times has spent more than a century building up its brand, at the cost of billions of dollars — can it really be said that Apple has “brought” that subscriber to the app, and that they deserve 30 percent of the revenue the app generates, forever? (Gruber doesn’t address the eternal nature of Apple’s cut; it’s like paying a New York apartment broker his finder’s fee, every year for the rest of your Manhattan-dwelling life.) It certainly seems like a transaction different in kind from, say, a game that exists only on (and only because) the iPhone platform.

Now back to Dirty Percent… one thing that’s interesting about this essay is the degree to which Gruber acknowledges the legitimacy of many of the arguments against Apple’s new policy. He explicitly agrees with Matt Drance’s criticism that the price matching requirement is unreasonable, is troubled by the fact that the new requirement to offer I-AP for digital products available elsewhere is “is taking away the ability to do something that they previously allowed” (in more recent entries, he’s gone further and said this feels like a bait-and-switch), and on the topic of 30% being too big a cut for doing little more than a credit-card swipe, he simply responds that “Apple… doesn’t see it this way”, neatly avoiding taking a stand himself.

Far from an absolute defense of Apple’s new I-AP policies, Gruber has wisely distanced himself from the most indefensible of Apple’s actions, and left himself some wiggle room in case things change.

The most rabid Apple defenders have also blithely ignored the inherent problems of I-AP, preferring to change the conversation to a “old media needs to change their business models” argument (which makes them sound curiously like the “everything should be free” crowd, who willingly misread Lawrence Lessig and Tim O’Reilly in order to justify content piracy). As I’ve said on a number of occasions, “if you don’t hate I-AP, you haven’t had to use it yet.”

A client of a client of mine is likely to get caught up in this I-AP drama, and in a meeting this week, we laid out exactly how I-AP works, and what they have to do in order to implement it, including entering every product into the iTunes Connect web interface, a nightmarish prospect when you have thousands of SKUs. When we finished, there was a long silence on the phone, followed by a colleague saying “you can probably imagine the look on everyone’s faces here.”

Adapting a company’s current digital storefront to incorporate I-AP is a grievously unpleasant proposition. Adding a storefront UI and Store Kit to the iOS app, plus integrating I-AP on the server side (coordinating I-AP purchases into the existing storefront, validating purchase receipts with Apple, etc.) will cost tens, if not hundreds, of thousands of dollars in developer time. More work for me as a consultant, but I can see why clients aren’t eager to spend it.

Because think about it: if the “Apple will bring you customers” argument were valid, everyone would have willingly done this back in 2009 when I-AP first hit the scene. It would have been in their self-interest to do so.

Look, I used I-AP in Road Tip because it suits the economic model of the app: I have ongoing service costs to MapQuest for every user; a data subscription plan is an appropriate way to cover that for users who continue to use the app. But it’s not necessary for other kinds of apps, like apps that view content the user has acquired elsewhere, or deluxe clients for websites that don’t work correctly in Mobile Safari (because, say, they depend on Flash).

The legitimate fear is that some content won’t be available at all for iOS because the hassle and expense of I-AP is too great. Obviously, Apple is counting on this not being the case. And I think this is a bigger deal for the small, niche content than for the big media companies. My fear is that the Apple Fanboys will go out of their way to purchase content through Apple as a political statement, so the small providers that somehow do cobble together the resources to add I-AP and enter all their content into iTunes Connect will then lose 30% on every sale that they could otherwise have run through their website. If you’re determined to pay Apple and only Apple for your content, you’d better hope they’re capable of meeting all your content needs indefinitely, because you might lose third-party content providers in the process.

For all you conspiracy theorists…

One more nugget about the I-AP subscription dustup (my previous blogs: 1, 2), particularly for all you conspiracy theorists who loves you some nefarious skullduggery!:

What if the real story here is that Apple has decided to release an AppleTV SDK later this year? Streaming media apps would be far and away the most appropriate use of such an SDK — nobody needs Twitter clients for their TV or Angry Birds with a tiny D-pad — and by establishing a 30% tax on content now, it would be a fait accompli by the time the first Hulu, NFL, and Crunchyroll streams roll through port 80.

Not that I have any reason to think this is what’s going on. I’m just putting out there now in case I get lucky and get to do the “told you so” happy dance later.

You’re welcome. Happy conspiring!

Apple’s Full Employment for Data Entry Workers Act

Talking with a colleague from Cocoaheads Ann Arbor last night, I stumbled across an even bigger objection to Apple’s new “must offer in-app purchase if app content is available elsewhere” rule, beyond those that I covered in In-App Purchase and Rent Seeking.

The problem is that to make something available for in-app purchase, you need to create an I-AP product for it in iTunes Connect. In this web interface, you enter a product ID, a description in whatever languages you want to support, and set a price. To get approved by apple, you also have to submit a screenshot of the purchased product in the application.

Apparently, the web interface is the only way to create products.

And if you’re thinking “that doesn’t scale”… well, yeah, that’s what we suddenly realized. If you’re Amazon, and you have 810,000 Kindle books, does Apple seriously expect you to submit all 810,000 of those, one at a time, and with screenshots, via the ITC web interface?

Even if that’s possible, even if you think that content providers won’t utterly balk at the impracticality of it, let’s tease this out a little further. Add in the hundreds of thousands (or millions?) of titles available for the Barnes and Noble Nook. And 20,000 Netflix streaming titles, and so on… how on Earth is Apple seriously going to review and approve all these products? If we just assume 2,000,000 products need to be added by the June 30 deadline, and we assume each could be reviewed in about five minutes, then that’s 12 products per person-hour, meaning Apple would need over 160,000 person hours just to approve all these products. Divide again by 8-hour days and 130 days between now and June 30, and they’d need 160 employees doing nothing but reviewing I-AP products for this to work.

This, clearly, is madness.

The benign and simplest explanation for all of this is that Apple has painted itself into a corner, that it hasn’t really thought through all these issues. And if that’s the case, something will have to give: a bulk-submission tool, lax review of products, or (ideally) an abandonment of the new rent-seeking policy.

Conspiracy theorists could also pick up this ball and run with it: the premise that Apple is using an unreasonable and unworkable I-AP system to get content providers off the platform, leaving Apple as the sole seller of books and movies and such on iOS (while still being able to say “hey, they’re the ones who bailed on the platform”), is arguably consistent with the facts. I think it’s implausible… but not impossible.

I have to acknowledge one thing has gotten better: the new auto-renewing subscriptions are restored by -[SKPaymentQueue restoreCompletedTransactions], meaning it’s now actually practical to get a user’s new iOS device to recover subscriptions purchased with their iTunes account on previous devices. This is what I was complaining about in bug 7470096, and the new purchase type looks a lot more practical and thought-out. I feel like I should update Road Tip to use these subscriptions (and therefore gain restorability across devices), but anytime I touch that code, it’s throwing good money after bad, so it will be hard to justify for any reason other than shame that the current version is so compromised by the impracticality of the old I-AP subscriptions.

In-App Purchase and Rent-Seeking

In economics, rent-seeking occurs when an individual, organization or firm seeks to earn income by capturing economic rent through manipulation or exploitation of the economic or political environment, rather than by earning profits through economic transactions and the production of added wealth.
Rent-seeking, from Wikipedia

Most of my tweets today have been about in-app purchase, first with the news of Sony’s Reader app being rejected on the basis of its purchase model, and then Apple’s clarification / de facto policy change stating that apps that offer user-purchasable content must offer Apple in-app purchase in addition to whatever other purchase methods might be available.

Matt Ingram at GigaOM nearly nails the issue in a section header:

The Landlord Will Get His Share

What Apple seeks to collect is rent, specifically monopoly rent, the ability to extract excess payments not as a consequence of a mutually-beneficial trade, but because it owns the damn store and it sets the damn rules.

I have long argued that in-app purchase can be a pretty raw deal for developers. Slide 50 from my Voices That Matter (Seattle 2010) talk, In-App Purchase: Best/Worst Thing Ever puts this in perspective:

App Store In-App Purchase
Product Hosting
Audit Trail
Purchase UI
Purchase Restoration (sometimes)
Local Purchase Storage
Apple’s Cut 30% 30%

To clarify what I mean by each of these:

  • Product Hosting: Apps are hosted on Apple’s servers. In-App Purchases go on your server (unless they’re bundled with the app and simply unlocked)
  • Audit Trail: The audit trail for an app purchase is entirely verifiable through Apple. With In-App Purchases, the developer gets a digital receipt that he or she needs to log on their own server, after validating it against an Apple webservice.
  • Purchase UI: For apps, the description, screenshots, user ratings, pricing, and purchase process are all handled by iTunes or the iOS App Store. For I-AP, the developer needs to create a UI for all of this, beyond a simple “are you sure” alert provided by Store Kit once a purchase is initiated.
  • Purchase Restoration: Users can easily re-download their old apps to a new device for free with iTunes or the App Store, once they’ve logged back into their iTunes account. For In-App Purchases, developers are expected to provide restoration of “durable” and “subscription” products, but Store Kit’s -[SKPaymentQueue restoreCompletedTransactions] method only restores the former. There is no programmatic way to discover old subscription purchases on a new device. There’s also no way to get an identifier for the iTunes account, so you don’t even have anything to associate with the subscription purchase on your own server.
  • Local Purchase Storage: iOS is responsible for storing the apps on the device’s file system. The developer is responsible for storing in-app purchases, ideally in a form that will survive crashes, wipes and restores, etc.

If you sell a $10 subscription, you do almost all the work, and yet Apple still feels it is entitled to a $3 cut for doing little more than running a credit-card swipe. Obviously, I don’t think they earn it.

If Apple’s now going to force the issue, it’s truly a sad and ugly moment for them and for all of us. How far does this concept go, after all? Consider websites that have premiere memberships, like ESPN.com or Crunchyroll. Both of them have dedicated iOS apps, since the full functionality of their Flash-heavy sites don’t work in Mobile Safari. Is Apple going to insist that these memberships be made available for purchase by I-AP as well? Or will users not be able to use iOS devices to access the online content they’ve paid for? How is that good for the platform?

It’s enough to make you hope that content providers switch to an ad-supported model and let Google make all the money. That would be just desserts, with a cherry on top.

What you missed at Voices That Matter: iPhone Developers Conference

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.

Calculating as-the-crow-flies Apple Store distances from GRR

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.

Calculating drivable Apple Store distances from GRR

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.

Purchasing an item with I-AP

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?

Coming next: my 360iDev slides, and the much-anticipated cleaned-up Core Audio sample code

An In-App Purchase Brain Dump

Oh thank goodness. Apple has finally come up with an API that’s a bigger pain in the ass than Core Audio. Namely, In-App Purchase. So no more bitching from any of you about kAudioUnitProperty_SetRenderCallback until you’ve tried validating a restored purchase.

I’m not complaining, not entirely, because both of these are inherently complex propositions, and the APIs are, by and large, designed to account for the hard parts of each problem domain.

That said, I spent as much time developing Road Tip‘s (née Next Exit) in-app purchase of continued mapping service as I did the app’s core functionality, so that’s gotta tell you that working through I-AP is no weekend project.

Apple’s programming guide is a decent-enough overview, as is the WWDC 2009 session, but I still felt like I ran into enough surprises that a brain-dump of tips and hints is in order.

  • Leave yourself a lot of time for I-AP. Seriously, it took me a person-month to get it all together.
  • The most critical decision is to figure out exactly what you’re selling and how it fits into I-AP’s view of the world. The one case that’s straightforward is “non-consumables” or “durables”, stuff that the user buys and has forever, like eBooks, or new levels in a game. Since these never disappear, Apple requires that you support copying these purchases to other devices, which you do with restoreCompletedTransactions. In fact, this is the only way you can do it: nothing in a purchase transaction tells you anything about the user (like their iTunes ID), so this method call is the only way of discovering a user’s previous purchases.
  • Other purchases are meant to be used up, like ammo in a game. If you buy 500 rounds of howitzer ammo on your iPhone, you shouldn’t be able to use it up and then magically restore it on your iPod touch. So restoreCompletedTransactions doesn’t work for these.
  • The biggest problem in I-AP is the design of “subscription” products. These are defined as consumable products that copy between a user’s devices. There’s an inherent design problem here: if something is consumable, there’s usually a degree to which it has been used up. How many rounds of ammo have I fired? How far into my one-year subscription am I? The degree of consumption is a state variable, something that can be tracked on one device, but can’t be communicated by means of a restoreCompletedTransactions call. Actually, it gets worse; restoreCompletedTransactions doesn’t return subscription products at all, so there’s no practical way for a copy of your app running on a new device to discover what subscriptions the user has purchased on other devices. I consider this a design bug and filed it with Apple (see the Open Radar copy).
  • Assuming you figure out a product model that works for you, you’re going to be working with at least three data sources:
    1. A list of product ids, perhaps saved with your app as a .plist or in a database, or available from the cloud
    2. The Store Kit APIs, which provide SKProduct objects for given ids and include localized name, description, and price. You’ll then present these products to the user and purchase them via other SK APIs.
    3. Apple’s validation webservice.
  • The last of these catches some people by surprise. This is easy to overlook, but the idea goes something like this: if you want an audit trail of user purchases, you need that data sent back to you somehow (since the purchases go from user devices to Apple’s servers, neither of which you control). You can log purchases by having the app call back to a server of yours, but how do you know that you’re getting called from a real copy of your app and not just some hacker somewhere? You call an Apple webservice at https://buy.itunes.apple.com/verifyReceipt with a purchase receipt received on the device, and get a response telling you whether the receipt is good or bogus.
  • Communicating with the Apple web service is done with JSON, and the purchase receipt needs to be sent as base64. I ended up using the MBBase64 category posted to CocoaDev to do the base64 encode on the phone, send that and other data to my web service. I wrote my web service in Java on Google App Engine, using json.org’s Java library to format my submits to the Apple web service and parse the responses.
  • Back on the device, one thing you’ll notice is that the Store Kit APIs are highly asynchronous: instead of blocking when you request products or make a purchase, you set a delegate or observer and implement a callback. It seems natural to put your commerce stuff in one central place in your app, and have that communicate changes to the rest of your app by means of delegates or NSNotifications.
  • Another surprise is that the payment queue (into which you put purchase requests) is persistent, so an unfinished purchase hangs around between application launches. This saves you from losing the user’s purchase if the app dies or loses its network connection in mid-purchase. Good thing. But it also means your observer will get called back shortly after you create the SKPaymentQueue singleton, even if your user hasn’t touched the purchase stuff.
  • You remove purchases from the queue by calling a finishTransaction method. You only do this when you’re good and sure the purchase has gone through. Apple’s WWDC session suggested not unlocking functionality until you hear back from your webservice. I thought that was a little strict: I’m unlocking when I get the “purchased” callback from the queue, but not finishing the transaction until I hear back from the webservice. If my webservice ever went down, the user would still have the unlocked feature, but the purchase would hang around in the payment queue, prompting a new validation attempt with my webservice every time the app comes up. That seemed more elegant to me.
  • A thought for you: how do you persist the “unlocked” state from one launch to another? You could write a .plist, a database record, or other local file, but that struck me as rather hackable by the pirate/jailbreak crowd. It’s also bad for consumables if a user could use up most or all of a consumable, then wipe the app (and your state data), reload, and get free stuff. I opted for putting this data — in my case an install date, which marks the beginning of a free trial period — in the keychain, whose data survives wipes (see the Apple devforum thread Keychain is now my best friend against in app purchase piracy). Only downside is that the keychain API is fairly hard to use, and Apple’s sample code is so determined to put a pretty Obj-C wrapper around the keychain, they actually make the material harder to learn (more info in this thread).
  • One thing that came up in the forum was the idea of when to try a restoreCompletedTransactions to get already-purchased items onto the current device. One developer said he or she planned to do this check at every startup, but I think that’s a bad idea: the user will typically be prompted for a password when you call restore, and that would be highly annoying to have to do all the time, especially as the need to pull old purchases to a new device is likely to be somewhat rare. I opted to make it a manual action, which means the user will only be prompted for a password as a direct result of a restore action.

  • Here’s another presentation concern: what should the purchase options look like? It seems like there’s an emerging consensus to put it in a “buy” button that’s placed at the right side of a table cell. This way, you can leave tapping the cell itself as a “preview” or “more info” gesture, like the iTunes application does, and make purchasing a more explicit gesture. Here’s what it looks like in a typical third-party app with in-app purchase, Weekly Astro Boy Magazine for iPhone / iPod touch




    Slight problem with this approach: it is actually fairly difficult to create a working button on the right side of a table cell. The API for accessory buttons doesn’t support rendering custom content into a right-side button (like “buy” or a price), so I opted to use a custom table cell, and a custom button class that can crawl the container hierarchy to find the parent table and call a selector when it’s tapped.




    Note that this image is debugging only: the published app will only present the user with the product that extends their service period by exactly one year.

OK, I think that’s all I’ve got to dump at the moment. Hope this helps people work through the challenges of I-AP. It’s an important API, but man it’s a struggle to actually put into practice.