Can Coral Microbes Protect Reefs From Climate Change?

It turns out that humans aren’t the only species that rely on their microbiome to stay healthy. Researchers at Ohio State University are looking at the microbial communities of corals, which appear…

Smartphone

独家优惠奖金 100% 高达 1 BTC + 180 免费旋转




iOS Subscriptions are Hard

The unreasonable difficulty of implementing iOS subscriptions

Subscriptions provide developers a better way to make money. Building an audience of paying subscribers not only generates more revenue, but it offers better customer-developer alignment and leads to better apps.

Apple’s StoreKit lacks some of the basic functionality for implementing subscriptions correctly. It is up to the developer to fill this gap.

Apple bolted on Subscriptions to the existing in-app purchase infrastructure that introduced almost ten years ago. Doing this was not a great start. StoreKit assumes a transactional, user-driven purchasing experience. For subscriptions, purchases are only transactional initially. Beyond the first transaction, they occur automatically, recurring without user input.

StoreKit’s queue and receipt mechanism is clunky for handling renewing transactions. At some point, before a subscription renews, an SKPaymentTransaction will appear on the StoreKit queue, unprompted by any user action. This unprompted appearance makes handling the queue much more complicated. Users can switch devices, receipts can be stale, and transactions can go unhandled. Unexpected transactions create an unmanageable number of cases that you need to consider to provide a user with their paid content.

There are two ways to handle subscriptions in your iOS app:

Implementing subscriptions without a server is possible. Device-side means your app implements some form of the following:

Let’s go through each of these.

Normal IAP flow.

Handling renewals is a common area for mistakes. In a standard IAP flow, you only need to worry about the status of the StoreKit payment queue while a user is completing a purchase. With subscriptions, your app needs to be prepared to handle these transactions at any time. Now you need to handle purchases from literally anywhere in the app; the effect of a user’s subscription status changing needs to be considered on every screen.

The appropriate way to handle it is: as soon as it appears on the StoreKit queue, validate the receipt, and update a user’s entitlements. However, this can be difficult. For example, if your application has an account system, how do you handle a transaction that occurs while there is no user logged in? Or consider a transaction that occurs in the middle of some flow that depends on a user’s subscribed state. You have to plan for all of these possibilities when designing your app.

Device-side receipt handling makes a few important things difficult or impossible.

Firstly, your subscription status is trapped on the device. If you ever want to expand your service beyond your current app, you will need to design some elaborate escape plan for the current subscription status of your users.

Limiting subscription handling to the device also makes it difficult to understand the performance of your business. iTunes Connect has gotten better but is still lacking if you ever want to understand anything on a user-by-user basis. All of Apple’s dashboards are fully anonymized. Aggregate metrics are fine if all you want is a bird’s eye view, but you will quickly be unable to answer even simple data questions using Apple’s dashboards.

I think the biggest reason to avoid a device only subscription implementation is just being at the mercy of the StoreKit queue. If for some reason there is a hiccup either in your code or in StoreKit, you could miss a transaction. This would potentially deprive a paying customer or their service. If you are using only device side subscriptions, you may have a hard time debugging or remediating the situation.

It really makes sense to use a server.

Using a server means: rather than parsing a receipt on the device, you send that receipt to a server for validation and parsing. On the device, implementation is similar to that of device-side subscriptions but with a couple of key changes:

Step 2 represents the most radical difference from device-side subscriptions. Rather than implementing receipt parsing and validation in the app, you send the receipt over HTTP to your server. Doing this has two significant advantages:

When you parse a receipt device side, whatever transactions are in the file are what you get. When you use /verifyReceipt, Apple sends along a list of the most up-to-date subscription transactions. The receipt file acts as a fetch token to poll data from Apple. This polling is essential for building a complete subscription server.

When a user has an active subscription, the answer is relatively simple. You can start checking when they are close to renewing, but you will miss out on returns. The complexity comes once a customer cancels a subscription. There is a possibility that, at any time in the future, they resubscribe. If they do this in your app, you will be able to send a new receipt and tell your backend to update their status. However, a user can also resubscribe from the App Store settings page. You need to rely on some combination of polling and the status notifications to have complete knowledge of a user’s subscription status.

However, only storing the latest expiration cuts you off from a lot of the interesting information a receipt provides. A better implementation would be storing the complete transaction history of a user. Storing the complete history gives you the ability to understand more complex subscriber behaviors like average subscriber lifetimes, cancellations, and the evolution of your paying subscriber base day-by-day.

Without a server holding your receipts, getting good metrics is very difficult. If you plan on understanding your LTV and perhaps making some decisions about user acquisition spending you need to know the dollar amount that each user is spending. Tracking a user’s total transaction history enables this.

Having a system that parses the user’s entire transaction history and attaches dollar values to each transaction gives you the basis for answering any monetization questions you have and in the most accurate manner possible.

The last big advantage that server-based subscription tracking provides is related to customer support. Supporting Apple subscriptions customers can be painful.

Developers lack programmatic access to a user’s account history and the ability to modify or cancel their subscription. Often our best course of action is to tell the user how to contact Apple, or send them instructions for managing their subscription via App Store settings. With a server, we can do better.

Having a user’s entire history accessible via your backend, you are much more equipped to understand the user’s situation. IAP transactions fail in weird ways, user’s get confused, and emotions can run high when money is involved. Having a user’s entire subscription history at your fingertips will give you a much better starting point for understanding a customer’s issue.

With a server as your source of truth for a customer’s subscription, you are empowered to resolve more support tickets than if everything were device-side. Adding “support” transactions to a user’s history allows you to grant a user a subscription for as long as you’d like. This requires some work on the back end but can really pay off in avoided 1-star reviews.

If there is a possibility that the app becomes a serious money-making endeavor, having a server tracking your subscriptions from day one will make your life easier.

The server features described above represent a substantial amount of work. If you only have time to do one thing, I suggest using a server for receipt validation and storing the receipt file. Having the receipt file will enable you to build everything else mentioned at a later date. If your receipts are trapped on the device, your options are limited.

Add a comment

Related posts:

A Strange New World

The past two days have really opened my eyes. The life in the forest which I had taken for granted, is now very dear to me. Deforestation, the effect of which until now seemed to have only been…

April is National Sexual Assault Awareness Month

The goal of National Sexual Assault Awareness Month is to raise public consciousness about sexual violence — how to prevent it, how to take action to promote safety, respect and equality and how to…