- Swift tutorial: auto-renewable subscriptions in iOS
- Set up subscriptions in App Store Connect
- Shared secret key
- Programming auto-renewable subscriptions
- Purchasing subscriptions
- Checking subscription status
- Refreshing a receipt
- Restoring transactions
- Sandbox testing
- What’s new in StoreKit in iOS 13?
- Caveats when working with auto-renewable subscriptions
- Conclusion
- Гайдлайнами apple auto renewable subscriptions
- Making Signup Effortless
- Supporting Offer Codes
- Helping People Manage Their Subscriptions
- Designing a Sign-up Screen for a watchOS App
Swift tutorial: auto-renewable subscriptions in iOS
In this article I will talk about auto-renewable subscriptions on latest iOS 12 & iOS 13. I will show how to create, manage, purchase and validate auto-renewable subscriptions. I will also talk about hidden rocks and some cases that many developers miss out.
Set up subscriptions in App Store Connect
If you already have an app in ASC (abbreviated from App Store Connect) you may skip this tutorial and go to coding part. But if you don’t have an app yet here is what you need to do.
Before going to ASC you should first log in to Apple Developer Portal and open Certificates, Identifiers & Profile page. Then click on Identifiers tab. Since June 2019, Apple has finally updated this page design to match ASC.
You should create a new explicit Bundle ID. It’s a reverser-domain name style string (i.e. com.apphud.subscriptionstest ). If you scroll down, you can see capabilities list where In-App Purchases has already been checked. After you create App ID, go to App Store Connect.
Another main step is filling up all information in Agreements, Tax and Banking section. You won’t have active Paid apps agreement you won’t be able to test in-app purchases.
After that you create a new App Store app. It’s really simple. Choose your recently created Bundle ID and enter any unique name — you can change it later.
If you already had an app, you can continue reading an article from here
In app page go to Features section.
Adding auto-renewable subscriptions consists of several steps.
Creating subscription identifier and a subscription group. Subscription groups are like a collection of subscriptions, where just one can be active at one moment. Free trial period can be activated only once within a group. If your app needs two subscriptions at a time, then you will need to create two subscription groups.
You can read more about auto-renewable subscriptions in this article.
Next, you will need to fill subscription page: duration, display name and description. If you add your first subscription to a group you would need to specify a group display name as well. Save changes from time to time: ASC often freezes.
Finally, add subscription price. This includes the regular price, introductory offers and promotional offers. Add the price in your currency — it will be automatically recalculated for other currencies. Introductory offers let you create free trial, “pay as you go” or “pay up front” offers. Promotional offers is a new thing which was added recently: you can set up personal offers for users who canceled their subscription in order to bring them back.
Shared secret key
At the in-app purchases page you may notice “App-Specific Shared Secret” button. It’s a special key which is used for validating receipt. In our case we use it to get subscription status.
Shared secret key can be app-specific or account-specific (Master shared secret key). Don’t ever touch shared secrets if you have live apps: you won’t be able to validate purchases with an invalid key.
Copy all your subscriptions IDs and shared key. Now is programming part.
Programming auto-renewable subscriptions
How to make a good subscriptions manager class? This class at least should be capable of doing these:
- Purchasing subscriptions
- Checking subscription status
- Refreshing a receipt
- Restoring transactions (don’t confuse with receipt refreshing!)
Purchasing subscriptions
The process of purchasing a subscription can be divided into two steps: loading products information and implementing payment. But in advance we should set an observer for payment queue SKPaymentTransactionObserver :
Full code is available at the end of this article.
When we request products information a delegate method will be called back. IAP_PRODUCTS_DID_LOAD_NOTIFICATION can be used to update UI in the app.
Later lets write payment initializing:
And here’s our SKPaymentTransactionObserver delegate method:
After purchase operation finishes it calls func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) delegate method. We check transaction’s state to check whether purchase succeeded or not.
Okay, subscription has been purchased. But how to get its expiration date?
Checking subscription status
It is actually the same as validating receipt with the App Store. We send POST request verifyReceipt to Apple, in this request we include local receipt as a base64encoded string parameter. We get JSON in response, containing all our transactions. There’s an array of transactions with all purchases including renewals (by latest_receipt_info key). All we need to do is loop through array and check expiration date for all of those transactions and get active ones.
At WWDC 2017 a new key has been added as a request parameter: exclude-old-transactions . If we set it to true, then Apple will return only active transactions in a verifyReceipt request.
In the beginning of this method you will find that if local receipt is not found then request is not being sent. That’s correct: local receipt may not exist in some cases: for example, when you install an app from iTunes. In such cases we need to refresh a receipt first, then call this function again.
Refreshing a receipt
There is a special SKReceiptRefreshRequest class for it:
After we started this request we will get a delegate method requestDidFinish(_ request : SKRequest) which calls refreshSubscriptionsStatus again.
How we parse JSON response from Apple? Here’s an example how you can do that:
We loop through array looking for expires_date key and save it if is not expired yet. It’s a simple example which considered to be for learning purposes. It doesn’t handle errors or several cases, for example, canceling (refunding) a subscription.
In order to check if subscription is active or not you should compare current date with subscription’s expiration date:
Restoring transactions
It’s just one method: SKPaymentQueue.default().restoreCompletedTransactions() . These functions restore transactions so that observer calls updatedTransactions delegate method as many times as many transactions you have.
Popular question is being asked:
Restoring transactions vs. refreshing a receipt. What are the differences?
Well, both methods let you restore purchases information. Here’s a good screenshot from this WWDC video:
In most cases you just need to use receipt refreshing. And you don’t really need restoring transactions. In case of auto-renewable subscriptions we send a local receipt to Apple to validate it in order to get subscription’s expiration date. And we don’t actually care about transactions. However, if you use Apple-hosted content in your purchases or target device below iOS 7 you will need to use the first method.
Sandbox testing
To test auto-renewable subscriptions you will need to add sandbox testers first. Subscriptions can be tested only using device. So in ASC go to Users & Access then go to Sandbox Testers. There you will create your first sandbox tester.
While creating a new tester you, can enter any text. However, don’t forget email and password!
Previously when testing in-app purchases you used to log out from the App Store. This was very annoying: your iTunes music were being removed from device. Now this problem has gone, sandbox test account is separated from real App Store account.
The process of making an in-app purchase is similar to real purchase. But it has some nuances:
- You will also have to enter sandbox credentials: Apple ID & password. Using device’s Touch ID / Face ID is still not supported.
- If you entered credentials correctly but system keeps showing the same dialog box, then you should tap on “Cancel”, hide the app, then go back and try again. Seems ridiculous but it works. Sometimes payment process may go on from second attempt.
- You can’t test subscriptions cancellations.
- Sandbox subscription durations are much less than real durations. And they renew only 6 times a day. Here’s a table:
Actual duration | Test duration |
1 week | 3 minutes |
1 month | 5 minutes |
2 months | 10 minutes |
3 months | 15 minutes |
6 months | 30 minutes |
1 year | 1 hour |
What’s new in StoreKit in iOS 13?
Well, the only new thing is SKStorefront , which gives you a country code of user’s App Store account. It may be useful if you need to show different in-app purchases for different countries. Previously, developers had to check iPhone region settings or location to get the country. But now it is made with in one line of code: SKPaymentQueue.default().storefront?.countryCode . There’s also a delegate method which tells you if user’s App Store country has been changed during purchase process. In this case you may continue or cancel the payment process.
Caveats when working with auto-renewable subscriptions
- Online receipt validation directly from device is not recommended by Apple. It’s being said in this video from WWDC (starting at 5:50) and in documentation. It’s not secure, because your data may be compromised with man-in-the-middle attack. The only right way to validate receipts — using local receipt validation or server-to-server validation.
- There is a problem related to an expiration date comparing. If you don’t use server-to-server validation, user may change system date to a passed one, and given code will give an unexpected result — expired subscription will become active. To avoid this problem, you should get the world time from any online service.
- Not every user is eligible for free trial. He may already used it. But many developers don’t handle this case, they just display “Start Free Trial” text on a button. To handle this case, you should validate receipt before showing a purchase screen and check JSON for trial eligibility.
- If user has canceled his trial via Apple Care (made a refund), then JSON will provide a new cancellation_date key. But an expires_date key will still be there. That means that you should always check for cancellation date first, as it’s primary.
- You shouldn’t refresh receipt too often. This action sometimes asks for user’s Apple ID password. But we don’t want that — we need everything to be done behind the scenes. You should refresh receipt when showing purchase screen if needed or when user taps on “Restore Purchases” button.
- How often you should validate a receipt to get the latest subscription info? Probably the good way is to call once during app launch. Or you may do this only when subscription expires. However, don’t forget possible cancellations (refunds). User will be able to use your app for free until the end of billing period.
Conclusion
I hope this article was useful. I tried not only include the code but explain some important caveats. The full class code can be downloaded here. This class will be useful for learning purposes. However, for live apps you should use more complex solutions, such as SwiftyStoreKit.
As being said, Apple doesn’t recommend using online receipt validation directly from your device. And not every step can be easily done without a server. But what if you don’t have a server for your app? Well, you can use our Apphud SDK — a subscription validation, managing and analytics tool.
Источник
Гайдлайнами apple auto renewable subscriptions
Auto-renewable subscriptions give people access to virtual content, services, and premium features in your app on an ongoing basis. An auto-renewable subscription continues to automatically renew at the end of each subscription period until people choose to cancel it. For App Store guidance on supporting subscriptions in your app, see Auto-renewable Subscriptions.
Highlight subscription benefits during onboarding. By showing the value of your subscription when users first launch your app, you can educate them on how the app works and help them understand what they’ll gain by subscribing. Include a strong call to action and a clear summary of subscription terms (see Making Signup Effortless). For related guidance, see Onboarding.
Offer a range of content choices, service levels, and durations. People appreciate the flexibility to choose the subscription that best meets their needs.
Consider letting people try your content for free before signing up. Limited free access gives people the opportunity to sample your content and encourages engaged users to sign up. For example, you might offer a freemium app, a metered paywall, or a free trial.
Prompt people to subscribe at relevant times, like when they near their monthly limit of free content. Additionally, consider making it easy for people to subscribe at any time by including prompts at relevant points throughout your app.
Encourage a new subscription only when a user isn’t already a subscriber. Otherwise, people may believe their existing subscription has lapsed when that’s not actually the case. If you offer the same subscription options in multiple apps or through your website, provide a sign-in option so people don’t think they have to pay multiple times for the same service.
Making Signup Effortless
A simple and informative sign-up experience makes it easy for people to act on their interest in your content, whether they’re in your app or viewing your App Store product page.
Provide clear, distinguishable subscription options. Use short, self-explanatory names that differentiate subscription options from one another, and specify the price and duration for each option. If you offer an introductory price, list the introductory price, the duration of the offer, and the standard price the user pays after the offer ends.
Simplify initial signup by asking only for necessary information. A lengthy sign-up process may lower your subscription conversion rate. Defer asking for additional information until after people have signed up.
In your tvOS app, help people sign up or authenticate using another device. Instead of asking people to input information in your tvOS app, send a code to another device where they can enter the information you need.
Give people more information in your app’s sign-up screen. In addition to including links to your Terms of Service and Privacy Policy in your app and App Store metadata, the in-app sign-up screen should include:
- The subscription name, duration, and the content or services provided during each subscription period
- The billing amount, correctly localized for the territories and currencies where the subscription is available for purchase
- A way for existing subscribers to sign in or restore purchases
For example, the Forest Explorer sign-up screen displays billing totals for monthly, biannual, and annual subscriptions in the most prominent positions. In subordinate positions, it shows breakdowns of the biannual and annual prices, so that people can compare the values and make an informed choice. The sign-up screen also contains a button that existing subscribers can use to restore their purchases.
Clearly describe how a free trial works. It’s particularly important to make sure people know that when the free trial is over, a payment will be automatically initiated for the next subscription period. For example, the Ocean Journal sign-up screen explicitly states both the duration of the free trial and the amount that’s billed when it ends.
Include a sign-up opportunity in your app’s settings. App and account settings are common places for people to look for a way to subscribe.
Supporting Offer Codes
Subscription offer codes let you use both online and offline channels to give new, existing, and lapsed subscribers free or discounted access to your subscription content. For example, you might provide offer codes through email, give them out at a store or event, or print one on a physical product. People can redeem an offer code in your installed iOS app or in the App Store, where they’re prompted to install your app if they haven’t already. For business guidance on using offer codes, see Offer Codes; to learn more about other types of offers, see Providing Subscription Offers.
Clearly explain offer details. To help people make an informed decision, provide a straightforward and succinct description of your offer in your marketing materials.
Consider supporting offer redemption within your app. The system automatically provides screens that enable the offer-redemption flow, whether people redeem the offer in your app or in the App Store. When you use StoreKit API to let people redeem offer codes within your app, the only custom UI you need to create is one that initiates the system-provided flow (for developer guidance, see presentCodeRedemptionSheet). There are several natural places to provide this custom UI. For example, you could add a “Redeem Code” button to your paywall, onboarding screens, or your app’s settings screen.
After people tap your custom redeem button, the system automatically provides a series of code-redemption screens like the ones shown below.
Supply an engaging and informative promotional image. Just as a promotional image for any in-app purchase does, this optional image should help people understand the value of your content. If you don’t create a promotional image, the code redemption screens use your app icon by default. To learn more, see Promoting Your In-App Purchases.
Help people benefit from unlocked content as soon as they complete the redemption flow. Think about ways to align the post-redemption experience in your app with the subscriber’s new status. For example, you might provide a welcome experience for new subscribers or a brief tour of new features for an existing subscriber who’s unlocked additional functionality. In particular, be prepared to welcome people who subscribe before they open your app for the first time. For example, if you require people to create an account or sign in before they can use your app, make this process as smooth as possible for new subscribers who haven’t experienced it before.
Helping People Manage Their Subscriptions
Supporting subscription management means people can upgrade, downgrade, or cancel a subscription without leaving your app. Offering subscription management within your app also gives you a natural place to provide help for common subscriber issues and present alternative offers for people to consider. For related guidance, see Providing Help with In-App Purchases.
Provide summaries of the customer’s subscriptions. In particular, people appreciate viewing the upcoming renewal date without having to search for it. Consider displaying this information in a settings or account screen, near the subscription-management option. For developer guidance, see Product.SubscriptionInfo.
Consider using the system-provided subscription-management UI. Using StoreKit APIs lets you present a consistent experience that helps people manage or cancel their subscriptions without leaving your app. For developer guidance, see showManageSubscriptions(in:).
Consider ways to encourage a subscriber to keep their subscription or resubscribe later. When you use StoreKit APIs, your app is notified when a user chooses to cancel their subscription. In this scenario, you might want to extend a personalized offer as an alternative to cancellation or invite people to describe their reasons for canceling in an exit survey. In addition to giving you insights into various customer problems, survey feedback can also help inform messaging for retention and win-back strategies.
Always make it easy for customers to cancel an auto-renewable subscription. If the manage subscription action is deep within an app — or hard to recognize — subscribers can feel they’re being discouraged or prevented from canceling.
Consider creating a branded, contextual experience to complement the system-provided management UI. Within your custom UI, you might offer a popular premium tier or provide personalized suggestions for alternative plans based on what you know about the customer’s preferences or how they use your app. For example, you can create a promotional offer that provides a discounted price for a specific period of time. You might also consider subscription offer codes to help you win back lapsed subscribers and encourage existing subscribers to upgrade.
Designing a Sign-up Screen for a watchOS App
The sign-up screen in your watchOS app needs to display the same set of information about your subscription options that you display in other versions of your app. For the complete list of required items, see Making Signup Effortless. The following guidelines can help you design a sign-up screen that feels at home on Apple Watch.
Clearly describe the differences between versions of your app that run on different devices. If your watchOS app supports different functionality or provides a subset of the content that’s available on other devices, be sure to clarify these differences in your description. Be straightforward about the advantages of accessing subscription content through your watchOS app without implying that the experience is identical to the ones in other versions of your app.
A description that might lead people to expect access to 90,000 maps on their Apple Watch
A description that clarifies how the subscription works on Apple Watch in contrast with other devices
Consider using a modal sheet to display the required information. After people respond to your call to action to learn more about your subscription offers, you can use a modal sheet to present all required items in a single, focused view. Even though people must scroll the view to access all the information, displaying it in a modal sheet helps your app UI remain streamlined and concise. Also, a modal sheet’s default Close button makes it easy for people to return to your free content with one tap. If you create a custom sign-up view instead of using a modal sheet, design a focused experience that includes a Close or Cancel button that lets people return to your free content.
Make subscription options easy to compare on a small screen. People need to understand the terms of each subscription option before they can choose one. Aim to display the duration and discount information for each option in a compact way that’s easy to scan and compare. Here are two ways you might present subscription options in your watchOS app:
- Display each option in a separate button. Using one button per payment option lets people start the signup process with one tap. In this design, it’s important to lock up each button with its description so that people can see how these elements are related, especially while scrolling.
- Display a list of options, followed by a button people tap to start the signup process. Using a list to display one option per row gives you a compact design that minimizes scrolling while making subscription choices easy to scan and understand. In this design, the button’s title can update to reflect the chosen option.
One payment option per button
One payment option per list row, followed by a button that updates to display the chosen option
Источник