$30 off During Our Annual Pro Sale. View Details »

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

uzzu
September 17, 2021

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

uzzu

September 17, 2021
Tweet

More Decks by uzzu

Other Decks in Technology

Transcript

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

    View Slide

  2. ࣗݾ঺հ
    ɾ@uzzu

    ɾCookpad Inc. ٕज़෦ Ϣʔβܾࡁج൫άϧʔϓ

    ɾݞॻ͸AndroidΤϯδχΞɺ࠷ۙ͸Rails

    ɾલ৬͸εϚʔτϑΥϯήʔϜ։ൃ

    ɾझຯ͸VR

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  6. 🎊StoreKit2🎊
    WWDC21

    View Slide

  7. ΞδΣϯμ
    ɾΞϓϦ಺՝࣮ۚ૷ͷ֓ཁ

    ɾStoreKitͱStoreKit2ͷҧ͍(ߪೖɾ෮ݩػೳΛ௥͍ͳ͕Β)

    ɾStoreKit2Ͱ৽ͨʹͰ͖Δࣄ

    ɾ·ͱΊ

    View Slide

  8. ࿩͞ͳ͍ࣄ
    ● Promoting IAPɺSubscription Offerɺ

    Family Sharing SubscriptionͳͲͷOptionalͳܾࡁػೳ


    ● ΞϓϦ಺՝ۚҎ֎ͷStoreKitͷػೳ(SKOverlay౳)


    ● App Store Server APIͷৄࡉ


    ● async/awaitͷৄࡉ


    ● StoreKitͱStoreKit2͕ڞଘͨ͠৔߹ͷڍಈ

    View Slide

  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 ૣ͘དྷͯ͘Εʙ)

    ɾಈ͘Α͏ʹͳͬͨΒ࠶ݕূ͠·͠ΐ͏

    View Slide

  10. ΞδΣϯμ
    ɾΞϓϦ಺՝࣮ۚ૷ͷ֓ཁ

    ɾStoreKitͱStoreKit2ͷҧ͍(ߪೖɾ෮ݩػೳΛ௥͍ͳ͕Β)

    ɾStoreKit2Ͱ৽ͨʹͰ͖Δࣄ

    ɾ·ͱΊ

    View Slide

  11. ΞϓϦ಺՝ۚͷ࣮૷ͷ֓ཁ(1/2)
    ɾΞϓϦ಺Ͱσδλϧίϯςϯπͷൢച΍ఆظߪಡػೳΛ

    ɹఏڙ͢Δࡍʹ͸ΞϓϦ಺՝ۚͷ࣮૷͕ඞཁ


    ɾΞϓϦ಺՝ۚͷ঎඼λΠϓ͸4छ

    ɹফ໣ܕΞΠςϜ(Consumable)

    ɹඇফ໣ܕΞΠςϜ(Non-Consumable)

    ɹࣗಈߋ৽αϒεΫϦϓγϣϯ(Auto-Renewable Subscription)

    ɹඇࣗಈߋ৽αϒεΫϦϓγϣϯ(Non-Renewing Subscription)

    View Slide

  12. ΞϓϦ಺՝ۚͷ࣮૷ͷ֓ཁ(1/2)
    ɾͦΕͧΕఏڙ͢Δҝʹ࣮૷ඞਢͳػೳ

    ɹߪೖ

    ɹ෮ݩ

    ɾͦͷଞɺඞਢͰ͸ͳ͍͕ඞཁʹԠ࣮ͯ͡૷ΛٻΊΒΕΔػೳ

    ɹPromoting IAP .. App Store ΞϓϦ্Ͱͷ঎඼ͷϓϩϞʔγϣϯɺߪೖ

    ɹSubscription Offer .. ೚ҙͷϢʔβʹ௿Ձ֨Ͱఏڙ͢Δ

    ɹFamily Sharing Subscription .. ϑΝϛϦʔڞ༗ͷػೳͰఆظߪೖΛڞ༗͢Δ

    View Slide

  13. ΞδΣϯμ
    ɾΞϓϦ಺՝࣮ۚ૷ͷ֓ཁ

    ɾStoreKitͱStoreKit2ͷҧ͍(ߪೖɾ෮ݩػೳΛ௥͍ͳ͕Β)

    ɾStoreKit2Ͱ৽ͨʹͰ͖Δࣄ

    ɾؔ࿈ͯ͠AppStore Server API

    View Slide

  14. ߪೖɾ෮ݩͷઆ໌ʹೖΔલʹ…ॳظԽʹ͍ͭͯ
    ɾچStoreKit͸ΞϓϦ಺՝ۚͷ࣮૷ʹඞཁͳ

    ɹ֤छ௨஌Λड͚औΔҝͷObserverͷ࣮૷ͱొ࿥ॲཧ

    ɹ͕ඞཁɻຊεϥΠυͰ͸͜ΕΛศ্ٓॳظԽͱݺͿ


    ɾొ࿥ॲཧ .. SKPaymentTransactionObserverΛ࣮૷ͨ͠

    ɹΫϥεͷΠϯελϯεΛSKPaymentQueueʹొ࿥

    View Slide

  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)


    }


    }

    View Slide

  16. ߪೖɾ෮ݩͷઆ໌ʹೖΔલʹ…ॳظԽʹ͍ͭͯ
    ॳظԽʹ·ͭΘΔτϥϒϧ

    ɹɾΞϓϦىಈ࣌ͷॳظԽॲཧ(Ϣʔβೝূetc…)͕

    ɹɹऴΘͬͯͳ͍ঢ়ଶͰObserverॲཧͯ͠͠·͏

    ɹɾ௨஌͕͍ͭདྷͯ΋ྑ͍Α͏ͳ࣮૷ߟྀ͕͞Ε͍ͯͳ͍

    ɹɾSKPaymentQueue΁ͷremove/addΛ͓ͯ͠Βͣظ଴ͨ͠௨஌͕དྷͳ͍

    ɹɾ3rd party ϥΠϒϥϦ͕Observerొ࿥Λ͓ͯ͠Γ

    ɹɹࣗΞϓϦͷObserverʹظ଴ͨ͠௨஌͕དྷͳ͍

    View Slide

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

    View Slide

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

    +

    注⽂を有効にして

    購⼊した商品を

    付与する
    レシート検証

    最新レシート

    取得
    購⼊情報を

    更新

    View Slide

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

    +

    注⽂を有効にして

    購⼊した商品を

    付与する
    レシート検証

    最新レシート

    取得
    購⼊情報を

    更新

    View Slide

  20. 購⼊処理フロー/商品情報の取得 .. 旧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))


    }


    }


    }

    View Slide

  21. 購⼊処理フロー/商品情報の取得 .. 旧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ͷ໋໊ΛϧʔϧԽ͢Δ౳ɺରࡦ͕ඞཁ


    ɹɾ঎඼৘ใऔಘ͢Δ͚ͩͳͷʹ

    ɹɹίʔυྔ͕ଟ͍(هࡌͷίʔυͰ͸࣮ࡍ͸଍Γͳ͍)


    View Slide

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

    View Slide

  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)

    View Slide

  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)ͱܨ͗͜Ή

    ɹɹͷ͸Ͱ͖ͳ͘͸ͳ͍͕େม

    View Slide

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

    View Slide

  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
    ↓最新レシート情報を元に商品付与、注⽂を有効にする
    ↓後続処理へ…

    View Slide

  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 ͳΦϓγϣϯͰ

    ɹɹɹߴ଎Խ͕ਤΕΔ͕

    ɹɹɹݹ͍ߪೖ৘ใ΋ඞཁͳϢʔεέʔε͸

    ɹɹɹ࣮ӡ༻্΅ͪ΅ͪ͋Δ


    View Slide

  28. 購⼊処理フロー/レシート検証、最新レシート取得 .. StoreKit2の場合
    JWS化!レシート検証でサーバ間通信不要

    巨⼤なレシート送らなくてもOK(代わりにJWS)

    AppStore Server APIで個別にTransaction単位で問合せ可能に
    🍻🍻🍻🍻🍻🍻🍻🍻🍻
    🍻🍻🍻🍻🍻🍻🍻🍻🍻
    JWSがどれくらいのサイズになるだろうか…🤔

    View Slide

  29. ෮ݩͱ͸…ʁ
    ɾIAPܾࡁ͸ߦΘΕ͍ͯΔ͕঎඼͕෇༩͞Ε͍ͯͳ͍

    ɹϢʔβ΁ͷٹࡁાஔ

    ɹ- ߪೖΤϥʔ͕ൃੜͨ͠··ܾࡁը໘͔Β཭୤ͯ͠͠·ͬͨ

    ɹ- ػछมߋޙʹݩʑར༻͍ͯͨ͠ঢ়ଶʹ໭͍ͨ͠

    ɹ- ߪೖࡁΈͷ঎඼Λෳ਺୺຤Ͱར༻͍ͨ͠


    ɾܾࡁ৘ใΛ෮ݩ͢Δػೳ͕ఏڙ͞Ε͍ͯΔͷͰ

    ɹͦΕΛར༻ͯ͠෮ݩॲཧΛߦ͏

    View Slide

  30. ෮ݩͱ͸…ʁ
    ɾফ໣ܕΞΠςϜͷ৔߹

    ɹ=> ະॲཧͳܾࡁ৘ใ͕͋Ε͹ɺͦΕΛߪೖॲཧʹԊͬͯॲཧͯ͠঎඼Λ෇༩

    ɾඇফ໣ܕΞΠςϜɺࣗಈߋ৽αϒεΫϦϓγϣϯ

    ɹඇࣗಈߋ৽αϒεΫϦϓγϣϯͷ৔߹

    ɹ=> ະॲཧͳܾࡁ৘ใ͕͋Ε͹ɺͦΕΛߪೖॲཧʹԊͬͯॲཧͯ͠঎඼Λ෇༩

    ɹ=> ॲཧࡁΈͰ͋Ε͹

    ɹɹϩάΠϯ͍ͯ͠ΔϢʔβΛݩʑར༻͍ͯͨ͠Ϣʔβʹ੾Γସ͑Δ

    ɹɹ·ͨ͸ ݩʑར༻͍ͯͨ͠Ϣʔβʹ౷߹ͭͭ͠ϩάΠϯϢʔβΛ੾Γସ͑Δ

    ɹɹ·ͨ͸ ߪೖ৘ใʹ߹ΘͤͯݱࡏͷϢʔβʹ঎඼Λ෇͚ସ͑Δ

    ɹɹͳͲɺཁ݅ʹ͋Θͤͯ…

    View Slide

  31. 復元処理フロー
    復元操作をする

    or ⾃動で復元
    レシート送信

    +

    購⼊情報を

    復元する為の

    あれこれ

    決済情報を

    復元する
    レシート検証

    最新レシート

    取得
    購⼊情報を

    復元する為の

    あれこれ

    View Slide

  32. 復元処理フロー
    復元操作をする

    or ⾃動で復元
    レシート送信

    +

    購⼊情報を

    復元する為の

    あれこれ

    決済情報を

    復元する
    レシート検証

    最新レシート

    取得
    購⼊情報を

    復元する為の

    あれこれ

    View Slide

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


    // :


    }

    View Slide

  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ɺ΢ο…

    View Slide

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

    View Slide

  36. ΞδΣϯμ
    ɾΞϓϦ಺՝࣮ۚ૷ͷ֓ཁ

    ɾStoreKitͱStoreKit2ͷҧ͍(ߪೖɾ෮ݩػೳΛ௥͍ͳ͕Β)

    ɾStoreKit2Ͱ৽ͨʹͰ͖Δࣄ

    ɾ·ͱΊ

    View Slide

  37. StoreKit2Ͱ৽ͨʹͰ͖Δࣄ
    ɾTransactionͷৄࡉ(unified_receipt૬౰)Λ

    ɹ༰қʹࢀরͰ͖Δ

    ɹچStoreKitͰ΋ग़དྷ͕ͨ…

    ɹɹηΩϡΞͱ͸ݴ͍೉͍΍Γํͩͬͨ

    ɹɹܕ҆શʹࢀর͢ΔҝʹखલͰؤுͬͯσίʔυ͢Δ

    ɹɹඞཁ͕͋ͬͨ

    View Slide

  38. StoreKit2Ͱ৽ͨʹͰ͖Δࣄ
    ɾฦۚϦΫΤετΛ࣮૷Ͱ͖Δ

    ɹ
    返⾦リクエストボタン
    を押す
    返⾦リクエスト
    返⾦リクエスト
    通知
    購⼊情報を

    提出
    返⾦と判断されれば

    返⾦

    View Slide

  39. ɾiOS15ະຬ

    ɹ=>async/await backport ͕དྷͨΒมΘΔ͔΋…

    ɾApple School Manager΍Apple Business Manager্Ͱ

    ɹVolume Purchase ProgramΛར༻͍ͯ͠Δ৔߹

    ɾΞϓϦͷ༧໿ൢചػೳΛར༻͢Δ৔߹

    ɾաڈʹ༗ྉΞϓϦ͕ͩͬͨϑϦʔϛΞϜϞσϧʹ

    ɹҠߦͨ͠ΞϓϦͷ৔߹ɺ·ͨ͸ͦͷٯͷ৔߹

    ɹ=>StoreKit2ʹ·ͩAPI (preorder_date) ͕ଘࡏ͠ͳ͍
    StoreKit2͕࢖͑ͳ͍έʔε

    View Slide

  40. ΞδΣϯμ
    ɾΞϓϦ಺՝࣮ۚ૷ͷ֓ཁ

    ɾStoreKitͱStoreKit2ͷҧ͍(ߪೖɾ෮ݩػೳΛ௥͍ͳ͕Β)

    ɾStoreKit2Ͱ৽ͨʹͰ͖Δࣄ

    ɾ·ͱΊ

    View Slide

  41. ·ͱΊ
    ● ͨͩͰܾ͑͞ࡁॲཧ͸ෳࡶͳॴʹ

    چStoreKitͷSKPaymentTransactionObserverΛத৺ͱͨ͠ઃܭ͕

    ͞Βʹෆඞཁͳෳࡶ͞ΛੜΜͰ͠·͍ͬͯͨ

    - ߪೖɺ෮ݩॲཧ࣮૷ʹ͓͚ΔόοΫάϥ΢ϯυॲཧͷߟྀ

    - ঎඼ͷछผຖͷద੾ͳॲཧͷҧ͍

    - ߋʹ௥Ճػೳ(Promoting IAP, Subscription Offer, etc…)Λར༻͢Δ

    શ෦ࡌͤͨঢ়ଶͷSKPaymentTransactionObserverΛ૝૾ͯ͠Έ·͠ΐ͏

    ɹͱͯ΋͔ΜͨΜͱ͸ݴ͍೉͍ɻਅ໘໨ʹ޲͖߹͏ͱઐ໳৬͕ඞཁͳϨϕϧ

    ɹ3rd partyϥΠϒϥϦΛ࢖͍ͨ͘ͳΔؾ࣋ͪ΋෼͔Δ


    ● StoreKit2Ͱ͸Observerύλʔϯ͸ഇࢭ͞Εɺasync/await͕෼͔Ε͹෼͔Δ͙Β͍ͷ

    ۙ୅Խ͕͞Ε͍ͯΔ

    ࣮ʹ…࣮ʹγϯϓϧͳAPIʹͳͬͨ

    ։ൃ͢ΔΞϓϦʹඞཁͳܾࡁॲཧͷ࣮૷ʹूதͰ͖ΔΑ͏ʹͳͬͨɻૣ͘࢖͍͍ͨ…ɻ


    ● App Store Server΋(·ͩ࢖͑ͳ͍ͷͰͲ͏ͳΔ͔෼͔Βͳ͍͚Ͳ)ૣ͘࢖͍͍ͨ…ɻ

    View Slide

  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

    View Slide