Highlight
Apple added refund notifications, DID_RENEW renewal notifications, family sharing transactions, watchOS StoreKit, SKOverlay and SKAdNetwork 2.0 for in-app purchases at WWDC 2020, allowing developers to use server notifications and StoreKit API to manage purchases, subscriptions and promotion links.
Core Content
The most difficult situation to deal with with in-app purchases often occurs after the purchase is completed. The user bought 100 gems and applied for a refund from Apple; the user’s subscription was upgraded, downgraded, failed to renew, and then restored; family members opened the app and hoped to get the shared rights immediately. If developers only look at the purchase results once on the client side, they will quickly lose the real status.
In this session, we first fill the holes on the server side. Apple has added refund notifications to allow refunds for consumable (consumable items), non-consumable (non-consumable items), and non-renewing subscriptions (non-renewing subscriptions) to enter App Store Server Notifications. DID_RENEW is also added on the subscription side, so that there will be a server event for every successful automatic renewal.
StoreKit then brings this state back to the device. Family Sharing will generate transactions for the buyer and each family member; watchOS 6.2 can directly initiate in-app purchases; the subscription price increase consent pop-up window can be controlled by the app when it is displayed; SKOverlay allows App Clip or a complete app to use the system floating layer to promote another app.
Finally, there’s advertising attribution. SKAdNetwork 2.0 adds source app id, download and conversion value. Advertising apps can update a conversion value from 0 to 63 after first launch, and the postback received by the ad network is still verified by Apple’s public key, with more context when privacy constraints allow.
Detailed Content
Refund notification turns content revocation into a server-side event
(01:04) The opening example is 100 Gems in the game. The user applies for a refund from Apple after purchasing. If the developer does not know that the transaction has been refunded, it cannot determine whether to retain the content, deduct the balance, or display an explanation message to the user.
(03:24) Apple’s approach is to add a Refund notification. It is a new event in App Store Server Notifications that notifies developers via JSON POST when a refund is issued; if the endpoint does not return HTTP OK, Apple will retry up to three times.
refund notification:
bid
password
unified_receipt.latest_receipt_info[].original_transaction_id
unified_receipt.latest_receipt_info[].cancellation_date
unified_receipt.latest_receipt_info[].cancellation_reason
unified_receipt.latest_receipt_info[].product_id
Key points:
original_transaction_idUsed to locate the original transaction that was refunded. -cancellation_dateIndicate when Apple will complete the refund. -cancellation_reasonThe value is 0 or 1; when the value is 1, Apple indicates that the user requested a refund due to an in-app problem. -bidandproduct_idUsed to confirm which app and product the notification belongs to. -passwordIt is the shared secret of the App, used to verify that the payload comes from Apple.
(09:11) After receiving a refund event, developers can perform refund monitoring, in-app messaging, and restrict access to refunded content. For consumables, the in-app currency balance can also be deducted. Session clearly leaves the choice to developers: actions must be consistent with community health and economic system fairness.
Subscription status changes from polling to notification-driven
(11:52) The subscription life cycle includes first subscription, automatic renewal success or failure, automatic renewal turned off or on, upgrade, downgrade, cancellation and other states. Apple recommends using App Store Server Notifications to receive status updates instead of frequently polling for verify receipt.
subscription notification:
auto_renew_product_id
notification_type
password
bid
unified_receipt.latest_receipt
unified_receipt.latest_receipt_info[].original_transaction_id
pending_renewal_info[]
Key points:
notification_typeFlag event types such as INITIAL_BUY, INTERACTIVE_RENEWAL, DID_FAIL_TO_RENEW, DID_RECOVER. -auto_renew_product_idPoints to the item scheduled for automatic renewal. -latest_receipt_infoContains the last 100 transactions and can be usedoriginal_transaction_idActive subscriptions found. -pending_renewal_infoStore the next renewal information.
(16:05) New in 2020 DID_RENEW. It will be sent after each automatic renewal is successful. The payload contains unified receipt, original transaction ID, transaction ID of the new subscription period, expiration time and auto-renew product id.
(17:14) Apple also added the promotional offer id to the pending renewal info. When a user decides to take advantage of a subscription offer for their next renewal, developers can know about it in advance.
(18:00) verify receipt still retains three positions: recovery mode after server failure, immediate judgment of entitlement (rights and interests) when the user goes online, and double confirmation after automatic renewal. The recommended approach is to subscribe to DID_RENEW first, and then schedule a verify receipt call after the subscription expiration time; if DID_RENEW arrives normally, cancel the task.
Family Sharing generates transactions for family members
(19:36) Family Sharing supports auto-renewable subscriptions and non-consumable in-app purchases, allowing up to five additional family members to share a purchase. Developers need to turn it on for specific products in App Store Connect. Once turned on, it cannot be turned off.
(21:27) Sharing is not simply reusing the purchaser’s receipt. Apple creates transactions for the buyer and each family member. When a family member opens the App, the corresponding transaction will appear in the transaction queue, and the latest receipt info of the receipt will also contain the shared transaction.
Family Sharing APIs and signals:
SKProduct.isFamilySharable
transaction queue entries for family members
unique receipt for each family member
SKPaymentTransactionObserver.paymentQueue(didRevokeEntitlementsForProductIdentifiers:)
Key points:
SKProduct.isFamilySharableLet the app determine whether the product supports family sharing after requesting product information.- New purchases will put transactions similar to restored purchase for family members, and there is already recovery logic that can be reused.
- Old non-consumable purchases require restore purchases before family members can get the content.
-
paymentQueue(didRevokeEntitlementsForProductIdentifiers:)Will be called after turning off home sharing, leaving the family group, or refunding the money. - After receiving the revocation callback, you need to re-verify the receipt. You cannot directly revoke all overlapping rights and interests just by looking at the product identifiers array.
StoreKit extends to watchOS, price increase popups, and SKOverlay
(27:40) watchOS 6.2 starts supporting StoreKit and in-app purchases. The watchOS App can observe the payment queue, request products, and add payments to the queue. Server-side receipt validation is still available; during local verification, use WKInterfaceDevice instead of UIDevice to obtain the device identification.
(30:02) The subscription price increase consent process has also changed. The App Store will display a system consent pop-up window when the user opens the App; if the current time is not appropriate, the App can return false in the SKPaymentQueue delegate method and call it later.SKPaymentQueue.showPriceConsentIfNeededexhibit.
(31:33) SKOverlay is a new system floating layer used to display and promote apps. It is closer to the current interface than SKStoreProductViewController, and can also help App Clip guide users to the complete App.
SKOverlay flow:
create configuration
initialize overlay
set delegate
present in UIWindowScene
dismiss from UIWindowScene
animate alongside SKOverlay.TransitionContext
Key points:
- AppClipConfiguration is used to display the corresponding complete App from App Clip.
- AppConfiguration can display any App and provide app identifier.
- campaign token and provider token can be used in App Analytics.
- Position can choose bottom or bottomRaised, the latter is suitable for interfaces with tab bars.
- The delegate’s display and disappearance callbacks are in the main queue, and you can move your UI synchronously with the transition context.
SKAdNetwork 2.0 adds optional context to ad attribution
(37:43) SKAdNetwork involves three parties: advertising network, source app and advertising app. The advertising network puts the signed advertising data into the source app; after the user installs and opens the advertising app, the advertising app initializes the postback; the device sends the postback to the advertising network after the timer expires.
SKAdNetwork 2.0 additions:
version: 2.0
source app id
redownload
conversion value: 0...63
updateConversionValue
Key points:
- Ad display data needs to include version and source app id in 2.0.
- Postback is initialized when the advertising app is first started; subsequent calls will not repeat the startup process.
-
updateConversionValueA 6-bit value from 0 to 63 can be written to express events such as purchase, trial registration, and level completion. - The conversion value can only be increased, updates lower than the current value will be ignored.
- The source app id and conversion value in postback are optional and Apple will return them when privacy calculations allow.
Core Takeaways
- Refund event ledger
- What to do: for each
original_transaction_idCreate a refund processing record to record the refund time, reason, processing action and user-visible messages.- Why it’s worth doing: Refund notification will be pushed after Apple completes the refund, so developers can process the content and in-app economic system in a timely manner.
- How to start: Access App Store Server Notifications and save
cancellation_date、cancellation_reason、product_id, and then synchronize the processing results to the App.
- Subscription renewal calibration task
- What to do: Use DID_RENEW to update the subscription period, and schedule the verify receipt task after the expiration time.
- Why it’s worth doing: session recommends using notifications to reduce polling, but still preserve a recovery path in the event of server failure or delayed notifications.
- How to start: Cancel the corresponding calibration task after receiving DID_RENEW; call verify receipt when the task is triggered and press
original_transaction_idUpdate entitlement.
- Family Sharing Rights Page
- What to do: Mark which products support family sharing on the purchase page and refresh the UI when family members gain or lose sharing benefits.
- Why it’s worth doing: StoreKit generates transactions for family members and also triggers undo callbacks when the share is closed, leaves the family group, or is refunded.
- How to start: Read
SKProduct.isFamilySharable, reuse the restored purchase logic to process family member transactions, and re-verify the receipt after receiving the revoke callback.
- Upgrade entrance from App Clip to complete App
- What to do: Display the SKOverlay after the App Clip key task is completed to guide the user to install the complete App.
- Why it’s worth doing: SKOverlay specifically supports the transition from App Clip to a complete App, and the overlay can animate together with the current interface.
- How to start: Create AppClipConfiguration, set up the overlay delegate, present in the appropriate window scene, and use transition context to adjust the bottom UI.
- Privacy-friendly ad conversion layering
- What: Map key post-install actions to conversion values from 0 to 63, such as registration, trial, purchase, and completion of the first level.
- Why it’s worth it: SKAdNetwork 2.0 allows advertising apps to update conversion values, and ad networks can evaluate quality while protecting privacy.
- How to start: Define an incremental level for the event and only call it when the new level is higher than the old level
updateConversionValue, the server accepts missing source app id or conversion value when processing postback.
Related Sessions
- Introducing StoreKit Testing in Xcode — Local testing of in-app purchases, refunds, and subscription scenarios is a supporting tool for verifying server-side status processing in this session.
- Architecting for subscriptions — Let’s talk about entitlement design in depth, followed by DID_RENEW, verify receipt and subscription life cycle processing.
- Streamline your App Clip — Talking about the transaction experience of App Clip and SKOverlay usage scenarios can supplement the SKOverlay part of this article.
- Explore App Clips — First establish the background of the design and discovery mechanism of App Clips, and then understand why SKOverlay is suitable for complete App guidance.
Comments
GitHub Issues · utterances