Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

ࣗݾ঺հ ɾ@uzzu 
 ɾCookpad Inc. ٕज़෦ Ϣʔβܾࡁج൫άϧʔϓ 
 ɾݞॻ͸AndroidΤϯδχΞɺ࠷ۙ͸Rails 
 ɾલ৬͸εϚʔτϑΥϯήʔϜ։ൃ 
 ɾझຯ͸VR

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

🎊StoreKit2🎊 WWDC21

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

࿩͞ͳ͍ࣄ ● Promoting IAPɺSubscription Offerɺ 
 Family Sharing SubscriptionͳͲͷOptionalͳܾࡁػೳ ● ΞϓϦ಺՝ۚҎ֎ͷStoreKitͷػೳ(SKOverlay౳) ● App Store Server APIͷৄࡉ ● async/awaitͷৄࡉ ● StoreKitͱStoreKit2͕ڞଘͨ͠৔߹ͷڍಈ

Slide 9

Slide 9 text

஫ҙࣄ߲ ⚠ ɾStoreKit2͸ݱࡏsandbox՝ۚ΋ࣦഊ͢Δ(iOS15 beta8) 
 ɹStoreKit TestingΛར༻͢ΔࣄͰಈ࡞͠·͢ 
 ɹhttps://developer.apple.com/forums/thread/681904 ɾStoreKit Testing ར༻ʹ͓͍ͯXcode 13 beta 5࣌఺Ͱ 
 ɹچStoreKitͱͷڠௐಈ࡞ͷ֬ೝ͕औΕͳ͍ 
 ɹ=> ڞଘͨ͠৔߹ͷಈ࡞͕Ͳ͏ͳΔͷ͔౳ࡉ͔͍ॴ͸ݱঢ়෼͔Βͳ͍ 
 ɾ࢖͑ΔΑ͏ʹͳΔͷ͸ iOS15 ʙ (async/await backport ૣ͘དྷͯ͘Εʙ) 
 ɾಈ͘Α͏ʹͳͬͨΒ࠶ݕূ͠·͠ΐ͏

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

ΞϓϦ಺՝ۚͷ࣮૷ͷ֓ཁ(1/2) ɾΞϓϦ಺Ͱσδλϧίϯςϯπͷൢച΍ఆظߪಡػೳΛ 
 ɹఏڙ͢Δࡍʹ͸ΞϓϦ಺՝ۚͷ࣮૷͕ඞཁ ɾΞϓϦ಺՝ۚͷ঎඼λΠϓ͸4छ 
 ɹফ໣ܕΞΠςϜ(Consumable) 
 ɹඇফ໣ܕΞΠςϜ(Non-Consumable) 
 ɹࣗಈߋ৽αϒεΫϦϓγϣϯ(Auto-Renewable Subscription) 
 ɹඇࣗಈߋ৽αϒεΫϦϓγϣϯ(Non-Renewing Subscription)

Slide 12

Slide 12 text

ΞϓϦ಺՝ۚͷ࣮૷ͷ֓ཁ(1/2) ɾͦΕͧΕఏڙ͢Δҝʹ࣮૷ඞਢͳػೳ 
 ɹߪೖ 
 ɹ෮ݩ 
 ɾͦͷଞɺඞਢͰ͸ͳ͍͕ඞཁʹԠ࣮ͯ͡૷ΛٻΊΒΕΔػೳ 
 ɹPromoting IAP .. App Store ΞϓϦ্Ͱͷ঎඼ͷϓϩϞʔγϣϯɺߪೖ 
 ɹSubscription Offer .. ೚ҙͷϢʔβʹ௿Ձ֨Ͱఏڙ͢Δ 
 ɹFamily Sharing Subscription .. ϑΝϛϦʔڞ༗ͷػೳͰఆظߪೖΛڞ༗͢Δ

Slide 13

Slide 13 text

ΞδΣϯμ ɾΞϓϦ಺՝࣮ۚ૷ͷ֓ཁ 
 ɾStoreKitͱStoreKit2ͷҧ͍(ߪೖɾ෮ݩػೳΛ௥͍ͳ͕Β) 
 ɾStoreKit2Ͱ৽ͨʹͰ͖Δࣄ 
 ɾؔ࿈ͯ͠AppStore Server API

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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) } }

Slide 16

Slide 16 text

ߪೖɾ෮ݩͷઆ໌ʹೖΔલʹ…ॳظԽʹ͍ͭͯ ॳظԽʹ·ͭΘΔτϥϒϧ 
 ɹɾΞϓϦىಈ࣌ͷॳظԽॲཧ(Ϣʔβೝূetc…)͕ 
 ɹɹऴΘͬͯͳ͍ঢ়ଶͰObserverॲཧͯ͠͠·͏ 
 ɹɾ௨஌͕͍ͭདྷͯ΋ྑ͍Α͏ͳ࣮૷ߟྀ͕͞Ε͍ͯͳ͍ 
 ɹɾSKPaymentQueue΁ͷremove/addΛ͓ͯ͠Βͣظ଴ͨ͠௨஌͕དྷͳ͍ 
 ɹɾ3rd party ϥΠϒϥϦ͕Observerొ࿥Λ͓ͯ͠Γ 
 ɹɹࣗΞϓϦͷObserverʹظ଴ͨ͠௨஌͕དྷͳ͍

