View in English

  • Apple Developer
    • Get Started

    Explore Get Started

    • Overview
    • Learn
    • Apple Developer Program

    Stay Updated

    • Latest News
    • Hello Developer
    • Platforms

    Explore Platforms

    • Apple Platforms
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store

    Featured

    • Design
    • Distribution
    • Games
    • Accessories
    • Web
    • Home
    • CarPlay
    • Technologies

    Explore Technologies

    • Overview
    • Xcode
    • Swift
    • SwiftUI

    Featured

    • Accessibility
    • App Intents
    • Apple Intelligence
    • Games
    • Machine Learning & AI
    • Security
    • Xcode Cloud
    • Community

    Explore Community

    • Overview
    • Meet with Apple events
    • Community-driven events
    • Developer Forums
    • Open Source

    Featured

    • WWDC
    • Swift Student Challenge
    • Developer Stories
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Centers
    • Documentation

    Explore Documentation

    • Documentation Library
    • Technology Overviews
    • Sample Code
    • Human Interface Guidelines
    • Videos

    Release Notes

    • Featured Updates
    • iOS
    • iPadOS
    • macOS
    • watchOS
    • visionOS
    • tvOS
    • Xcode
    • Downloads

    Explore Downloads

    • All Downloads
    • Operating Systems
    • Applications
    • Design Resources

    Featured

    • Xcode
    • TestFlight
    • Fonts
    • SF Symbols
    • Icon Composer
    • Support

    Explore Support

    • Overview
    • Help Guides
    • Developer Forums
    • Feedback Assistant
    • Contact Us

    Featured

    • Account Help
    • App Review Guidelines
    • App Store Connect Help
    • Upcoming Requirements
    • Agreements and Guidelines
    • System Status
  • Quick Links

    • Events
    • News
    • Forums
    • Sample Code
    • Videos
 

Vidéos

Ouvrir le menu Fermer le menu
  • Collections
  • Toutes les vidéos
  • À propos

