大多数浏览器和
Developer App 均支持流媒体播放。
-
StoreKit 和 App 内购买项目的新功能
了解最新的 StoreKit API 增强功能,它们有助于你为顾客提供出色的 App 内购买项目体验。我们将介绍 AppTransaction、Transaction 和 RenewalInfo 中新增的字段,以及针对 App 内购买项目优惠代码所做的更新。我们还将介绍如何使用 App Store Server Library 创建已签名的 App 内购买项目请求,以及如何使用 SwiftUI 来更新陈列订阅项。
章节
- 0:00 - Introduction
- 0:36 - Explore new features
- 10:24 - Sign In-App purchase requests
- 14:21 - Merchandise Subscriptions
资源
- Advanced Commerce API
- Human Interface Guidelines: In-app purchase
- Implementing a store in your app using the StoreKit API
- Set up offer codes
- Simplifying your implementation by using the App Store Server Library
- StoreKit
相关视频
WWDC25
WWDC24
WWDC23
WWDC21
-
搜索此视频…
Hi, I’m Rudy. I’m excited to share the new features in StoreKit and show how you can incorporate the App Store Server Library and new StoreKit 2 APIs into your development workflow. First, I'll go over the new core framework features in StoreKit.
Then, I’ll show how you can sign your In-App Purchase requests using the App Store Server Library.
Finally, I’ll review a new way you can merchandise subscriptions in your app using SwiftUI and StoreKit views.
To start, let’s discuss the updates made to three crucial types: AppTransaction, Transaction, and RenewalInfo. These types give you insight into the purchase of your app and enable you to monitor purchase history and manage subscription statuses.
AppTransaction provides information about the original purchase of your app. You can use this to know the original purchase date, the version of your app the customer downloaded, and the date a customer pre-ordered your app before you released it on the App Store. You could, for example, use appVersion to prompt customers to upgrade their app to ensure they’re running the latest version. To get an AppTransaction, query the AppTransaction.shared API and use a verified result. StoreKit automatically validates the JSON web signature for the AppTransaction and returns a verified value in the verification result. A verified AppTransaction means StoreKit was able to verify that the AppTransaction was signed by the App Store and that it belongs to your app and the customer’s device.
We want to provide you as much information as possible about subscriptions and offers as you build your business strategy. This year, we added two fields to the AppTransaction type.
As of iOS 18.4, the AppTransaction type includes the appTransactionID field, which is back deployed to iOS 15. appTransactionID is a globally unique value for each Apple Account that downloads your app.
The appTransactionID is also unique for each family group member for apps that support Family Sharing. With appTransactionID, you can now do things like associate distinct original Transaction IDs without a server-to-server call.
iOS 18.4 also introduced the originalPlatform field.
originalPlatform is of a new type called AppStore.Platform.
This value represents the platform on which the customer originally purchased your app.
iOS, macOS, tvOS, or visionOS. These values match the target platforms available in App Store Connect.
Apps people download on watchOS have the originalPlatform field set to iOS.
With the originalPlatform field, you can now more easily support business model changes, such as moving from a paid app to a free app with In-App Purchases.
The originalPlatform field can help you entitle customers appropriately as your business evolves over time. Next, we have updates to the Transaction type. A Transaction represents a successful In-App Purchase and contains useful information about the purchase. The Transaction includes the date of the purchase, the productID of the In-App Purchase, and in the case of auto-renewable subscriptions, the date the subscription expires. Transaction is primarily used to validate customer entitlement and unlock content.
Your app identifies the content it should unlock by using the productID field.
The system yields a Transaction either in-line after a purchase successfully completes or through one of the Transaction sequences, such as Transaction.currentEntitlements. Regardless of how you retrieve Transactions, Transactions are always wrapped in a verification result, similar to AppTransactions.
This means you don’t need to worry about manually verifying the Transaction, since StoreKit 2 handles that for you automatically. Speaking of current entitlements, starting with iOS 18.4, the Transaction.currentEntitlement for productID API is deprecated and is replaced by the new Transaction.currentEntitlements API. Call this new API by passing a productID. This API returns an asynchronous sequence of Transactions that entitle the customer to a given product. Because a customer can have more than one Transaction that entitles them to a product, for example, if they own a subscription but also have access to it through Family Sharing, it’s recommended you adopt this API in your project.
New this year, the Transaction model has three additional fields.
The appTransactionID field, which is back deployed to iOS 15, is a unique identifier of the app download Transaction. This is the same value that the AppTransaction type contains, which I discussed earlier. iOS 18.4 also introduced the Offer Period field, which is contained in the offer member. Offer Period is the subscription period associated with a subscription offer a customer redeems at the time of purchase.
The final new field introduced in iOS 18.4 is advancedCommerceInfo.
AdvancedCommerceInfo only applies to apps that use the Advanced Commerce API. For apps that don’t use the Advanced Commerce API, this field is always nil.
Advanced Commerce API enables you to more easily support In-App Purchases for large content catalogs, creator experiences, and subscriptions with optional add-ons.
To support the Advanced Commerce API, StoreKit 2 provides new native APIs, including AdvancedCommerceProduct, which is available in iOS 18.4, and existing APIs, like Transaction and SubscriptionStatus.
To learn more about the Advanced Commerce API, please visit the list of webpage resources for this session.
Lastly, let’s review our updates to the RenewalInfo type.
The RenewalInfo type is specifically for auto-renewable subscriptions. RenewalInfo contains information such as whether the subscription will auto-renew, the date of the next subscription renewal, and for subscribers such subscriptions have expired, the reason the subscription expired.
An example of how you could use the subscription expiration reason is if you recently increased the price of your service, and the expiration reason is didNotConsentToPriceIncrease. This would be a good time to merchandise a win-back offer and encourage the customer to resubscribe to your service.
StoreKit makes available RenewalInfo values as a wrapped VerificationResult member on SubscriptionStatus instances. You can attain a SubscriptionStatus in several ways, such as through the SubscriptionStatus updates API, or by querying StoreKit for subscription statuses using a subscription group ID. As a reminder, when you query StoreKit for subscription statuses using a subscription group ID, be sure to provide access to your app service based on the SubscriptionStatus that offers the highest service level, as outlined in your business model.
Also new beginning with iOS 18.4 is the SubscriptionStatus API that takes a Transaction ID. Now, you can query StoreKit for a subscription status using the Transaction ID of any Transaction associated with a subscription. This year, we introduced four additional fields to the RenewalInfo type.
The appTransactionID field is back deployed to iOS 15, and the Offer Period and advancedCommerceInfo fields are available beginning with iOS 18.4.
We also added the appAccountToken field, which associates a subscription with a customer account on your service.
You optionally provide an appAccountToken at the time of purchase using the appAccountToken purchase option.
The App Store returns this same value in the new appAccountToken field for the RenewalInfo associated with the subscription. To access these new fields, all you need to do is build your app using the latest Xcode. We think these new fields will make developing your app even easier and will help you deliver a better customer experience. Now, I’d like to shift focus and discuss offer codes. These are alphanumeric codes that enable you to provide subscriptions at a discount or for free for a specific duration.
Customers can redeem offer codes in the App Store using one-time redemption URLs or in your app if you implement the offer code Redemption StoreKit APIs.
I’m excited to share offer codes are now available for consumables, non-consumables, and non-renewing subscriptions. Customers can redeem offer codes within your app through the offerCodeRedemption API. If your app uses UIKit, you use the presentOfferCodeRedeemSheet API.
Redeeming offer codes for consumables, non-consumables, and non-renewing subscriptions is available back to iOS 16.3. The Transaction generated by a successful offer code redemption is available on any OS version using the StoreKit 2 APIs. If your app supports even earlier OS versions, customers can redeem offer codes for auto-renewable subscriptions all the way back to iOS 14.2.
To support offer code redemptions for product types other than auto-renewable subscriptions, we introduced a new payment mode on the Transaction.Offer.PaymentMode type. This describes how the customer is charged or not charged during the offer period, depending on the offer type. It represents various payment modes including cases like freeTrial where no payment is required. The other payment modes include payAsYouGo and payUpFront. Now in iOS, you can expect the oneTime payment mode for In-App Purchase offer codes which is available back to iOS 17.2.
If your app supports OS versions prior to 17.2 you can access this new payment mode through the offerPaymentModeStringRepresentation member on Transaction which is available as far back as iOS 15.
If you’re looking to dive deeper into setting up In-App Purchase offer codes, check out the 2025 session, “What’s new in App Store Connect?” Also beginning in iOS 18.2, StoreKit has added purchase methods that require a UI context. Your app needs to specify the UI context where a purchase originates to ensure the system can display the payment sheet and success dialog in the most intuitive region of the device’s active scene.
These new purchase methods are available beginning with iOS 18.2 and aligned releases. The UI context you provide differs by platform.
On iOS, macCatalyst, tvOS, and visionOS, the UI context is a UIViewController. On macOS, it’s an NSWindow. If you're developing for watchOS, you don't provide UI context.
If you’re purchasing from a SwiftUI view, you don’t perform this calculation on your own.
Instead, read the purchase environment value to get a PurchaseAction instance.
When you're ready to perform a purchase, You call the PurchaseAction instance directly because it defines a callAsFunction method that Swift calls when you call the instance.
If you’re using StoreKit views, you don’t have to worry about providing the UI context.
The system handles it for you automatically. To learn how to implement a best-in-class In-App Purchase experience for your customers using ProductView, StoreView, and SubscriptionStoreView, check out our WWDC 23 session, Meet StoreKit for SwiftUI. Now that we’ve explored the core API enhancements, I want to draw your attention to another important update. This year, we’ve introduced new APIs that require a JSON web signature.
Let’s explore these new APIs and how you can use the App Store Server Library in your development workflow to simplify the signing process.
New this year, you can set a customer’s eligibility for an introductory offer using the introductoryOfferEligibility purchase option. You can also now sign your promotional offers using the JWS format with the new promotionalOffer purchase option.
These new purchase options both require a compact JWS string and are back deployed to iOS 15.
We also introduced new SwiftUI view modifiers to go along with each of these purchase options. Using JWS helps the App Store verify that you authorized the purchase for specific use cases, like setting a customer’s eligibility for a promotional offer or an intro offer.
To make signing your requests as easy as possible, we have great open source tools like the App Store Server Library that simplify the signing process.
To see just how fast it is to create signed requests for your app, let’s see how we would sign a promotional offer in SKDemo.
Before we get started, you’ll first need to retrieve your In-App Purchase signing key from App Store Connect. You can do this by navigating to the Users & Access tab, clicking on the Integrations header, and choosing In-App Purchases in the left navigation.
You can use any active key or create a new key.
You’ll want to make a note of the issuer ID and key ID of your In-App Purchase signing key. Now that you have an In-App Purchase signing key, let’s view the in-app subscription store in SKDemo. Our subscription store merchandises the plans available for a customer to purchase. I’d like to reacquire subscribers whose subscriptions have expired.
To do this, I’ll merchandise a promotional offer on the Pro plan using the new JWS-based subscriptionPromotionalOffer modifier.
This modifier expects two closures.
In the first closure, you provide the subscription offer that should apply to the purchase of a given subscription. For this example, I’ll choose the promotional offer that has the longest free trial period for the Pro Plan using a helper method I created earlier. The second closure of this modifier expects a compact JWS containing the signed offer details.
Here, this is provided to us by the NetworkLayer type. Let’s take a closer look at what that implementation looks like.
In ourNetworkLayer, we pass the productID and offer ID for our product and subscription offer as query parameters for the request.
Then, we perform a GET request to the promotion offer signing route on our server.
Finally, we decode the response.
On your server project, you begin by adding the App Store Server Library Swift package dependency and importing the App Store Server Library. In your implementation of the route responsible for handling promotion offer signing requests, you create a promotional signing context by initializing a PromotionOfferV2SignatureCreator with your app’s bundle ID, the signing key, key ID, and issuer ID you retrieved from App Store Connect earlier.
Then, you call the createSignature function and provide the productID for the subscription being purchased and the offer ID of the subscription offer.
It’s also good practice to include a value for the Transaction ID field.
This value can be the appTransactionID or the TransactionID of any Transaction that belongs to the customer. Although the TransactionID field is optional, it is recommended to include it.
Back in the app, the promotional offer can now be successfully redeemed and the purchase completes without incident.
And that’s how you can create signed In-App Purchase requests using the App Store Server Library.
Signing your In-App Purchase requests helps the App Store verify that you authorized a purchase.
Integrating with the App Store Server Library makes signing your requests easy. And best of all, the App Store Server Library is available in four languages: Java, Python, Node.js, and Swift. To get started with the App Store Server Library, check out our WWDC24 session, Explore App Store server APIs for In-App Purchase. For our final set of updates, let’s review a new way to use SwiftUI to engage with customers in your app.
I’m excited to introduce the newest member to the StoreKit views family, the SubscriptionOfferView. This is a new SwiftUI view for merchandising and auto-renewable subscription and is designed to capture your customer’s attention about your app’s service. You declare a SubscriptionOfferView using an already loaded auto-renewable subscription, or by using the productID for an auto-renewable subscription. When declared this way, the view does all the work of loading the product metadata from the App Store. You can optionally use the subscription image you set up in App Store Connect to decorate the view by setting the prefersPromotionalIcon flag to true. The decorative icon is displayed when the system finishes loading the subscription metadata.
If you prefer to use a custom icon to decorate the view, you can use the alternate spelling of this API and pass in a trailing ViewBuilder closure.
You can also provide a custom placeholder icon, which is shown while the subscription metadata is being downloaded from the App Store server.
The SubscriptionOfferView is capable of merchandising more than just an individual subscription plan. When paired with the new subscriptionOfferViewDetailAction modifier, you can use this view to, for example, direct customer traffic to your in-app subscription store. Declaring this modifier draws the detailLink button on the view.
When a customer taps the detailLink button, the view calls to close your path to this modifier.
Here's an example in SKDemo.
I modify some state in ContentView that controls the presentation method of the app’s user flow. When the customer taps the detailLink button, the customer is taken to the app’s subscription store to view subscription plans available for purchase. An important consideration when deciding to use this API is which subscription plan to merchandise or whether it should even be displayed at all. Let’s head back into the code for an example of how to use this API. Knowing which subscription plan to merchandise with a SubscriptionOfferView begins with determining the customer’s subscription status. In apps written using SwiftUI, the most convenient place to do this is in your implementation of the App protocol.
You then use this data to inform the rest of your view hierarchy.
You can do this by declaring the subscriptionStatusTask modifier introduced in iOS 17.
Then, you translate the subscription statuses from StoreKit in this modifier into a model your app understands. In SKDemo, this model is called SKDemoPlusStatus. You then update a source of truth in your view that tracks a status and vend it through the environment using an environment variable.
Now that I have the customer status, I’ll use this to display a SubscriptionOfferView in ContentView.
Here, I read the environment value containing the customer status and decide to either merchandise a standard plan if the customer isn’t an active subscriber or higher tier plans if the customer’s already subscribed.
To keep my code more concise, I’ll use the group ID initializer to create my SubscriptionOfferView.
When declared this way, the system automatically chooses a plan from my subscription group.
You’ll also need to specify the relationship of the merchandised plan relative to the customer’s current plan. The visibleRelationship parameter can be one of five values: upgrade, downgrade, crossgrade, current, and all. This API behaves differently depending on the customer’s status. Let’s take a closer look at each of these relationships, starting with upgrade. For demonstration purposes, let’s assume the customer in our example is subscribed to the middle-tier plan.
Specifying upgrade causes the view to merchandise a subscription plan which is one level higher than the current plan. The inverse happens for the downgrade relationship. In this example, the subscribed and unsubscribed customer would see the same plan. You may want to merchandise a more affordable plan if your customer has turned off auto-renew and you want to retain them before the renewal cycle ends.
The crossgrade option considers the plans in the group whose tier is equivalent to the current plan, and chooses the best value option among those. With the current relationship, the customer’s current plan is merchandised. By default, all interactions are disabled unless there is a subscription offer available to redeem. You mark a customer as eligible for an offer using any of the offer modifiers, such as the new subscriptionPromotionalOffer modifier and the preferredSubscriptionOffer modifier. A great use of this relationship is to merchandise a discount for an expiring subscription to help retain subscribers.
Finally, the all relationship. This relationship behaves the same for all customers. When initialized this way, the view displays pricing information about all the plans in your group. You provide the action to be performed on the view by declaring the subscriptionOfferViewDetailAction modifier. Regardless of which relationship you create a SubscriptionOfferView with, you can also decorate it using a custom icon and placeholder icon, similar to the example earlier in the session. There’s also a convenience to use your app’s icon.
Just set the useAppIcon flag to true.
And that wraps-up the new SubscriptionOfferView, an exciting way to engage with your customers. Today, I covered numerous StoreKit API enhancements that will help you deliver a great in-app purchase experience to your customers.
To utilize these new features, now is a great time to adopt StoreKit 2 in your project, if you haven’t already. To get the latest designs and create an excellent store in your app, use StoreKit views to merchandise your In-App Purchases and subscriptions.
Check out the App Store Server Library on GitHub and integrate it into your project to make signing In-App Purchase requests as easy as possible.
To learn more about App Store server APIs, we have a new WWDC25 session, Dive into App Store server APIs for In-App Purchase. And to get started adopting StoreKit 2, our WWDC21 session, Meet StoreKit 2, is an excellent starting point. Thanks for joining me today. I’m excited to see what you build using StoreKit.
-