Best Practices and What’s New with In-App Purchases

WWDC 2018

Posted by Den on September 16, 2018 · 15 mins read
Best Practices and What’s New with In-App Purchases

Best Practices and What’s New with In-App Purchases

WWDC 2018

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
.payAsYouGo
.payUpFront

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

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

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