Plus de vidéos

  • À propos
  • Code
  • Implement proactive in-app purchase restore

    Learn how you can restore someone's in-app purchases access proactively when they first open your app. We'll show you how you can deliver instant access to existing subscriptions using StoreKit or StoreKit 2 and cover best practices for both your client and server implementations. Find out more about how you can determine customer purchase state and create a personalized onboarding experience for your app.

    Ressources

    • Implementing a store in your app using the StoreKit API
    • Introducing StoreKit 2
    • App Store Server Notifications
    • Determining service entitlement on the server
    • Reducing Involuntary Subscriber Churn
    • CloudKit
      • Vidéo HD
      • Vidéo SD

    Vidéos connexes

    WWDC22

    • Explore in-app purchase integration and migration
    • What's new with in-app purchase

    WWDC21

    • Meet StoreKit 2

    Tech Talks

    • Support customers with StoreKit 2 and App Store Server API

    WWDC20

    • Architecting for subscriptions
  • Rechercher dans cette vidéo…
    • 11:16 - Transaction Listener at app launch

      //Transaction Listener at app launch
      func listenForTransactions() -> Task<Void, Error> {
          return Task.detached {
              //Iterate through any transactions which didn't come from a direct call to `purchase()`.
              for await result in Transaction.updates {
                  do {
                      let transaction = try self.checkVerified(result)
                      
                      //Deliver products to the user.
                      await self.updateCustomerProductStatus()
                      
                      //Always finish a transaction
                      await transaction.finish()
                      
                  } catch {
                      //StoreKit transaction failed verification, don't deliver content to user.
                      print("Transaction failed verification")
                  }
              }
          }
      }
    • 12:27 - Determine customer product state

      //Determine customer product state
      func updateCustomerProductStatus() async {
         
          var purchasedCars: [Product] = []
          var purchasedSubscriptions: [Product] = []
          var purchasedNonRenewableSubscriptions: [Product] = []
      
          //Iterate through all of the user's purchased products.
          for await result in Transaction.currentEntitlements {
      
             do {
               //First check if the transaction is verified. If the transaction is not verified
               //we'll catch the `failedVerification` error.
               let transaction = try checkVerified(result)
      
               //Check the `productType` of the transaction and get the corresponding product 
                 from the store.
               switch transaction.productType {
      
               case .nonConsumable:
                          
                   if let car = cars.first(where: { $0.id == transaction.productID }) {
                              purchasedCars.append(car)
                   }
               //..
    • 12:56 - Determine customer product state

      //Determine customer product state
      
      case .nonRenewable:
       
          if let nonRenewable = nonRenewables.first(where: { $0.id == transaction.productID }),
                transaction.productID == "nonRenewing.standard" {
      
       //Non-renewing subscriptions have no inherent expiration. 
               
           let currentDate = Date()
           let expirationDate = Calendar(identifier: .gregorian).date(byAdding:
                                                          DateComponents(year: 1),
                                                          to: transaction.purchaseDate)!
      
          if currentDate < expirationDate {
              purchasedNonRenewableSubscriptions.append(nonRenewable)
      
            }
         }
      //..
    • 13:09 - Determine customer product state

      //Determine customer product state
      
      case .autoRenewable:
        
        if let subscription = subscriptions.first(where: { $0.id == transaction.productID }) {
      purchasedSubscriptions.append(subscription) }
           default:
             break
            }
        } catch {
            print()
        }
      }
      //Update the Store information with the purchased products.
      self.purchasedCars = purchasedCars
      self.purchasedNonRenewableSubscriptions = purchasedNonRenewableSubscriptions
      self.purchasedSubscriptions = purchasedSubscriptions
      
      //Check subscriptionGroupStatus to learn auto-renewable subscription state
      subscriptionGroupStatus = try? await subscriptions.first?.subscription?.status.first?.state
      
      }
    • 13:45 - Updating my car view at app launch

      //Updating my car view at app launch
      
      if store.purchasedCars.isEmpty && store.purchasedNonRenewableSubscriptions.isEmpty 
                                     && store.purchasedSubscriptions.isEmpty {
              
                     VStack {
                          Text("SK Demo App")
                              .bold()
                              .font(.system(size: 50))
                              .padding(.bottom, 20)
                          Text("🏎💨")
                              .font(.system(size: 120))
                              .padding(.bottom, 20)
                          Text("Head over to the shop to get started!")
                              .font(.headline)
                          NavigationLink {
                              StoreView()
                          }
                  //…
      
           }
         }
      }
    • 13:59 - Updating my car view at app launch

      //Updating my car view at app launch
      
      else {
          List {
              Section("My Cars") {
                
              if !store.purchasedCars.isEmpty {
                   
                    ForEach(store.purchasedCars) { product in
                        NavigationLink {
                            ProductDetailView(product: product)
                       } label: {
                            ListCellView(product: product, purchasingEnabled: false)
                      }
                 } 
                     } else {
      
                Text("You don't own any car products. \nHead over to the shop to get started!")
      
            }
         }
      //…
    • 14:20 - Updating my car view at app launch

      //Updating my car view at app launch
      
      Section("Navigation Service") {
         
           if !store.purchasedNonRenewableSubscriptions.isEmpty || 
               !store.purchasedSubscriptions.isEmpty {
      
                ForEach(store.purchasedNonRenewableSubscriptions) { product in
                     NavigationLink {
                        ProductDetailView(product: product)
                    } label: {
                        ListCellView(product: product, purchasingEnabled: false)
                    }
                }
      
                ForEach(store.purchasedSubscriptions) { product in
                     NavigationLink {
                         ProductDetailView(product: product)
                     } label: {
                         ListCellView(product: product, purchasingEnabled: false)
                    }
              }
          }
    • 14:30 - Updating my car view at app launch

      //Updating my car view at app launch
      
      else  {
             
        if let subscriptionGroupStatus = store.subscriptionGroupStatus {
                                    
           if subscriptionGroupStatus == .expired || subscriptionGroupStatus == .revoked {
                                         
               Text("Welcome Back! \nHead over to the shop to get started!")
                         
           } else if subscriptionGroupStatus == .inBillingRetryPeriod {
                                         
              //Provide a deep link from your app to https://apps.apple.com/account/billing.
               Text("Please verify your billing details.")
                                     
           }
           } else {
      
             Text("You don't own any subscriptions. \nHead over to the shop to get started!")
           }
         }         
      }
    • 17:42 - Fetch App Receipt Data

      //Fetch App Receipt Data
      
      public func getReceipt() {
      
          if let appStoreReceiptURL = Bundle.main.appStoreReceiptURL,
              FileManager.default.fileExists(atPath: appStoreReceiptURL.path) {
      
              do {
                  let receiptData = try Data(contentsOf: appStoreReceiptURL, 
                                                options: .alwaysMapped)
                  print(receiptData)
                  
                  let receiptString = receiptData.base64EncodedString(options: [])
                  
                  print("receipt send it to your server: \(receiptString)")
      
                  // Read receiptData
              }
              catch { 
                  print("Couldn't read receipt data with error: " + error.localizedDescription) 
              }
          }
      }

Developer Footer

  • Vidéos
  • WWDC22
  • Implement proactive in-app purchase restore
  • Open Menu Close Menu
    • iOS
    • iPadOS
    • macOS
    • tvOS
    • visionOS
    • watchOS
    • App Store
    Open Menu Close Menu
    • Swift
    • SwiftUI
    • Swift Playground
    • TestFlight
    • Xcode
    • Xcode Cloud
    • Icon Composer
    • SF Symbols
    Open Menu Close Menu
    • Accessibility
    • Accessories
    • Apple Intelligence
    • Audio & Video
    • Augmented Reality
    • Business
    • Design
    • Distribution
    • Education
    • Games
    • Health & Fitness
    • In-App Purchase
    • Localization
    • Maps & Location
    • Machine Learning & AI
    • Security
    • Safari & Web
    Open Menu Close Menu
    • Documentation
    • Downloads
    • Sample Code
    • Videos
    Open Menu Close Menu
    • Help Guides & Articles
    • Contact Us
    • Forums
    • Feedback & Bug Reporting
    • System Status
    Open Menu Close Menu
    • Apple Developer
    • App Store Connect
    • Certificates, IDs, & Profiles
    • Feedback Assistant
    Open Menu Close Menu
    • Apple Developer Program
    • Apple Developer Enterprise Program
    • App Store Small Business Program
    • MFi Program
    • Mini Apps Partner Program
    • News Partner Program
    • Video Partner Program
    • Security Bounty Program
    • Security Research Device Program
    Open Menu Close Menu
    • Meet with Apple
    • Apple Developer Centers
    • App Store Awards
    • Apple Design Awards
    • Apple Developer Academies
    • WWDC
    Read the latest news.
    Get the Apple Developer app.
    Copyright © 2026 Apple Inc. All rights reserved.
    Terms of Use Privacy Policy Agreements and Guidelines