Upgrade to Pro — share decks privately, control downloads, hide ads and more …

StoreKitのこれまでとこれから / StoreKit 2 from 1

2d855b951ff3160c55915821261432f9?s=47 uzzu
September 17, 2021

StoreKitのこれまでとこれから / StoreKit 2 from 1

2d855b951ff3160c55915821261432f9?s=128

uzzu

September 17, 2021
Tweet

Transcript

  1. StoreKitͷ͜Ε·Ͱͱ͜Ε͔Β uzzu @ iOSDC JAPAN 2021

  2. ࣗݾ঺հ ɾ@uzzu 
 ɾCookpad Inc. ٕज़෦ Ϣʔβܾࡁج൫άϧʔϓ 
 ɾݞॻ͸AndroidΤϯδχΞɺ࠷ۙ͸Rails 


    ɾલ৬͸εϚʔτϑΥϯήʔϜ։ൃ 
 ɾझຯ͸VR
  3. IAPؔ࿈ͷ͓࢓ࣄ(1/2) https://speakerdeck.com/uzzu/xin-gui-apurikai-fa-wozhi-eruyuzajue-ji-ji-pan

  4. IAPؔ࿈ͷ͓࢓ࣄ(2/2) https://speakerdeck.com/uzzu/xin-gui-apurikai-fa-wozhi-eruyuzajue-ji-ji-pan

  5. IAPؔ࿈ͷ͓࢓ࣄ(2/2) https://speakerdeck.com/uzzu/xin-gui-apurikai-fa-wozhi-eruyuzajue-ji-ji-pan できた!(iOS クックパッド 2021/03)

  6. 🎊StoreKit2🎊 WWDC21

  7. ΞδΣϯμ ɾΞϓϦ಺՝࣮ۚ૷ͷ֓ཁ 
 ɾStoreKitͱStoreKit2ͷҧ͍(ߪೖɾ෮ݩػೳΛ௥͍ͳ͕Β) 
 ɾStoreKit2Ͱ৽ͨʹͰ͖Δࣄ 
 ɾ·ͱΊ

  8. ࿩͞ͳ͍ࣄ • Promoting IAPɺSubscription Offerɺ 
 Family Sharing SubscriptionͳͲͷOptionalͳܾࡁػೳ •

    ΞϓϦ಺՝ۚҎ֎ͷStoreKitͷػೳ(SKOverlay౳) • App Store Server APIͷৄࡉ • async/awaitͷৄࡉ • StoreKitͱStoreKit2͕ڞଘͨ͠৔߹ͷڍಈ
  9. ஫ҙࣄ߲ ⚠ ɾStoreKit2͸ݱࡏsandbox՝ۚ΋ࣦഊ͢Δ(iOS15 beta8) 
 ɹStoreKit TestingΛར༻͢ΔࣄͰಈ࡞͠·͢ 
 ɹhttps://developer.apple.com/forums/thread/681904 ɾStoreKit

    Testing ར༻ʹ͓͍ͯXcode 13 beta 5࣌఺Ͱ 
 ɹچStoreKitͱͷڠௐಈ࡞ͷ֬ೝ͕औΕͳ͍ 
 ɹ=> ڞଘͨ͠৔߹ͷಈ࡞͕Ͳ͏ͳΔͷ͔౳ࡉ͔͍ॴ͸ݱঢ়෼͔Βͳ͍ 
 ɾ࢖͑ΔΑ͏ʹͳΔͷ͸ iOS15 ʙ (async/await backport ૣ͘དྷͯ͘Εʙ) 
 ɾಈ͘Α͏ʹͳͬͨΒ࠶ݕূ͠·͠ΐ͏
  10. ΞδΣϯμ ɾΞϓϦ಺՝࣮ۚ૷ͷ֓ཁ 
 ɾStoreKitͱStoreKit2ͷҧ͍(ߪೖɾ෮ݩػೳΛ௥͍ͳ͕Β) 
 ɾStoreKit2Ͱ৽ͨʹͰ͖Δࣄ 
 ɾ·ͱΊ

  11. ΞϓϦ಺՝ۚͷ࣮૷ͷ֓ཁ(1/2) ɾΞϓϦ಺Ͱσδλϧίϯςϯπͷൢച΍ఆظߪಡػೳΛ 
 ɹఏڙ͢Δࡍʹ͸ΞϓϦ಺՝ۚͷ࣮૷͕ඞཁ ɾΞϓϦ಺՝ۚͷ঎඼λΠϓ͸4छ 
 ɹফ໣ܕΞΠςϜ(Consumable) 
 ɹඇফ໣ܕΞΠςϜ(Non-Consumable) 


    ɹࣗಈߋ৽αϒεΫϦϓγϣϯ(Auto-Renewable Subscription) 
 ɹඇࣗಈߋ৽αϒεΫϦϓγϣϯ(Non-Renewing Subscription)
  12. ΞϓϦ಺՝ۚͷ࣮૷ͷ֓ཁ(1/2) ɾͦΕͧΕఏڙ͢Δҝʹ࣮૷ඞਢͳػೳ 
 ɹߪೖ 
 ɹ෮ݩ 
 ɾͦͷଞɺඞਢͰ͸ͳ͍͕ඞཁʹԠ࣮ͯ͡૷ΛٻΊΒΕΔػೳ 
 ɹPromoting

    IAP .. App Store ΞϓϦ্Ͱͷ঎඼ͷϓϩϞʔγϣϯɺߪೖ 
 ɹSubscription Offer .. ೚ҙͷϢʔβʹ௿Ձ֨Ͱఏڙ͢Δ 
 ɹFamily Sharing Subscription .. ϑΝϛϦʔڞ༗ͷػೳͰఆظߪೖΛڞ༗͢Δ
  13. ΞδΣϯμ ɾΞϓϦ಺՝࣮ۚ૷ͷ֓ཁ 
 ɾStoreKitͱStoreKit2ͷҧ͍(ߪೖɾ෮ݩػೳΛ௥͍ͳ͕Β) 
 ɾStoreKit2Ͱ৽ͨʹͰ͖Δࣄ 
 ɾؔ࿈ͯ͠AppStore Server API

  14. ߪೖɾ෮ݩͷઆ໌ʹೖΔલʹ…ॳظԽʹ͍ͭͯ ɾچStoreKit͸ΞϓϦ಺՝ۚͷ࣮૷ʹඞཁͳ 
 ɹ֤छ௨஌Λड͚औΔҝͷObserverͷ࣮૷ͱొ࿥ॲཧ 
 ɹ͕ඞཁɻຊεϥΠυͰ͸͜ΕΛศ্ٓॳظԽͱݺͿ ɾొ࿥ॲཧ .. SKPaymentTransactionObserverΛ࣮૷ͨ͠ 


    ɹΫϥεͷΠϯελϯεΛSKPaymentQueueʹొ࿥
  15. class AppDelegate: UIResponder, UIApplicationDelegate { private var iapObserver: SKPaymentTransactionObserver =

    IAPObserver() func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil ) -> Bool { SKPaymentQueue.default().add(iapObserver) return true } func applicationWillTerminate(_ application: UIApplication) { SKPaymentQueue.default().remove(iapObserver) } }
  16. ߪೖɾ෮ݩͷઆ໌ʹೖΔલʹ…ॳظԽʹ͍ͭͯ ॳظԽʹ·ͭΘΔτϥϒϧ 
 ɹɾΞϓϦىಈ࣌ͷॳظԽॲཧ(Ϣʔβೝূetc…)͕ 
 ɹɹऴΘͬͯͳ͍ঢ়ଶͰObserverॲཧͯ͠͠·͏ 
 ɹɾ௨஌͕͍ͭདྷͯ΋ྑ͍Α͏ͳ࣮૷ߟྀ͕͞Ε͍ͯͳ͍ 
 ɹɾSKPaymentQueue΁ͷremove/addΛ͓ͯ͠Βͣظ଴ͨ͠௨஌͕དྷͳ͍

    
 ɹɾ3rd party ϥΠϒϥϦ͕Observerొ࿥Λ͓ͯ͠Γ 
 ɹɹࣗΞϓϦͷObserverʹظ଴ͨ͠௨஌͕དྷͳ͍
  17. ߪೖɾ෮ݩͷઆ໌ʹೖΔલʹ…ॳظԽʹ͍ͭͯ StoreKit 2͸ॳظԽ͸ෆཁ🎉🎉🎉

  18. 購⼊処理フロー 購⼊ボタンを押す 注⽂番号を発⾏ 商品情報取得 決済 レシート送信 
 + 
 注⽂を有効にして

    
 購⼊した商品を 
 付与する レシート検証 
 最新レシート 
 取得 購⼊情報を 
 更新
  19. 購⼊処理フロー 購⼊ボタンを押す 注⽂番号を発⾏ 商品情報取得 決済 レシート送信 
 + 
 注⽂を有効にして

    
 購⼊した商品を 
 付与する レシート検証 
 最新レシート 
 取得 購⼊情報を 
 更新
  20. 購⼊処理フロー/商品情報の取得 .. 旧StoreKitの場合 public typealias ProductsRequestResult = Result<SKProductsResponse, Error> public

    typealias ProductsRequestCompletion = (ProductsRequestResult) -> Void public class ProductsRequest: NSObject, SKProductsRequestDelegate { private var completion: ProductsRequestCompletion? private var request: SKProductsRequest init(_ productIDs: Set<String>) { self.request = SKProductsRequest(productIdentifiers: productIDs) } public func send(completion: @escaping ProductsRequestCompletion) { self.completion = completion self.request.delegate = self self.request.start() } public func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) { if let completion = completion { self.completion = nil completion(.success(response)) } } public func request(_ request: SKRequest, didFailWithError error: Error) { if let completion = completion { self.completion = nil completion(.failure(error)) } } }
  21. 購⼊処理フロー/商品情報の取得 .. 旧StoreKitの場合 public typealias ProductsRequestResult = Result<SKProductsResponse, Error> public

    typealias ProductsRequestCompletion = (ProductsRequestResult) -> Void public class ProductsRequest: NSObject, SKProductsRequestDelegate { private var completion: ProductsRequestCompletion? private var request: SKProductsRequest init(_ productIDs: Set<String>) { self.request = SKProductsRequest(productIdentifiers: productIDs) } public func send(completion: @escaping ProductsRequestCompletion) { self.completion = completion self.request.delegate = self self.request.start() } public func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) { if let completion = completion { self.completion = nil completion(.success(response)) } } public func request(_ request: SKRequest, didFailWithError error: Error) { if let completion = completion { self.completion = nil completion(.failure(error)) } } } ɹɾdelegate method͕ݺ͹ΕΔεϨου͸อূ͞Ε͍ͯͳ͍ 
 ɹɹ=>ϝΠϯεϨουͰݺ͹ΕΔલఏͰ͍Δͱ 
 ɹɹɹޙଓॲཧ͕Ϋϥογϡ͢Δ(iOS 13.1ʙ) ɹɾ঎඼λΠϓ͕෼͔Βͳ͍ 
 ɹɹ=>productIdentifierͷ໋໊ΛϧʔϧԽ͢Δ౳ɺରࡦ͕ඞཁ ɹɾ঎඼৘ใऔಘ͢Δ͚ͩͳͷʹ 
 ɹɹίʔυྔ͕ଟ͍(هࡌͷίʔυͰ͸࣮ࡍ͸଍Γͳ͍)
  22. 購⼊処理フロー/商品情報の取得 .. StoreKit2の場合 let products = try await Product.products(for: ["productId"])

    ΋ͪΖΜ঎඼λΠϓ΋औಘՄೳ (Product.type) 🥳🥳🥳🥳🥳🥳🥳🥳🥳 🥳🥳🥳🥳🥳🥳🥳🥳🥳
  23. 購⼊処理フロー/決済 .. 旧StoreKitの場合 let payment = SKMutablePayment(product: product) // 様々オプションを指定

    SKPaymentQueue.default().add(payment) ↓ SKPaymentTransactionObserverの以下のdelegateが呼ばれる func paymentQueue( 
 _ queue: SKPaymentQueue, 
 updatedTransactions transactions: [SKPaymentTransaction]) { // : } ↓SKPaymentTransaction.transactionState == .purchasing でやってくる ↓SKPaymentTransactionObserverの同じdelegateが呼ばれる ↓IAP決済ダイアログが出てくる。ユーザが決済を⾏う ↓SKPaymentTransaction.transactionState == .purchased でやってくる ↓レシート送信、商品付与 ↓商品付与後、SKPaymentQueue.default().finishTransaction(transaction)
  24. ↓商品付与後、 購⼊処理フロー/決済 .. 旧StoreKitの場合 let payment = SKMutablePayment(product: product) //

    様々オプションを指定 SKPaymentQueue.default().add(payment) ↓ SKPaymentTransactionObserverの以下のdelegateが呼ばれる func paymentQueue( 
 _ queue: SKPaymentQueue, 
 updatedTransactions transactions: [SKPaymentTransaction]) { // : } ↓SKPaymentTransaction.transactionState == .purchasing でやってくる ↓SKPaymentTransactionObserverの同じdelegateが呼ばれる ↓IAP決済ダイアログが出てくる。ユーザが決済を⾏う ↓SKPaymentTransaction.transactionState == .purchased でやってくる ↓レシート送信、商品付与 SKPaymentQueue.default().finishTransaction(transaction) ɹɾupdatedTransactionsʹ͸ 
 ɹɹfinish͞Ε͍ͯͳ͍શͯͷTransaction͕΍ͬͯ͘Δ 
 ɹɹ=>ݱࡏߪೖதͷ঎඼͕Կ͔ΛͲ͔͜͠ΒͰ͓࣋ͬͯ͘ 
 ɹɹɹ ඞཁ͕͋Δ 
 ɹɾAsk To Buy(ϖΞϨϯλϧίϯτϩʔϧػೳ)ͷΑ͏ʹ 
 ɹɹܾࡁ׬ྃ௨஌͕όοΫάϥ΢ϯυ͔Β΍ͬͯ͘Δέʔε 
 ɹɹ͕͋ΔͷͰɺͦͷߟྀ΋ඞཁ ɹɾ΋ͪΖΜɺ঎඼λΠϓશͯͷTransaction͕΍ͬͯ͘Δ 
 ɹɹ=>঎඼λΠϓΛෳ਺ѻ͏Α͏ʹͳͬͨΒ 
 ɹɹɹ Observer͕େมͳࣄʹͳΔ 
 ɹɾ্هΛ౿·্͑ͨͰObserverͱ(Rx|Combine)ͱܨ͗͜Ή 
 ɹɹͷ͸Ͱ͖ͳ͘͸ͳ͍͕େม
  25. 購⼊処理フロー/決済 .. StoreKit2の場合 let result = try await product.purchase() 🎉🎉🎉🎉🎉🎉🎉🎉🎉

    🎉🎉🎉🎉🎉🎉🎉🎉🎉 Transaction#finish() ͸๨Εͣʹ
  26. 購⼊処理フロー/レシート検証、最新レシート取得 .. 旧StoreKitの場合 let base64EncodedReceipt: String? if let appStoreReceiptURL =

    Bundle.main.appStoreReceiptURL, FileManager.default.fileExists(atPath: appStoreReceiptURL.path) { base64EncodedReceipt = try? Data( contentsOf: appStoreReceiptURL, options: .alwaysMapped) .base64EncodedString() } else { base64EncodedReceipt = "" } ↓注⽂番号と合わせてサーバに送信 ↓POST https://buy.itunes.apple.com/verifyReceipt ↓最新レシート情報を元に商品付与、注⽂を有効にする ↓後続処理へ…
  27. 購⼊処理フロー/レシート検証、最新レシート取得 .. 旧StoreKitの場合 let base64EncodedReceipt: String? if let appStoreReceiptURL =

    Bundle.main.appStoreReceiptURL, FileManager.default.fileExists(atPath: appStoreReceiptURL.path) { base64EncodedReceipt = try? Data( contentsOf: appStoreReceiptURL, options: .alwaysMapped) .base64EncodedString() } else { base64EncodedReceipt = "" } ↓注⽂番号と合わせてサーバに送信 ↓POST https://buy.itunes.apple.com/verifyReceipt ↓最新レシート情報を元に商品付与、注⽂を有効にする ↓後続処理へ… ɹɾϨγʔτݕূࣗମ͸ΞϓϦ୯ମͰ΋Ͱ͖Δ͕ 
 ɹɹ؆қͳ΋ͷͳͷͰجຊతʹ͸࢖Θͳ͍ 
 ɹɾաڈͷಉΞϓϦͰͷߪೖ৘ใ͕શؚͯ·ΕΔҝ 
 ɹɹϖΠϩʔυαΠζ͕૿Ճ 
 ɹɹࣗಈߋ৽αϒεΫϦϓγϣϯͳΒߋ৽݄෼૿͑Δ 
 ɹɾϖΠϩʔυ͕େ͖͘ͳΔ΄ͲɺverifyReceiptͷ 
 ɹɹϨεϙϯε΋஗͘ͳΔɻΑ͘500Λు͘ ɹɹ=>exclude_old_transactions ͳΦϓγϣϯͰ 
 ɹɹɹߴ଎Խ͕ਤΕΔ͕ 
 ɹɹɹݹ͍ߪೖ৘ใ΋ඞཁͳϢʔεέʔε͸ 
 ɹɹɹ࣮ӡ༻্΅ͪ΅ͪ͋Δ
  28. 購⼊処理フロー/レシート検証、最新レシート取得 .. StoreKit2の場合 JWS化!レシート検証でサーバ間通信不要 
 巨⼤なレシート送らなくてもOK(代わりにJWS) 
 AppStore Server APIで個別にTransaction単位で問合せ可能に

    🍻🍻🍻🍻🍻🍻🍻🍻🍻 🍻🍻🍻🍻🍻🍻🍻🍻🍻 JWSがどれくらいのサイズになるだろうか…🤔
  29. ෮ݩͱ͸…ʁ ɾIAPܾࡁ͸ߦΘΕ͍ͯΔ͕঎඼͕෇༩͞Ε͍ͯͳ͍ 
 ɹϢʔβ΁ͷٹࡁાஔ 
 ɹ- ߪೖΤϥʔ͕ൃੜͨ͠··ܾࡁը໘͔Β཭୤ͯ͠͠·ͬͨ 
 ɹ- ػछมߋޙʹݩʑར༻͍ͯͨ͠ঢ়ଶʹ໭͍ͨ͠

    
 ɹ- ߪೖࡁΈͷ঎඼Λෳ਺୺຤Ͱར༻͍ͨ͠ ɾܾࡁ৘ใΛ෮ݩ͢Δػೳ͕ఏڙ͞Ε͍ͯΔͷͰ 
 ɹͦΕΛར༻ͯ͠෮ݩॲཧΛߦ͏ 

  30. ෮ݩͱ͸…ʁ ɾফ໣ܕΞΠςϜͷ৔߹ 
 ɹ=> ະॲཧͳܾࡁ৘ใ͕͋Ε͹ɺͦΕΛߪೖॲཧʹԊͬͯॲཧͯ͠঎඼Λ෇༩ 
 ɾඇফ໣ܕΞΠςϜɺࣗಈߋ৽αϒεΫϦϓγϣϯ 
 ɹඇࣗಈߋ৽αϒεΫϦϓγϣϯͷ৔߹ 


    ɹ=> ະॲཧͳܾࡁ৘ใ͕͋Ε͹ɺͦΕΛߪೖॲཧʹԊͬͯॲཧͯ͠঎඼Λ෇༩ 
 ɹ=> ॲཧࡁΈͰ͋Ε͹ 
 ɹɹϩάΠϯ͍ͯ͠ΔϢʔβΛݩʑར༻͍ͯͨ͠Ϣʔβʹ੾Γସ͑Δ 
 ɹɹ·ͨ͸ ݩʑར༻͍ͯͨ͠Ϣʔβʹ౷߹ͭͭ͠ϩάΠϯϢʔβΛ੾Γସ͑Δ 
 ɹɹ·ͨ͸ ߪೖ৘ใʹ߹ΘͤͯݱࡏͷϢʔβʹ঎඼Λ෇͚ସ͑Δ 
 ɹɹͳͲɺཁ݅ʹ͋Θͤͯ…
  31. 復元処理フロー 復元操作をする 
 or ⾃動で復元 レシート送信 
 + 
 購⼊情報を

    
 復元する為の 
 あれこれ 
 決済情報を 
 復元する レシート検証 
 最新レシート 
 取得 購⼊情報を 
 復元する為の 
 あれこれ
  32. 復元処理フロー 復元操作をする 
 or ⾃動で復元 レシート送信 
 + 
 購⼊情報を

    
 復元する為の 
 あれこれ 
 決済情報を 
 復元する レシート検証 
 最新レシート 
 取得 購⼊情報を 
 復元する為の 
 あれこれ
  33. 復元処理フロー/決済情報の復元 .. 旧StoreKitの場合 SKPaymentQueue.default().restoreCompletedTransactions() ↓ SKPaymentTransactionObserverの以下のdelegateが呼ばれる func paymentQueue( 
 _

    queue: SKPaymentQueue, 
 updatedTransactions transactions: [SKPaymentTransaction]) { // : } ↓SKPaymentTransaction.transactionState == .restored でやってくる ↓アプリとして必要な復元処理を実施 ↓復元処理を実施後SKPaymentQueue.default().finishTransaction(transaction) ↓ SKPaymentTransactionObserverの以下のdelegateが呼ばれる func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) { // : }
  34. 復元処理フロー/決済情報の復元 .. 旧StoreKitの場合 SKPaymentQueue.default().restoreCompletedTransactions() ↓ SKPaymentTransactionObserverの以下のdelegateが呼ばれる func paymentQueue( 
 _

    queue: SKPaymentQueue, 
 updatedTransactions transactions: [SKPaymentTransaction]) { // : } ↓SKPaymentTransaction.transactionState == .restored でやってくる ↓アプリとして必要な復元処理を実施 ↓復元処理を実施後SKPaymentQueue.default().finishTransaction(transaction) ↓ SKPaymentTransactionObserverの以下のdelegateが呼ばれる func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) { // : } ɹɾ·ͨupdatedTransactions… 
 ɹɹ=>ߪೖॲཧͱ෮ݩॲཧ͸ผ΋ͷͳͷͰ 
 ɹɹɹͪΌΜͱtransactionStateΛݟΔ 
 ɹɾະॲཧͳܾࡁͷ৔߹͸ߪೖॲཧͱಉ౳ͷॲཧΛ࣮ࢪ͢Δ 
 ɹɹඞཁ͕͋Δ ɹɾ΋ͪΖΜɺ঎඼λΠϓશͯͷTransaction͕΍ͬͯ͘Δ 
 ɹɾRxɺCombineɺ΢ο…
  35. 復元処理フロー/決済情報の復元 .. StoreKit2の場合 let transaction = await product.latestTransaction let result

    = await product.currentEntitlement let result = await Transaction.latest(for: "productId") let results = await Transaction.currentEntitlements // etc… 👏👏👏👏👏👏 👏👏👏👏👏👏 SKReceiptRefreshRequest૬౰ͷ΋ͷ͸ 
 await AppStore.sync()
  36. ΞδΣϯμ ɾΞϓϦ಺՝࣮ۚ૷ͷ֓ཁ 
 ɾStoreKitͱStoreKit2ͷҧ͍(ߪೖɾ෮ݩػೳΛ௥͍ͳ͕Β) 
 ɾStoreKit2Ͱ৽ͨʹͰ͖Δࣄ 
 ɾ·ͱΊ

  37. StoreKit2Ͱ৽ͨʹͰ͖Δࣄ ɾTransactionͷৄࡉ(unified_receipt૬౰)Λ 
 ɹ༰қʹࢀরͰ͖Δ 
 ɹچStoreKitͰ΋ग़དྷ͕ͨ… 
 ɹɹηΩϡΞͱ͸ݴ͍೉͍΍Γํͩͬͨ 
 ɹɹܕ҆શʹࢀর͢ΔҝʹखલͰؤுͬͯσίʔυ͢Δ

    
 ɹɹඞཁ͕͋ͬͨ
  38. StoreKit2Ͱ৽ͨʹͰ͖Δࣄ ɾฦۚϦΫΤετΛ࣮૷Ͱ͖Δ 
 ɹ 返⾦リクエストボタン を押す 返⾦リクエスト 返⾦リクエスト 通知 購⼊情報を

    
 提出 返⾦と判断されれば 
 返⾦
  39. ɾiOS15ະຬ 
 ɹ=>async/await backport ͕དྷͨΒมΘΔ͔΋… 
 ɾApple School Manager΍Apple Business

    Manager্Ͱ 
 ɹVolume Purchase ProgramΛར༻͍ͯ͠Δ৔߹ 
 ɾΞϓϦͷ༧໿ൢചػೳΛར༻͢Δ৔߹ 
 ɾաڈʹ༗ྉΞϓϦ͕ͩͬͨϑϦʔϛΞϜϞσϧʹ 
 ɹҠߦͨ͠ΞϓϦͷ৔߹ɺ·ͨ͸ͦͷٯͷ৔߹ 
 ɹ=>StoreKit2ʹ·ͩAPI (preorder_date) ͕ଘࡏ͠ͳ͍ StoreKit2͕࢖͑ͳ͍έʔε
  40. ΞδΣϯμ ɾΞϓϦ಺՝࣮ۚ૷ͷ֓ཁ 
 ɾStoreKitͱStoreKit2ͷҧ͍(ߪೖɾ෮ݩػೳΛ௥͍ͳ͕Β) 
 ɾStoreKit2Ͱ৽ͨʹͰ͖Δࣄ 
 ɾ·ͱΊ

  41. ·ͱΊ • ͨͩͰܾ͑͞ࡁॲཧ͸ෳࡶͳॴʹ 
 چStoreKitͷSKPaymentTransactionObserverΛத৺ͱͨ͠ઃܭ͕ 
 ͞Βʹෆඞཁͳෳࡶ͞ΛੜΜͰ͠·͍ͬͯͨ 
 - ߪೖɺ෮ݩॲཧ࣮૷ʹ͓͚ΔόοΫάϥ΢ϯυॲཧͷߟྀ

    
 - ঎඼ͷछผຖͷద੾ͳॲཧͷҧ͍ 
 - ߋʹ௥Ճػೳ(Promoting IAP, Subscription Offer, etc…)Λར༻͢Δ 
 શ෦ࡌͤͨঢ়ଶͷSKPaymentTransactionObserverΛ૝૾ͯ͠Έ·͠ΐ͏ 
 ɹͱͯ΋͔ΜͨΜͱ͸ݴ͍೉͍ɻਅ໘໨ʹ޲͖߹͏ͱઐ໳৬͕ඞཁͳϨϕϧ 
 ɹ3rd partyϥΠϒϥϦΛ࢖͍ͨ͘ͳΔؾ࣋ͪ΋෼͔Δ • StoreKit2Ͱ͸Observerύλʔϯ͸ഇࢭ͞Εɺasync/await͕෼͔Ε͹෼͔Δ͙Β͍ͷ 
 ۙ୅Խ͕͞Ε͍ͯΔ 
 ࣮ʹ…࣮ʹγϯϓϧͳAPIʹͳͬͨ 
 ։ൃ͢ΔΞϓϦʹඞཁͳܾࡁॲཧͷ࣮૷ʹूதͰ͖ΔΑ͏ʹͳͬͨɻૣ͘࢖͍͍ͨ…ɻ • App Store Server΋(·ͩ࢖͑ͳ͍ͷͰͲ͏ͳΔ͔෼͔Βͳ͍͚Ͳ)ૣ͘࢖͍͍ͨ…ɻ
  42. ࢀߟ ɾMeet StoreKit 2 @ WWDC21 
 ɹhttps://developer.apple.com/videos/play/wwdc2021/10114/ ɾManage in-app

    purchases on your server @ WWDC21 
 ɹhttps://developer.apple.com/videos/play/wwdc2021/10174/ ɾSupport customers and handle refunds @ WWDC21 
 ɹhttps://developer.apple.com/videos/play/wwdc2021/10175 ɾIn-App Purchase 
 ɹhttps://developer.apple.com/documentation/storekit/in-app_purchase ɾImplementing a Store In Your App Using the StoreKit API 
 ɹhttps://developer.apple.com/documentation/storekit/in-app_purchase/implementing_a_store_in_your_app_using_the_storekit_api ɾApp Store Server API 
 ɹhttps://developer.apple.com/documentation/appstoreserverapi