Slide 17

Slide 17 text

ߪೖɾ෮ݩͷઆ໌ʹೖΔલʹ…ॳظԽʹ͍ͭͯ StoreKit 2͸ॳظԽ͸ෆཁ🎉🎉🎉

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

購⼊処理フロー/商品情報の取得 .. 旧StoreKitの場合 public typealias ProductsRequestResult = Result public typealias ProductsRequestCompletion = (ProductsRequestResult) -> Void public class ProductsRequest: NSObject, SKProductsRequestDelegate { private var completion: ProductsRequestCompletion? private var request: SKProductsRequest init(_ productIDs: Set) { 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)) } } }

Slide 21

Slide 21 text

購⼊処理フロー/商品情報の取得 .. 旧StoreKitの場合 public typealias ProductsRequestResult = Result public typealias ProductsRequestCompletion = (ProductsRequestResult) -> Void public class ProductsRequest: NSObject, SKProductsRequestDelegate { private var completion: ProductsRequestCompletion? private var request: SKProductsRequest init(_ productIDs: Set) { 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ͷ໋໊ΛϧʔϧԽ͢Δ౳ɺରࡦ͕ඞཁ ɹɾ঎඼৘ใऔಘ͢Δ͚ͩͳͷʹ 
 ɹɹίʔυྔ͕ଟ͍(هࡌͷίʔυͰ͸࣮ࡍ͸଍Γͳ͍)

Slide 22

Slide 22 text

購⼊処理フロー/商品情報の取得 .. StoreKit2の場合 let products = try await Product.products(for: ["productId"]) ΋ͪΖΜ঎඼λΠϓ΋औಘՄೳ (Product.type) 🥳🥳🥳🥳🥳🥳🥳🥳🥳 🥳🥳🥳🥳🥳🥳🥳🥳🥳

Slide 23

Slide 23 text

購⼊処理フロー/決済 .. 旧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)

Slide 24

Slide 24 text

↓商品付与後、 購⼊処理フロー/決済 .. 旧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)ͱܨ͗͜Ή 
 ɹɹͷ͸Ͱ͖ͳ͘͸ͳ͍͕େม

Slide 25

Slide 25 text

購⼊処理フロー/決済 .. StoreKit2の場合 let result = try await product.purchase() 🎉🎉🎉🎉🎉🎉🎉🎉🎉 🎉🎉🎉🎉🎉🎉🎉🎉🎉 Transaction#finish() ͸๨Εͣʹ

Slide 26

Slide 26 text

購⼊処理フロー/レシート検証、最新レシート取得 .. 旧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 ↓最新レシート情報を元に商品付与、注⽂を有効にする ↓後続処理へ…

Slide 27

Slide 27 text

購⼊処理フロー/レシート検証、最新レシート取得 .. 旧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 ͳΦϓγϣϯͰ 
 ɹɹɹߴ଎Խ͕ਤΕΔ͕ 
 ɹɹɹݹ͍ߪೖ৘ใ΋ඞཁͳϢʔεέʔε͸ 
 ɹɹɹ࣮ӡ༻্΅ͪ΅ͪ͋Δ

Slide 28

Slide 28 text

購⼊処理フロー/レシート検証、最新レシート取得 .. StoreKit2の場合 JWS化!レシート検証でサーバ間通信不要 
 巨⼤なレシート送らなくてもOK(代わりにJWS) 
 AppStore Server APIで個別にTransaction単位で問合せ可能に 🍻🍻🍻🍻🍻🍻🍻🍻🍻 🍻🍻🍻🍻🍻🍻🍻🍻🍻 JWSがどれくらいのサイズになるだろうか…🤔

Slide 29

Slide 29 text

෮ݩͱ͸…ʁ ɾIAPܾࡁ͸ߦΘΕ͍ͯΔ͕঎඼͕෇༩͞Ε͍ͯͳ͍ 
 ɹϢʔβ΁ͷٹࡁાஔ 
 ɹ- ߪೖΤϥʔ͕ൃੜͨ͠··ܾࡁը໘͔Β཭୤ͯ͠͠·ͬͨ 
 ɹ- ػछมߋޙʹݩʑར༻͍ͯͨ͠ঢ়ଶʹ໭͍ͨ͠ 
 ɹ- ߪೖࡁΈͷ঎඼Λෳ਺୺຤Ͱར༻͍ͨ͠ ɾܾࡁ৘ใΛ෮ݩ͢Δػೳ͕ఏڙ͞Ε͍ͯΔͷͰ 
 ɹͦΕΛར༻ͯ͠෮ݩॲཧΛߦ͏ 


Slide 30

Slide 30 text

