Archive for September 18, 2019

Wednesday, September 18, 2019

IAP Using Audible Credits

App Store Review Guidelines:

3.1.1 In-App Purchase:

If you want to unlock features or functionality within your app, (by way of example: subscriptions, in-game currencies, game levels, access to premium content, or unlocking a full version), you must use in-app purchase. Apps may not use their own mechanisms to unlock content or functionality, such as license keys, augmented reality markers, QR codes, etc. Apps and their metadata may not include buttons, external links, or other calls to action that direct customers to purchasing mechanisms other than in-app purchase.


3.1.3(a) “Reader” Apps: Apps may allow a user to access previously purchased content or content subscriptions (specifically: magazines, newspapers, books, audio, music, video, access to professional databases, VoIP, cloud storage, and approved services such as classroom management apps), provided that you agree not to directly or indirectly target iOS users to use a purchasing method other than in-app purchase, and your general communications about other purchasing methods are not designed to discourage use of in-app purchase.

3.1.3(b) Multiplatform Services: Apps that operate across multiple platforms may allow users to access content, subscriptions, or features they have acquired elsewhere, including consumable items in multi-platform games, provided those items are also available as in-app purchases within the app.

And yet it looks like you can now purchase audiobooks in-app, using Audible credits.

Steve Moser:

Wow, Apple must have changed its stance on using credits in iOS apps not bought through IAP. What will we see next — using coins in iOS games that were not bought through IAP?

You can’t always directly buy credits for money:

If you’ve run out of credits for your Gold/Platinum monthly or annual Audible membership before your renewal, occasionally a special offer will appear where you can purchase additional credits at a discounted rate.

But this does seem like a significant change that could be applied to other types of content.


Pocket Casts Goes Freemium

Morgan Wynn (via Jeff Perry, Hacker News):

Starting today, podcast fans all over the world can download Pocket Casts for free. Known for its beautiful design and robust set of controls, Pocket Casts is making the entirety of its existing features available at no charge. Power users looking for even more customization can upgrade to Pocket Casts Plus for USD$0.99 per month (USD$10/year). With these changes, we are now more closely aligned with the open-access model of our public media ownership.


Pocket Casts Plus, for those power listeners looking for even more control, offers:

  • Desktop apps including macOS, Windows and Web apps
  • Cloud storage for creators and listeners who want to use Pocket Casts for all of their audio and video files
  • Exclusive app icons and themes

The other way of looking at this is that some stuff that was previously covered with a one-time $9 payment is now under a $10 subscription. You get a three-year credit if you had previously paid.


Update (2019-09-27): Owen Grover (tweet):

Although we intended to demonstrate our appreciation to our most loyal users, we know many of you feel we missed the mark. With that in mind, today we’ve decided to provide any user who previously purchased our Web version with lifetime access to Pocket Casts Plus. This includes the Mac and Windows apps as well. No renewal, no monthly charge, no questions asked.

Serializing Heterogenous Arrays With Codable

Nick Lockwood:

Something I’ve spent time on recently is the problem of serializing heterogenous arrays (arrays containing multiple types) in Swift using Codable.

Here’s a pattern I’ve found that works pretty well, using a protocol and a type-erased wrapper.

Normally in Swift you do polymorphism by either using a protocol or an enum (for open or closed sets, respectively). This approach requires you to use both, which is slightly odd, and it inherently only supports closed sets, but it’s relatively little code to add new cases.


The other disadvantage is that containing types must use Array<AnyFoo> rather than Array<Foo>, otherwise they can’t use automatic Codable synthesis.

This is necessary because, unlike NSCoding, Codable does not store the type information in the archive. It has to be provided when decoding.

Drew McCormack:

I used a similar approach when messing with genetic programming last year. Began with a switch like you, but in the end went to a dictionary mapping of types.

Ian Keen:

If the underlying format doesn’t matter I have a fairly nice generic solution here.

the DecodingRoutine is just a wrapper around Decodable.inits that you’d normally create specific boxes for. And the ones I’ve provided take advantage of the fact AV cases without values are functions