-
What’s new in StoreKit 2 and StoreKit Testing in Xcode
Get to know the latest enhancements to StoreKit 2 and StoreKit Testing in Xcode. Discover API updates for promoted in-app purchases, StoreKit messages, the Transaction model, the RenewalInfo model, and the App Store sheet for managing subscriptions. Learn how to upgrade to SHA-256 for on-device receipt validation and use APIs to create SwiftUI views.
We'll also help you get started with StoreKit Testing in Xcode so that you can debug and test your in-app purchases and subscriptions. Meet the Transaction Inspector, explore the latest updates to the StoreKit configuration editor, and find out how you can simulate StoreKit errors to test your app's error handling.Recursos
- Testing failing subscription renewals and In-App Purchases
- Message
- Supporting promoted In-App Purchases in your app
- Turn on Family Sharing for in-app purchases in App Store Connect
- Setting up StoreKit Testing in Xcode
- Submit feedback
- StoreKit
Vídeos relacionados
WWDC23
WWDC22
WWDC21
-
Buscar neste vídeo...
-
-
1:42 - Create a listener for promoted in-app purchases
// Create a listener for promoted in-app purchases import StoreKit let promotedPurchasesListener = Task { for await promotion in PurchaseIntent.intents { // Process promotion let product = promotion.product // Purchase promoted product do { let result = try await product.purchase() // Process result } catch { // Handle error } } } -
2:57 - Check promotion order
// Check promotion order import StoreKit do { let promotions = try await Product.PromotionInfo.currentOrder if promotions.isEmpty { // No local promotion order set } for promotion in promotions { let productID = promotion.productID let productVisibility = promotion.visibility // Check promoted products } } catch { // Handle error } -
3:26 - Set a promotion order
// Set a promotion order import StoreKit let newPromotionOrder: [String] = [ "acorns.individual", "nectar.cup", "sunflowerseeds.pile" ] do { try await Product.PromotionInfo.updateProductOrder(byID: newPromotionOrder) } catch { // Handle error } -
4:02 - Update promotion visibility
// Update promotion visibility import StoreKit // Hide “acorns.individual” do { try await Product.PromotionInfo.updateProductVisibility(.hidden, for: "acorns.individual") } catch { // Handle error } -
4:17 - Update promotion visibility (alternative method)
// Update promotion visibility import StoreKit do { let promotions = try await Product.PromotionInfo.currentOrder // Hide the first product if var firstPromotion = promotions.first { firstPromotion.visibility = .hidden try await firstPromotion.update() } } catch { // Handle error } -
8:32 - Product view
// Product view import SwiftUI import StoreKit struct BirdFoodShop: View { let productID: String let productImage: String var body: some View { ProductView(id: productID) { BirdFoodProductIcon(for: productID) } .productViewStyle(.large) } } -
8:52 - Store view
// Store view import SwiftUI import StoreKit struct BirdFoodShop: View { let productIDs: [String] var body: some View { StoreView(ids: productIDs) { product in BirdFoodIcon(productID: product.id) } } } -
9:19 - Subscription view
// Subscription view import SwiftUI import StoreKit struct BackyardBirdsPassShop: View { let groupID: String var body: some View { SubscriptionStoreView(groupID: groupID) } } -
21:09 - Simulated off-device purchase using StoreKitTest
// Simulated off-device purchase using StoreKitTest import StoreKit import StoreKitTest func testSubscriptionRenewal() async throws { let session = try SKTestSession(configurationFileNamed: "Store") let oneYearInterval: TimeInterval = (365 * 24 * 60 * 60) let transaction = try await session.buyProduct( identifier: "birdpass.individual", options: [ .purchaseDate(Date.now - oneYearInterval) ] ) // Inspect transaction } -
21:48 - Set a simulated purchase error when loading products
// Set a simulated purchase error when loading products import StoreKit import StoreKitTest func testLoadProducts() async throws { let session = try SKTestSession(configurationFileNamed: "Store") let productIDs = [ "acorns.individual", "nectar.cup" ] // Set a simulated error, then load products, expecting an error session.setSimulatedError(.generic(.networkError), forAPI: .loadProducts) do { _ = try await Product.products(for: productIDs) XCTFail("Expected a network error") } catch StoreKitError.networkError(_) { // Expected error thrown, continue... } // Disable simulated error session.setSimulatedError(nil, forAPI: .loadProducts) } -
22:24 - Set a faster subscription renewal rate in a test session
// Set a faster subscription renewal rate in a test session import StoreKit import StoreKitTest func testSubscriptionRenewal() async throws { let session = try SKTestSession(configurationFileNamed: "Store") // Set renewals to expire every minute session.timeRate = .oneRenewalEveryMinute let transaction = try await session.buyProduct(identifier: "birdpass.individual") // Wait for renewals and inspect transactions }
-