Best Practices and What’s New with In-App Purchases
Best Practices and What’s New with In-App Purchases
WWDC 2018
Introductory Pricing
- 1 time discount for new subscribers
- 1 per subscription
- Automatically applied by App Store
- Eligibility based on subscription group
- Reflects data from App Store Connect
- Used to format and display UI
- Used to determine eligibility
Introductory Pricing
- New in iOS 11.2 and macOS 10.13.2
- New in iOS 12 and macOS 10.14
- Introductory Pricing eligibility is based on subscription group
- 1 introductory price per user for each group
Free Trials for Non-Subscription Apps (new)
Try before you buy
- Non-subscription apps can now offer a free trial
- Free app with non-consumable in-app purchase to unlock
- Trial Period: Use non-consumable in-app purchase at price tier 0
- Naming convention: 14-day Trial - Clearly inform customers
- Duration of trial
- Cost to unlock full functionality
- Features or content lost when trial ends
Asking for Ratings and Reviews
SKStoreReviewController
- Introduced in iOS 10.3
- Quick way to request a rating / review
- Restrictions in place
- Limited requests per device
- Can be disabled by user in Settings - Strategies for when to request review
- Don’t interupt
- Wait for a positive experience
- Track previous requests
Deep link to write a review in App Store
- Introduced in iOS 10.3
- Now supported on macOS
- Link to open your app in the App Store
- Presents compose review from app page - User-initiated actions
- Button in Settings - URL is formed using regular product URL with an anchor tag
- For creating product URLs visit
https://linkmaker.itunes.apple.com/
The Sandbox
- Environment for testing purchases during development
- Based on certificate used to sign your application
The Sandbox
Differences
- No charge
- Dedicated Sandbox accounts 👍👍👍👍👍
- Backend environment
- https://sandbox.itunes.apple.com/verifyReceipt - Test modes
-SKReceiptRefreshRequest
-SKMutablePayment simulatedsAskToBuyInSandbox
- Time contraction for subscriptions
Subscription Timing
Condensed intervals 👍
The Sandbox
Setting up the test environment 👍👍👍👍👍
- Setup in App Store Connect
- Create test user
- Enter products for sale - Build and sign your app
- Buy products
- Sign in with test user when prompted
Adding a Transaction Observer
- Add as early as possible
- Preferably during
application(_:didFinishLaunchingWithOptions:)
- Why?
- Interrupted buy ( User leaves app , User needs to edit billing info , App crashes )
- Subscription renewals
- Promoted in-App Purchases
- In-App Purchase Promo Codes
Finishing Transactions ⚠️
- Finish downloading hosted content first
- Downloads will cancel and become unavailable - Verify the receipt before finishing the transaction
- consumables will not appear after finished
Ask to Buy
The Receipt
- Trusted record of App an In-App Purchases
- Stored on device
- Issued by the App Store
- Signed and verifiable
- For your app, on that device only
Receipt Validation
- On-device vaildation
- Unlock features and content within the app - Server-to-Server validation
- Online validation through a request to the App Store
https://buy.itunes.apple.com/verifyReceipt
- Unlock features / subscription state on your server - Engineering Subscriptions (WWDC 2018)
Server-to-Server validation
- 😆 Use a trusted server to communicate with the App Store
- 😡 Do NOT post the receipt directly to the App Store to be validated
On-Device Receipt Validation
The basics
- Stored in the bundle
- API to get the path - Single file
- Purchase data
- Signature to check authenticity
- Locate the receipt using Bundle API
Standards
- Signing
- PKCS#7 Cryptographic Container - Data Encoding
- ASN.1 - Options for verifying and reading
- OpenSSL, asn1c, and more
- Create your own
Tips for using OpenSSL
- Build your own static library (.a file)
- Not a dynamic library - Include Apple Root CA Certificate
- Available online
- If bundled in app, watch out for expiry - Documentation online
Downloading pre-built solutions
- Convenience comes at price
- Reusing code brings with it bugs and vulnerabilities
- Single exploit affects may - It’s your revenue stream
- Make decisions that suit your product
- Know and own the risks
Certificate verification
- 😡 Do not check the expiry date of the certificate relative to current date
- 😆 Compare expiry date to purchase date of the transaction
Receipt payload
- Series of attributes
- Type
- Value
- ( Version )
Verify application
- Check the bundle identifier
- Check the bundle version
- Use hardcoded values
- Not Info.plist values - Attribute 5 is a SHA-1 hash of 3 key values
- Bundle identifier
- Device identifier
- Opaque value ( Attribute 4 ) - Unique to your app on this device
- Create hash using hardcoded values, compare
Receipt refresh
- If the receipt doesn’t exist or is invalid, refresh the receipt using
StoreKit
- Receipt refresh will require network
- Store sign-in will be required
- Avoid continuous loop of validate-and-refresh ⚠️
Free Trials 👍
- Iterate over In-App Purchases
- If any has
Full Unlock
Product Identifier, unlock the app - If any has
Free Trail
Product Identifier, compare current date to Purchase Date - If neither are present, display UI to begin
Free Trial
Changing Business Models ⚠️
- When moving from
- Paid upfront to subscription
- Paid upfront to free trial - Maintain functionality that users have already paid for
- Original application version in receipt