෮ݩͱ͸…ʁ ɾফ໣ܕΞΠςϜͷ৔߹ 
 ɹ=> ະॲཧͳܾࡁ৘ใ͕͋Ε͹ɺͦΕΛߪೖॲཧʹԊͬͯॲཧͯ͠঎඼Λ෇༩ 
 ɾඇফ໣ܕΞΠςϜɺࣗಈߋ৽αϒεΫϦϓγϣϯ 
 ɹඇࣗಈߋ৽αϒεΫϦϓγϣϯͷ৔߹ 
 ɹ=> ະॲཧͳܾࡁ৘ใ͕͋Ε͹ɺͦΕΛߪೖॲཧʹԊͬͯॲཧͯ͠঎඼Λ෇༩ 
 ɹ=> ॲཧࡁΈͰ͋Ε͹ 
 ɹɹϩάΠϯ͍ͯ͠ΔϢʔβΛݩʑར༻͍ͯͨ͠Ϣʔβʹ੾Γସ͑Δ 
 ɹɹ·ͨ͸ ݩʑར༻͍ͯͨ͠Ϣʔβʹ౷߹ͭͭ͠ϩάΠϯϢʔβΛ੾Γସ͑Δ 
 ɹɹ·ͨ͸ ߪೖ৘ใʹ߹ΘͤͯݱࡏͷϢʔβʹ঎඼Λ෇͚ସ͑Δ 
 ɹɹͳͲɺཁ݅ʹ͋Θͤͯ…

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

復元処理フロー/決済情報の復元 .. 旧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) { // : }

Slide 34

Slide 34 text

復元処理フロー/決済情報の復元 .. 旧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ɺ΢ο…

Slide 35

Slide 35 text

復元処理フロー/決済情報の復元 .. 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()

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

StoreKit2Ͱ৽ͨʹͰ͖Δࣄ ɾฦۚϦΫΤετΛ࣮૷Ͱ͖Δ 
 ɹ 返⾦リクエストボタン を押す 返⾦リクエスト 返⾦リクエスト 通知 購⼊情報を 
 提出 返⾦と判断されれば 
 返⾦

Slide 39

Slide 39 text

ɾiOS15ະຬ 
 ɹ=>async/await backport ͕དྷͨΒมΘΔ͔΋… 
 ɾApple School Manager΍Apple Business Manager্Ͱ 
 ɹVolume Purchase ProgramΛར༻͍ͯ͠Δ৔߹ 
 ɾΞϓϦͷ༧໿ൢചػೳΛར༻͢Δ৔߹ 
 ɾաڈʹ༗ྉΞϓϦ͕ͩͬͨϑϦʔϛΞϜϞσϧʹ 
 ɹҠߦͨ͠ΞϓϦͷ৔߹ɺ·ͨ͸ͦͷٯͷ৔߹ 
 ɹ=>StoreKit2ʹ·ͩAPI (preorder_date) ͕ଘࡏ͠ͳ͍ StoreKit2͕࢖͑ͳ͍έʔε

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

·ͱΊ ● ͨͩͰܾ͑͞ࡁॲཧ͸ෳࡶͳॴʹ 
 چStoreKitͷSKPaymentTransactionObserverΛத৺ͱͨ͠ઃܭ͕ 
 ͞Βʹෆඞཁͳෳࡶ͞ΛੜΜͰ͠·͍ͬͯͨ 
 - ߪೖɺ෮ݩॲཧ࣮૷ʹ͓͚ΔόοΫάϥ΢ϯυॲཧͷߟྀ 
 - ঎඼ͷछผຖͷద੾ͳॲཧͷҧ͍ 
 - ߋʹ௥Ճػೳ(Promoting IAP, Subscription Offer, etc…)Λར༻͢Δ 
 શ෦ࡌͤͨঢ়ଶͷSKPaymentTransactionObserverΛ૝૾ͯ͠Έ·͠ΐ͏ 
 ɹͱͯ΋͔ΜͨΜͱ͸ݴ͍೉͍ɻਅ໘໨ʹ޲͖߹͏ͱઐ໳৬͕ඞཁͳϨϕϧ 
 ɹ3rd partyϥΠϒϥϦΛ࢖͍ͨ͘ͳΔؾ࣋ͪ΋෼͔Δ ● StoreKit2Ͱ͸Observerύλʔϯ͸ഇࢭ͞Εɺasync/await͕෼͔Ε͹෼͔Δ͙Β͍ͷ 
 ۙ୅Խ͕͞Ε͍ͯΔ 
 ࣮ʹ…࣮ʹγϯϓϧͳAPIʹͳͬͨ 
 ։ൃ͢ΔΞϓϦʹඞཁͳܾࡁॲཧͷ࣮૷ʹूதͰ͖ΔΑ͏ʹͳͬͨɻૣ͘࢖͍͍ͨ…ɻ ● App Store Server΋(·ͩ࢖͑ͳ͍ͷͰͲ͏ͳΔ͔෼͔Βͳ͍͚Ͳ)ૣ͘࢖͍͍ͨ…ɻ

Slide 42

Slide 42 text

ࢀߟ ɾ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