詳解 Auto-Renewable Subscription / Detailed Auto-Renewable Subscription

070d33664df274636dad3da21c9b21fc?s=47 rockname
September 06, 2019

詳解 Auto-Renewable Subscription / Detailed Auto-Renewable Subscription

070d33664df274636dad3da21c9b21fc?s=128

rockname

September 06, 2019
Tweet

Transcript

  1. ৄղ Auto-Renewable Subscription iOSDC Japan 2019 2019/09/06 גࣜձࣾϛΫγΟ ΈͯͶࣄۀ෦ ϩΫωϜ

    @rockname
  2. ࣗݾ঺հ • גࣜձࣾϛΫγΟ • Ո଒ΞϧόϜΈͯͶ / ΞϓϦ։ൃάϧʔϓ
 iOS(Swift, obj-c) >

    Android(Kotlin, Java) == Rails(ruby) • VTuber͕޷͖ • WWDC 2019 ࢀՃ͠·ͨ͠ ✈ ϩΫωϜ@rockname
  3. ࠓ೔࿩͢͜ͱ 1. Auto-Renewable Subscriptionsͱ͸ʁ 2. ΈͯͶʹ͓͚ΔಋೖͷܦҢ 3. جຊతͳ࣮૷ํ๏ 4. αʔόʔؒ௨஌ʹ͍ͭͯ

    5. Status Pollingʹ͍ͭͯ 6. Sandbox؀ڥʹ͓͚Δಈ࡞֬ೝ 7. ϦδΣΫτʹ͍ͭͯؾΛ͚͍ͭͨϙΠϯτ 8. ·ͱΊ
  4. ࠓ೔࿩͞ͳ͍͜ͱ • Subscription Offers • Promoted In-App Purchases • Sales

    and TrendsͷϝτϦΫεͷݟํ
  5. Auto-Renewable Subscriptionsͱ͸ʁ 1.

  6. Auto-Renewable Subscription • ఆظతʹߋ৽͞ΕΔίϯςϯπʹରͯ͠ఆظ ՝ۚ͢ΔɺIn-App Purchasesʹ͓͚ΔҰͭͷ ՝ۚํ๏

  7. Auto-Renewable Subscription • ఆظతʹߋ৽͞ΕΔίϯςϯπʹରͯ͠ఆظ ՝ۚ͢ΔɺIn-App Purchasesʹ͓͚ΔҰͭͷ ՝ۚํ๏ αϒεΫϦϓγϣϯ ߪೖ Time

  8. Auto-Renewable Subscription • ఆظతʹߋ৽͞ΕΔίϯςϯπʹରͯ͠ఆظ ՝ۚ͢ΔɺIn-App Purchasesʹ͓͚ΔҰͭͷ ՝ۚํ๏ αϒεΫϦϓγϣϯ αϒεΫϦϓγϣϯ ߪೖ

    ߋ৽ Time
  9. Auto-Renewable Subscription • ఆظతʹߋ৽͞ΕΔίϯςϯπʹରͯ͠ఆظ ՝ۚ͢ΔɺIn-App Purchasesʹ͓͚ΔҰͭͷ ՝ۚํ๏ αϒεΫϦϓγϣϯ αϒεΫϦϓγϣϯ αϒεΫϦϓγϣϯ

    ߪೖ ߋ৽ ߋ৽ Time
  10. ΈͯͶʹ͓͚ΔಋೖͷܦҢ 2.

  11. ͦ΋ͦ΋ʮΈͯͶʯͬͯԿʁ • εϚϗͰࡱͬͨࢠͲ΋ͷࣸਅ΍ಈըΛ؆୯ʹڞ༗ɺ੔ཧͰ͖ΔΞϓϦ • ڞ༗͞ΕͨϝσΟΞΛݟͯՈ଒Ͱָ͘͠ձ࿩ͨ͠ΓɺࢠͲ΋ͷ੒௕Λৼ ΓฦΔ͜ͱ͕Ͱ͖Δ

  12. ΈͯͶϓϨϛΞϜɺ࢝ಈ • Ո଒ͷ͏ͪ1ਓͰ΋՝ۚͨ͠Βར༻Ͱ͖Δఆظߪಡ ܕͷϓϨϛΞϜϓϥϯΛ 2019/04/09 ʹϦϦʔε

  13. None
  14. None
  15. None
  16. 8/15ʹϦϦʔε

  17. جຊతͳ࣮૷ํ๏ 3.

  18. લ४උ • App಺՝ۚΛ࡞੒ • Reference Name / Product ID •

    Price / Duration • Subscription Display Name • Subscription GroupΛ࡞੒ • Reference Name • Subscription Group Display Name ʮ"QQ4UPSF$POOFDUϔϧϓʯΑΓ IUUQTIFMQBQQMFDPNBQQTUPSFDPOOFDUEFWGDF App Store Connect্ͰϓϩμΫτΛ࡞੒
  19. ߪಡ։࢝·Ͱͷγʔέϯε

  20. None
  21. None
  22. None
  23. None
  24. None
  25. None
  26. None
  27. None
  28. None
  29. ֤εςοϓͷ࣮૷ํ๏ʹ͍ͭͯ

  30. None
  31. Transaction ObserverͷηοτΞοϓ • transactionΛॲཧ͢ΔͨΊʹ͸·ͣObserverΛੜ ੒ͯ͠payment queueʹ௥Ճ͢Δඞཁ͕͋Δ • payment queue͔ΒͷΠϕϯτΛऔΓ͜΅͞ͳ͍ ͨΊʹ΋Observer͸ΞϓϦىಈ௚ޙʹ௥Ճ͢Δ

    IUUQTEFWFMPQFSBQQMFDPNEPDVNFOUBUJPOTUPSFLJUJO BQQ@QVSDIBTF TFUUJOH@VQ@UIF@USBOTBDUJPO@PCTFSWFS@BOE@QBZNFOU@RVFVF
  32. class PaymentTransactionObserver: NSObject, SKPaymentTransactionObserver { static let shared = PaymentTransactionObserver()

    private let queue = SKPaymentQueue.default() private override init() { super.init() NotificationCenter.default.addObserver( self, selector: #selector(self.didFinishLaunchingNotification), name: UIApplication.didFinishLaunchingNotification, object: nil ) NotificationCenter.default.addObserver( self, selector: #selector(self.willTerminate), name: UIApplication.willTerminateNotification, object: nil ) } deinit { NotificationCenter.default.removeObserver(self) } @objc private func didFinishLaunchingNotification() { queue.add(self) } @objc private func willTerminate() { queue.remove(self) } func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { // Handle transaction states here. } }
  33. class PaymentTransactionObserver: NSObject, SKPaymentTransactionObserver { static let shared = PaymentTransactionObserver()

    private let queue = SKPaymentQueue.default() private override init() { super.init() NotificationCenter.default.addObserver( self, selector: #selector(self.didFinishLaunchingNotification), name: UIApplication.didFinishLaunchingNotification, object: nil ) NotificationCenter.default.addObserver( self, selector: #selector(self.willTerminate), name: UIApplication.willTerminateNotification, object: nil ) } deinit { NotificationCenter.default.removeObserver(self) } @objc private func didFinishLaunchingNotification() { queue.add(self) } @objc private func willTerminate() { queue.remove(self) } func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { // Handle transaction states here. } } Observer͸γϯάϧτϯͰ࡞Δ
  34. class PaymentTransactionObserver: NSObject, SKPaymentTransactionObserver { static let shared = PaymentTransactionObserver()

    private let queue = SKPaymentQueue.default() private override init() { super.init() NotificationCenter.default.addObserver( self, selector: #selector(self.didFinishLaunchingNotification), name: UIApplication.didFinishLaunchingNotification, object: nil ) NotificationCenter.default.addObserver( self, selector: #selector(self.willTerminate), name: UIApplication.willTerminateNotification, object: nil ) } deinit { NotificationCenter.default.removeObserver(self) } @objc private func didFinishLaunchingNotification() { queue.add(self) } @objc private func willTerminate() { queue.remove(self) } func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { // Handle transaction states here. } } ΞϓϦىಈ࣌ʹpayment queueʹ௥Ճ
  35. class PaymentTransactionObserver: NSObject, SKPaymentTransactionObserver { static let shared = PaymentTransactionObserver()

    private let queue = SKPaymentQueue.default() private override init() { super.init() NotificationCenter.default.addObserver( self, selector: #selector(self.didFinishLaunchingNotification), name: UIApplication.didFinishLaunchingNotification, object: nil ) NotificationCenter.default.addObserver( self, selector: #selector(self.willTerminate), name: UIApplication.willTerminateNotification, object: nil ) } deinit { NotificationCenter.default.removeObserver(self) } @objc private func didFinishLaunchingNotification() { queue.add(self) } @objc private func willTerminate() { queue.remove(self) } func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { // Handle transaction states here. } } ΞϓϦऴྃ࣌ʹpayment queue͔Β࡟আ
  36. None
  37. App Store͔ΒProduct InformationΛऔಘ • SKPaymentQueue.canMakePayments() ͰϢʔβʔ͕ߪೖͰ͖Δ ͔֬ೝ • App Store

    ConnectͰొ࿥ͨ͠product identifierΛ࢖༻ͯ͠App Store͔ΒϓϩμΫτ৘ใΛऔಘ͢Δ • product identifierͷ؅ཧʹ͸2ύλʔϯ͋Δ 1. BundleʹؚΊΔ 2. αʔόʔͰ؅ཧ͢Δ
  38. App Store͔ΒProduct InformationΛऔಘ • SKPaymentQueue.canMakePayments() ͰϢʔβʔ͕ߪೖͰ͖Δ ͔֬ೝ • App Store

    ConnectͰొ࿥ͨ͠product identifierΛ࢖༻ͯ͠App Store͔ΒϓϩμΫτ৘ใΛऔಘ͢Δ • product identifierͷ؅ཧʹ͸2ύλʔϯ͋Δ 1. BundleʹؚΊΔ 2. αʔόʔͰ؅ཧ͢Δ ΈͯͶͰ͸ ʮ2. αʔόʔͰ؅ཧ͢ΔʯͰ࣮૷
  39. // Keep a strong reference to the product request. var

    request: SKProductsRequest! func requestProductInformation(with productIdentifiers: [String]) { let productIdentifiers = Set(productIdentifiers) request = SKProductsRequest(productIdentifiers: productIdentifiers) request.delegate = self request.start() }
  40. // Keep a strong reference to the product request. var

    request: SKProductsRequest! func requestProductInformation(with productIdentifiers: [String]) { let productIdentifiers = Set(productIdentifiers) request = SKProductsRequest(productIdentifiers: productIdentifiers) request.delegate = self request.start() } ϦΫΤετ͸ڧࢀরͰอ࣋͢Δඞཁ͕͋Δ
  41. // Keep a strong reference to the product request. var

    request: SKProductsRequest! func requestProductInformation(with productIdentifiers: [String]) { let productIdentifiers = Set(productIdentifiers) request = SKProductsRequest(productIdentifiers: productIdentifiers) request.delegate = self request.start() } delegateΛηοτͯ͠ϦΫΤετΛ։࢝
  42. // SKProductsRequestDelegate protocol method. func productsRequest(_ request: SKProductsRequest, didReceive response:

    SKProductsResponse) { if !response.products.isEmpty { let products = response.products // Custom method. displayStore(products) } for invalidIdentifier in response.invalidProductIdentifiers { // Handle any invalid product identifiers as appropriate. } }
  43. // SKProductsRequestDelegate protocol method. func productsRequest(_ request: SKProductsRequest, didReceive response:

    SKProductsResponse) { if !response.products.isEmpty { let products = response.products // Custom method. displayStore(products) } for invalidIdentifier in response.invalidProductIdentifiers { // Handle any invalid product identifiers as appropriate. } } delegateϝιουͰϓϩμΫτͷ഑ྻ Λड͚औͬͯUIʹදࣔ
  44. // SKProductsRequestDelegate protocol method. func productsRequest(_ request: SKProductsRequest, didReceive response:

    SKProductsResponse) { if !response.products.isEmpty { let products = response.products // Custom method. displayStore(products) } for invalidIdentifier in response.invalidProductIdentifiers { // Handle any invalid product identifiers as appropriate. } } ΈͯͶͰ͸invalidIdentifierΛ೦ͷҝ Crashlyticsʹඈ͹͍ͯ͠Δ
  45. None
  46. UIʹϓϩμΫτ৘ใΛදࣔ • Human Interface GuidelineΛ ख़ಡͯ͠ద੾ͳ৘ใΛදࣔ͢Δ • ৘ใ͕࿙Ε͍ͯͨΒଈϦδΣΫ τͳͷͰཁ஫ҙ (ৄ͘͠͸ޙ΄

    Ͳ࿩͠·͢) IUUQTEFWFMPQFSBQQMFDPNEFTJHOIVNBOJOUFSGBDFHVJEFMJOFT TVCTDSJQUJPOTPWFSWJFX
  47. None
  48. App Store΁ߪೖΛϦΫΤετ • Ϣʔβʔͷબ୒ͨ͠ϓϩμΫτ͔Βࢧ෷͍Ϧ ΫΤετΛ࡞੒ • ࢧ෷͍ϦΫΤετΛpayment queueʹ௥Ճ

  49. App Store΁ߪೖΛϦΫΤετ • Ϣʔβʔͷબ୒ͨ͠ϓϩμΫτ͔Βࢧ෷͍Ϧ ΫΤετΛ࡞੒ • ࢧ෷͍ϦΫΤετΛpayment queueʹ௥Ճ let payment

    = SKPayment(product: selectedProduct) SKPaymentQueue.default().add(payment)
  50. None
  51. TransactionΛॲཧ͢Δ • SKPaymentTransactionObserver#paymentQueue(_:updatedTransactio ns:) ʹtransaction͕ྲྀΕͯ͘Δ • transactionͷ SKPaymentTransactionState ʹԠͯ͡ద੾ʹॲཧ •

    transaction͸ finishTransaction() ͠ͳ͍͔͗Γqueueʹ࢒Γଓ͚Δ • ߪೖ్தʹΞϓϦΛऴྃͤͯ͞͠·ͬͨϢʔβʔ͸࣍ճىಈ࣌ʹ෮ ؼͰ͖Δ • updatedTransactions Λ͍ͭͰ΋ॲཧͯ݁͠ՌΛϢʔβʔʹ൓өͤ͞ Δ͜ͱ͕Ͱ͖Δঢ়ଶΛߏங͢Δඞཁ͕͋Δ
  52. 4,1BZNFOU
 5SBOTBDUJPO4UBUF QVSDIBTJOH EFGFSSFE GBJMFE QVSDIBTFE SFTUPSFE ঢ়ଶ ߪೖத ʮ"TLUP#VZʯʹΑ

    ͬͯࢠڙ͕ߪೖΛ੍ ݶ͞Ε͍ͯΔঢ়ଶ ߪೖʹࣦഊ ߪೖʹ੒ޭ લճͷߪೖͷ෮ݩʹ ੒ޭ 6*΁ͷ൓ө ߪೖதͷϓϩάϨε Λදࣔ͢Δ 6*ʹ΋൓ө FSSPSʹΑͬͯϝοη ʔδΛදࣔ ϨγʔτͷWBMJEBUJPO ݁ՌΛදࣔ ϨγʔτͷWBMJEBUJPO ݁ՌΛදࣔ USBOTBDUJPOͷॲཧ   pOJTI5SBOTBDUJPO WBMJEBUJPOͷ੒ޭ͋Δ ͍͸Ϩγʔτ͕ظݶ ੾Εͷ৔߹͸ pOTI5SBOTBDUJPO WBMJEBUJPOͷ੒ޭ͋Δ ͍͸Ϩγʔτ͕ظݶ ੾Εͷ৔߹͸ pOTI5SBOTBDUJPO
  53. 4,1BZNFOU
 5SBOTBDUJPO4UBUF QVSDIBTJOH EFGFSSFE GBJMFE QVSDIBTFE SFTUPSFE ঢ়ଶ ߪೖத ʮ"TLUP#VZʯʹΑ

    ͬͯࢠڙ͕ߪೖΛ੍ ݶ͞Ε͍ͯΔঢ়ଶ ߪೖʹࣦഊ ߪೖʹ੒ޭ લճͷߪೖͷ෮ݩʹ ੒ޭ 6*΁ͷ൓ө ߪೖதͷϓϩάϨε Λදࣔ͢Δ 6*ʹ΋൓ө FSSPSʹΑͬͯϝοη ʔδΛදࣔ ϨγʔτͷWBMJEBUJPO ݁ՌΛදࣔ ϨγʔτͷWBMJEBUJPO ݁ՌΛදࣔ USBOTBDUJPOͷॲཧ   pOJTI5SBOTBDUJPO WBMJEBUJPOͷ੒ޭ͋Δ ͍͸Ϩγʔτ͕ظݶ ੾Εͷ৔߹͸ pOTI5SBOTBDUJPO WBMJEBUJPOͷ੒ޭ͋Δ ͍͸Ϩγʔτ͕ظݶ ੾Εͷ৔߹͸ pOTI5SBOTBDUJPO
  54. 4,1BZNFOU
 5SBOTBDUJPO4UBUF QVSDIBTJOH EFGFSSFE GBJMFE QVSDIBTFE SFTUPSFE ঢ়ଶ ߪೖத ʮ"TLUP#VZʯʹΑ

    ͬͯࢠڙ͕ߪೖΛ੍ ݶ͞Ε͍ͯΔঢ়ଶ ߪೖʹࣦഊ ߪೖʹ੒ޭ લճͷߪೖͷ෮ݩʹ ੒ޭ 6*΁ͷ൓ө ߪೖதͷϓϩάϨε Λදࣔ͢Δ 6*ʹ΋൓ө FSSPSʹΑͬͯϝοη ʔδΛදࣔ ϨγʔτͷWBMJEBUJPO ݁ՌΛදࣔ ϨγʔτͷWBMJEBUJPO ݁ՌΛදࣔ USBOTBDUJPOͷॲཧ   pOJTI5SBOTBDUJPO WBMJEBUJPOͷ੒ޭ͋Δ ͍͸Ϩγʔτ͕ظݶ ੾Εͷ৔߹͸ pOTI5SBOTBDUJPO WBMJEBUJPOͷ੒ޭ͋Δ ͍͸Ϩγʔτ͕ظݶ ੾Εͷ৔߹͸ pOTI5SBOTBDUJPO
  55. 4,1BZNFOU
 5SBOTBDUJPO4UBUF QVSDIBTJOH EFGFSSFE GBJMFE QVSDIBTFE SFTUPSFE ঢ়ଶ ߪೖத ʮ"TLUP#VZʯʹΑ

    ͬͯࢠڙ͕ߪೖΛ੍ ݶ͞Ε͍ͯΔঢ়ଶ ߪೖʹࣦഊ ߪೖʹ੒ޭ લճͷߪೖͷ෮ݩʹ ੒ޭ 6*΁ͷ൓ө ߪೖதͷϓϩάϨε Λදࣔ͢Δ 6*ʹ΋൓ө FSSPSʹΑͬͯϝοη ʔδΛදࣔ ϨγʔτͷWBMJEBUJPO ݁ՌΛදࣔ ϨγʔτͷWBMJEBUJPO ݁ՌΛදࣔ USBOTBDUJPOͷॲཧ   pOJTI5SBOTBDUJPO WBMJEBUJPOͷ੒ޭ͋Δ ͍͸Ϩγʔτ͕ظݶ ੾Εͷ৔߹͸ pOTI5SBOTBDUJPO WBMJEBUJPOͷ੒ޭ͋Δ ͍͸Ϩγʔτ͕ظݶ ੾Εͷ৔߹͸ pOTI5SBOTBDUJPO
  56. 4,1BZNFOU
 5SBOTBDUJPO4UBUF QVSDIBTJOH EFGFSSFE GBJMFE QVSDIBTFE SFTUPSFE ঢ়ଶ ߪೖத ʮ"TLUP#VZʯʹΑ

    ͬͯࢠڙ͕ߪೖΛ੍ ݶ͞Ε͍ͯΔঢ়ଶ ߪೖʹࣦഊ ߪೖʹ੒ޭ લճͷߪೖͷ෮ݩʹ ੒ޭ 6*΁ͷ൓ө ߪೖதͷϓϩάϨε Λදࣔ͢Δ 6*ʹ΋൓ө FSSPSʹΑͬͯϝοη ʔδΛදࣔ ϨγʔτͷWBMJEBUJPO ݁ՌΛදࣔ ϨγʔτͷWBMJEBUJPO ݁ՌΛදࣔ USBOTBDUJPOͷॲཧ   pOJTI5SBOTBDUJPO WBMJEBUJPOͷ੒ޭ͋Δ ͍͸Ϩγʔτ͕ظݶ ੾Εͷ৔߹͸ pOTI5SBOTBDUJPO WBMJEBUJPOͷ੒ޭ͋Δ ͍͸Ϩγʔτ͕ظݶ ੾Εͷ৔߹͸ pOTI5SBOTBDUJPO
  57. 4,1BZNFOU
 5SBOTBDUJPO4UBUF QVSDIBTJOH EFGFSSFE GBJMFE QVSDIBTFE SFTUPSFE ঢ়ଶ ߪೖத ʮ"TLUP#VZʯʹΑ

    ͬͯࢠڙ͕ߪೖΛ੍ ݶ͞Ε͍ͯΔঢ়ଶ ߪೖʹࣦഊ ߪೖʹ੒ޭ લճͷߪೖͷ෮ݩʹ ੒ޭ 6*΁ͷ൓ө ߪೖதͷϓϩάϨε Λදࣔ͢Δ 6*ʹ΋൓ө FSSPSʹΑͬͯϝοη ʔδΛදࣔ ϨγʔτͷWBMJEBUJPO ݁ՌΛදࣔ ϨγʔτͷWBMJEBUJPO ݁ՌΛදࣔ USBOTBDUJPOͷॲཧ   pOJTI5SBOTBDUJPO WBMJEBUJPOͷ੒ޭ͋Δ ͍͸Ϩγʔτ͕ظݶ ੾Εͷ৔߹͸ pOTI5SBOTBDUJPO WBMJEBUJPOͷ੒ޭ͋Δ ͍͸Ϩγʔτ͕ظݶ ੾Εͷ৔߹͸ pOTI5SBOTBDUJPO
  58. 4,1BZNFOU
 5SBOTBDUJPO4UBUF QVSDIBTJOH EFGFSSFE GBJMFE QVSDIBTFE SFTUPSFE ঢ়ଶ ߪೖத ʮ"TLUP#VZʯʹΑ

    ͬͯࢠڙ͕ߪೖΛ੍ ݶ͞Ε͍ͯΔঢ়ଶ ߪೖʹࣦഊ ߪೖʹ੒ޭ લճͷߪೖͷ෮ݩʹ ੒ޭ 6*΁ͷ൓ө ߪೖதͷϓϩάϨε Λදࣔ͢Δ 6*ʹ΋൓ө FSSPSʹΑͬͯϝοη ʔδΛදࣔ ϨγʔτͷWBMJEBUJPO ݁ՌΛදࣔ ϨγʔτͷWBMJEBUJPO ݁ՌΛදࣔ USBOTBDUJPOͷॲཧ   pOJTI5SBOTBDUJPO WBMJEBUJPOͷ੒ޭ͋Δ ͍͸Ϩγʔτ͕ظݶ ੾Εͷ৔߹͸ pOTI5SBOTBDUJPO WBMJEBUJPOͷ੒ޭ͋Δ ͍͸Ϩγʔτ͕ظݶ ੾Εͷ৔߹͸ pOTI5SBOTBDUJPO ΈͯͶͰ͸ ʮUI΁ͷ൓өʯͱʮtransactionͷॲཧʯ͸ ׬શʹಠཱ࣮ͯ͠ߦ͍ͯ͠Δ
  59. None
  60. ϨγʔτͷόϦσʔγϣϯ (Appଆ) • ߪೖ͕׬ྃ͢ΔͱϨγʔτ͕ൃߦ͞ΕΔ • Auto-Renewable Subscriptionͷ৔߹ɺ̍ͭͷϨγʔ τʹߪೖ৘ใ͕௥ه͞Ε͍ͯ͘ • Bundle.main.appStoreReceiptURL

    ʹϨγʔτͷσʔλ ͕ଘࡏ͢ΔͷͰऔಘ • base64Encodingͨ͠ϨγʔτͷDataΛαʔόʔʹPOST
  61. // Get receipt if available if let appStoreReceiptURL = Bundle.main.appStoreReceiptURL,

    FileManager.default.fileExists(atPath: appStoreReceiptURL.path) { do { let receiptData = try Data(contentsOf: appStoreReceiptURL, options: .alwaysMapped) let receiptString = receiptData.base64EncodedString(options: []) // Send ReceiptData to your server with user information } catch { print("Couldn't read receipt data with error: " + error.localizedDescription) } }
  62. // Get receipt if available if let appStoreReceiptURL = Bundle.main.appStoreReceiptURL,

    FileManager.default.fileExists(atPath: appStoreReceiptURL.path) { do { let receiptData = try Data(contentsOf: appStoreReceiptURL, options: .alwaysMapped) let receiptString = receiptData.base64EncodedString(options: []) // Send ReceiptData to your server with user information } catch { print("Couldn't read receipt data with error: " + error.localizedDescription) } } Ϩγʔτ͕ଘࡏ͍ͯ͠Ε͹औಘ
  63. // Get receipt if available if let appStoreReceiptURL = Bundle.main.appStoreReceiptURL,

    FileManager.default.fileExists(atPath: appStoreReceiptURL.path) { do { let receiptData = try Data(contentsOf: appStoreReceiptURL, options: .alwaysMapped) let receiptString = receiptData.base64EncodedString(options: []) // Send ReceiptData to your server with user information } catch { print("Couldn't read receipt data with error: " + error.localizedDescription) } } base64encodingͨ͠ϨγʔτΛ Ϣʔβʔ৘ใͱڞʹServer΁POST
  64. ϨγʔτͷόϦσʔγϣϯ(Serverଆ) • Appleͷఏڙ͢ΔAPIͷ /verifyReceipt ʹରͯ͠ઌͷ receipt-data ͱ password , exclude-old-transactionsΩʔΛ

    JSONͰPOST password͸ͪ͜Β͔Βऔಘ
  65. /verifyReceipt ͷϨεϙϯε • environment: Sandbox͔PROD͕஋ͱͯ͠ೖ͍ͬͯΔɻ • status: ਖ਼ৗͳΒ0ɺͦ͏Ͱͳ͚Ε͹20000୆ͷΤϥʔίʔυ͕ೖ͍ͬͯΔɻ • latest_receipt:

    Base64Τϯίʔυ͞Εͨ࠷৽Ϩγʔτσʔλ • latest_receipt_info: ࠷৽Ϩγʔτ৘ใ͕ೖ͍ͬͯΔɻجຊͪ͜Βͷ৘ใΛ΋ͱʹdbΛߋ৽ ͍ͯ͘͠ɻ cancellation_at ϑΟʔϧυ͕ଘࡏ͢Δ͔Ͳ͏͔ΛݟͯApple ΧελϚʔαϙʔτ ʹΑͬͯΩϟϯηϧ͞Ε͔ͨͲ͏͔Λه࿥͓ͯ͘͠ͱྑ͍ɻ • pending_renewal_info: ࣗಈߋ৽͕༧ఆ͞Ε͍ͯΔɺ͋Δ͍͸աڈʹࣗಈߋ৽ʹࣦഊͨ͠Ϩ γʔτ͕ೖ͍ͬͯΔɻ is_in_billing_retry_period ϑΟʔϧυΛݟͯϦτϥΠத͔Ͳ͏͔Λه ࿥ expiration_intent ϑΟʔϧυΛݟͯظݶ੾Εͷཧ༝Λه࿥͓ͯ͘͠ͱྑ͍ɻ • is-retryable: Apple಺෦ͷΤϥʔʹΑͬͯϨγʔτͷvalidationʹࣦഊͨ͠৔߹ʹtrueͱͳ Δɺͦͷ৔߹retry͢Δͱྑ͍ɻ
  66. None
  67. ߪೖ͋Γ͕ͱ͏γʔϯΛදࣔ • όϦσʔγϣϯʹ੒ޭ͠ ͨΒʮߪೖ͋Γ͕ͱ͏ʯ γʔϯΛදࣔ͢Δ • ΞϓϦ෮ؼ࣌ʹόϦσʔ γϣϯʹ੒ޭ͢Δέʔε ΋͋ΔͨΊɺಠཱ͍ͯ͠ ͭͰ΋ग़ͤΔΑ͏ʹͯ͠

    ͓͘
  68. ߪೖ͋Γ͕ͱ͏γʔϯΛදࣔ • όϦσʔγϣϯʹ੒ޭ͠ ͨΒʮߪೖ͋Γ͕ͱ͏ʯ γʔϯΛදࣔ͢Δ • ΞϓϦ෮ؼ࣌ʹόϦσʔ γϣϯʹ੒ޭ͢Δέʔε ΋͋ΔͨΊɺಠཱ͍ͯ͠ ͭͰ΋ग़ͤΔΑ͏ʹͯ͠

    ͓͘ ͍͍࣮ͩͨ૷Ͱ͖ͨ
  69. ൪֎ฤ: ΤϥʔϋϯυϦϯά • ൃੜ͠͏ΔΤϥʔͷछྨ 1. transactionState ͕ .failed ͷঢ়ଶ 2.

    transactionState ͸ .purchased ͕ͩϨ γʔτͷόϦσʔγϣϯʹࣦഊ
  70. 1. transactionState͕ .failed ͷঢ়ଶ • AppStoreଆͷΤϥʔͳͷͰɺ localizedDescription ΛAlertʹ දࣔͯ͋͛͠Δ •

    ͨͩ͠ɺߪೖ్தʹΩϟϯηϧΛԡͯ͠΋transaction ͸ .failed ѻ͍ͱͳΔͷͰguardͯ͋͛͠Δඞཁ͕͋Δ
  71. 1. transactionState͕ .failed ͷঢ়ଶ • AppStoreଆͷΤϥʔͳͷͰɺ localizedDescription ΛAlertʹ දࣔͯ͋͛͠Δ •

    ͨͩ͠ɺߪೖ్தʹΩϟϯηϧΛԡͯ͠΋transaction ͸ .failed ѻ͍ͱͳΔͷͰguardͯ͋͛͠Δඞཁ͕͋Δ if let error = error as? SKError, error.code != .paymentCancelled { DispatchQueue.main.async { self.delegate?.presentAlert(error.localizedDescription) } }
  72. 2. transactionState͸ .purchased ͕ͩϨγʔ τͷόϦσʔγϣϯʹࣦഊ • ΈͯͶͷ৔߹2ύλʔϯͷΤϥʔΛϋϯυϦϯά 1. αʔόʔଆͰͷ༧ଌෆೳͳΤϥʔ 2.

    ड͚औͬͨϨγʔτ͕͢ͰʹϢʔβʔ(Ո଒)ͱ
 ඥ͍͍ͮͯΔ৔߹ͷΤϥʔ • restoreʹΑͬͯαϒεΫϦϓγϣϯΛ෮ݩ͢Δࡍ ʹൃੜ͠͏Δ (restoreʹ͍ͭͯ͸ޙ΄Ͳ࿩͠·͢)
  73. • ӈͷΑ͏ͳAlertΛදࣔ͠ɺ͓໰ ͍߹Θͤ΁༠ಋͰ͖ΔΑ͏ʹ͠ ͍ͯΔ • ϝʔϥʔͷbodyʹ͸֘౰ͷ transactionIdentifierΛ෇༩ͯ͠ ϢʔβʔΛdb͔ΒḷΕΔΑ͏ʹ ͍ͯ͠Δ

  74. αʔόʔؒ௨஌ʹ͍ͭͯ 4.

  75. αʔόʔؒ௨஌ͱ͸ʁ • App Store͔ΒϦΞϧλΠϜʹsubscriptionͷঢ়ଶมԽͷ௨஌ ΛHTTP POSTͰड͚औΔ࢓૊Έ (statusUpdateNotifications ͱݺ͹Εͯͨ) • Ϩεϙϯεʹ200Λฦ͞ͳ͍ݶΓ3ճ·ͰϦτϥΠͯ͘͠ΕΔ

    • ࣮૷͸optional͕ͩϨγʔτͷঢ়ଶΛ࠷৽ʹอͬͨΓϢʔ βʔʹରͯ͠offerΛग़ͤΔΑ͏ʹ͢ΔͨΊʹ΋΍͓͍ͬͯͨ ํ͕͍͍
  76. AppStoreConnectͰURLΛઃఆ • ͪ͜ΒͰ༻ҙ͓͍ͯͨ͠POSTΛड͚औΔURLΛ AppStoreConnectͰೖྗ IUUQTIFMQBQQMFDPNBQQTUPSFDPOOFDUEFWBC

  77. αʔόʔؒ௨஌Λड͚औΔ • POST͞ΕΔJSON͔Βجຊతʹ࢖͏ϑΟʔϧυ͸ҎԼͷ௨Γ • environment: Sandbox͔PROD͕஋ͱͯ͠ೖ͍ͬͯΔ • notification_type: αʔόʔؒ௨஌ͷtype(ৄ͘͠͸ޙड़͠·͢) •

    password: /verifyReceiptͷࡍʹ΋࢖༻ͨ͠shared secret • cancellation_date: AppleͷαϙʔτΛ௨ͯ͠ฦۚॲཧ͕ͳ͞ΕͯΩϟϯηϧ͞Εͨ೔࣌ • latest_receipt: Base64Τϯίʔυ͞Εͨ࠷৽Ϩγʔτσʔλ • latest_receipt_info: latest_receiptΛJSONͰදݱͨ͠΋ͷ • latest_expired_receipt: Base64Τϯίʔυ͞Εͨظݶͷ੾Ε͍ͯΔϨγʔτɺ • latest_expired_receipt_info: latest_expired_receiptΛJSONͰදݱͨ͠΋ͷ • auto_renew_status: ݱࡏࣗಈߋ৽ઃఆத͔Ͳ͏͔ͷϑϥά • auto_renew_status_change_date: ࣗಈߋ৽ͷঢ়ଶΛߋ৽ͨ͠೔࣌
  78. αʔόʔؒ௨஌Λड͚औΔ • POST͞ΕΔJSON͔Βجຊతʹ࢖͏ϑΟʔϧυ͸ҎԼͷ௨Γ • environment: Sandbox͔PROD͕஋ͱͯ͠ೖ͍ͬͯΔ • notification_type: αʔόʔؒ௨஌ͷtype(ৄ͘͠͸ޙड़͠·͢) •

    password: /verifyReceiptͷࡍʹ΋࢖༻ͨ͠shared secret • cancellation_date: AppleͷαϙʔτΛ௨ͯ͠ฦۚॲཧ͕ͳ͞ΕͯΩϟϯηϧ͞Εͨ೔࣌ • latest_receipt: Base64Τϯίʔυ͞Εͨ࠷৽Ϩγʔτσʔλ • latest_receipt_info: latest_receiptΛJSONͰදݱͨ͠΋ͷ • latest_expired_receipt: Base64Τϯίʔυ͞Εͨظݶͷ੾Ε͍ͯΔϨγʔτɺ • latest_expired_receipt_info: latest_expired_receiptΛJSONͰදݱͨ͠΋ͷ • auto_renew_status: ݱࡏࣗಈߋ৽ઃఆத͔Ͳ͏͔ͷϑϥά • auto_renew_status_change_date: ࣗಈߋ৽ͷঢ়ଶΛߋ৽ͨ͠೔࣌ ΈͯͶͰ͸ latest_receipt ͷσʔλΛ
 /verifyReceiptʹ౤͛Δϑϩʔʹ৐ͤΔ
 Α͏ʹ࣮૷
  79. ͦΕͧΕͷ௨஌λΠϓͷछྨ */*5*"-@#6: αϒεΫϦϓγϣϯΛ࠷ॳʹߪೖͨ͠ͱ͖ʹड͚औΔɻ ͍ͭͰ΋WFSJGZͯ͠࠷৽ϨγʔτΛऔͬͯདྷΕΔΑ͏ʹɺϨγʔτσʔλΛอଘ͠ ͓ͯ͘ɻ $"/$&- "QQMFͷαϙʔτܦ༝ɺ͋Δ͍͸"QQ4UPSFͰαϒεΫϦϓγϣϯΛΞοϓάϨʔ υͨ͠ࡍʹड͚औΔɻ TVCTDSJQUJPO@EBUFϑΟʔϧυ͕͍ͭΩϟϯηϧ͞Ε͔ͨΛ࣋ͭɻ 3&/&8"-

    Ұ౓ࣗಈߋ৽ʹࣦഊͨ͠ظݶ੾ΕͷαϒεΫϦϓγϣϯ͕ͦͷޙແࣄʹߋ৽Ͱ͖ ͨͱ͖ʹड͚औΔɻ FYQJSFT@EBUFΛݟͯ࣍ͷߋ৽࣌ࠁΛ֬ఆͤ͞Δɻ */5&3"$5*7& @3&/&8"- ΞϓϦܦ༝ɺ͋Δ͍͸"QQ4UPSFͷΞΧ΢ϯτઃఆ͔ΒαϒεΫϦϓγϣϯΛߋ৽ ͞Εͨࡍʹड͚औΔɻ αʔϏεΛ͙͢ʹར༻Ͱ͖Δঢ়ଶʹͯ͋͛͠Δඞཁ͕͋Δɻ %*%@$)"/(& @3&/&8"-@13&' ϓϥϯͷάϨʔυΛมߋ͞Εͨࡍʹड͚औΔɻ ݱߦͷϓϥϯʹ͸ಛʹӨڹ͸ͳ͍ɻ %*%@$)"/(& @3&/&8"-@45"564 ࣗಈߋ৽ͷઃఆʹมߋ͕͋ͬͨࡍʹड͚औΔɻ BVUP@SFOFX@TUBUVT@DIBOHF@EBUFͱBVUP@SFOFX@TUBUVTΛݟ͍ͯͭมߋ͕͋ͬ ͨͷ͔ɺݱࡏͷࣗಈߋ৽ͷঢ়ଶΛ֬ೝ͢Δɻ
  80. ࠓळ͔Β௥Ճ͞ΕΔ৽͍͠௨஌λΠϓ • WWDC19 ʮIn-App Purchases and Using Server-to-Server Notificationsʯʹͯൃද •

    ҎԼͷ3͕ͭ৽͘͠ՃΘΔ • DID_FAIL_TO_RENEW • DID_RECOVER • PRICE_INCREASE_CONSENT • DID_RECOVER͸طଘͷRENEWAL௨஌λΠϓͱஔ͖׵ΘΔ New
  81. ͦΕͧΕͷ௨஌λΠϓͷछྨ %*%@'"*-@50@3&/&8 ࣗಈߋ৽͠Α͏ͱ͕ࣦͨ͠ഊͨ͠৔߹ʹड͚औΔɻ %*%@3&$07&3 #JMMJOH3FUSZʹΑͬͯαϒεΫϦϓγϣϯͷߋ৽͕
 ੒ޭͨ͠ͱ͖ʹड͚औΔɻ 13*$&@*/$3&"4&@$0/4&/5 طଘϢʔβʔʹରͯ͠αϒεΫϦϓγϣϯͷՁ֨ΛҾ্͖͛ͨͱ͖ɺ
 ͓ΑͼͦΕʹϢʔβʔ͕ಉҙͨ͠ͱ͖ʹड͚औΔɻ

  82. ֤௨஌λΠϓͷλΠϛϯά

  83. INITIAL_BUY "QQ4UPSF 1VSDIBTF 4FSWFS

  84. INITIAL_BUY "QQ4UPSF 1VSDIBTF 4FSWFS

  85. INITIAL_BUY "QQ4UPSF 1VSDIBTF 4FSWFS */*5*"-@#6:

  86. INITIAL_BUY "QQ4UPSF 1VSDIBTF 4FSWFS CBTFFODPEFE SFDFJQU */*5*"-@#6: WFSJGZ@SFDFJQU

  87. INITIAL_BUY "QQ4UPSF 1VSDIBTF 4FSWFS CBTFFODPEFE SFDFJQU */*5*"-@#6: WFSJGZ@SFDFJQU INITIAL_BUYͷ৘ใͱϢʔβʔͷ৘ใΛoriginal_transaction_identifier, web_order_line_item_idΛΩʔͱͯͭ͠ͳ͗߹ΘͤΔ

  88. INITIAL_BUY "QQ4UPSF 1VSDIBTF 4FSWFS CBTFFODPEFE SFDFJQU */*5*"-@#6: WFSJGZ@SFDFJQU INITIAL_BUYͷ৘ใͱϢʔβʔͷ৘ใΛoriginal_transaction_identifier, web_order_line_item_idΛΩʔͱͯͭ͠ͳ͗߹ΘͤΔ

    ݱঢ়ΈͯͶͰ͸ड͚औͬͨINITIAL_BUYΛ อଘ͓͍ͯͯ͠ޙ͔Βಥ͖߹ΘͤΔͱ͍͏ ͜ͱ͸͍ͯ͠·ͤΜ
  89. CANCEL (Upgrade) "QQ4UPSF 6QHSBEF 4FSWFS

  90. CANCEL (Upgrade) "QQ4UPSF 6QHSBEF 4FSWFS $"/$&-

  91. CANCEL (Cancel Subscription) "QQ4UPSF $BODFM4VCTDSJQUJPO 4FSWFS

  92. CANCEL (Cancel Subscription) "QQ4UPSF $BODFM4VCTDSJQUJPO 4FSWFS $"/$&-

  93. CANCEL (Cancel Subscription) "QQ4UPSF $BODFM4VCTDSJQUJPO 4FSWFS $"/$&- ͲͷϓϩμΫτʹର͍ͯͭ͠Ωϟϯηϧͨ͠ͷ͔ͱ͍͏৘ใΛ ֘౰Ϣʔβʔʹରͯ͠ߋ৽͢Δ

  94. INTERACTIVE_RENEWAL "QQ4UPSF 6QHSBEF 4FSWFS

  95. INTERACTIVE_RENEWAL "QQ4UPSF 6QHSBEF 4FSWFS */5&3"$5*7& @3&/&8"-

  96. INTERACTIVE_RENEWAL "QQ4UPSF 6QHSBEF 4FSWFS ͲͷϓϩμΫτʹର͍ͯͭ͠Upgradeͨ͠ͷ͔ͱ͍͏৘ใΛ ֘౰Ϣʔβʔʹରͯ͠ߋ৽͢Δ */5&3"$5*7& @3&/&8"-

  97. INTERACTIVE_RENEWAL "QQ4UPSF 6QHSBEF 4FSWFS ͲͷϓϩμΫτʹର͍ͯͭ͠Upgradeͨ͠ͷ͔ͱ͍͏৘ใΛ ֘౰Ϣʔβʔʹରͯ͠ߋ৽͢Δ */5&3"$5*7& @3&/&8"- ݱঢ়ΈͯͶͰ͸ϓϥϯͷGrade͸ ͔̍ͭ͠ͳ͍ͷͰ

    ͜ͷ௨஌λΠϓ͸ແࢹ͍ͯ͠Δ
  98. DID_CHANGE_RENEWAL_STATUS "QQ4UPSF 4XJUDIBVUPSFOFXJOH 4FSWFS

  99. DID_CHANGE_RENEWAL_STATUS "QQ4UPSF 4XJUDIBVUPSFOFXJOH 4FSWFS %*%@$)"/(& @3&/&8"-
 @45"564

  100. DID_CHANGE_RENEWAL_STATUS "QQ4UPSF 4XJUDIBVUPSFOFXJOH 4FSWFS ࣗಈߋ৽͔Ͳ͏͔ͷϑϥάΛ֘౰Ϣʔβʔʹରͯ͠ߋ৽͢Δ %*%@$)"/(& @3&/&8"-
 @45"564

  101. DID_FAIL_TO_RENEW "QQ4UPSF #JMMJOH&SSPS 4FSWFS

  102. DID_FAIL_TO_RENEW "QQ4UPSF #JMMJOH&SSPS 4FSWFS %*%@'"*-@50 @3&/&8

  103. DID_FAIL_TO_RENEW "QQ4UPSF #JMMJOH&SSPS 4FSWFS %*%@'"*-@50 @3&/&8 ֘౰ϢʔβʔͷαϒεΫϦϓγϣϯͷঢ়ଶΛߋ৽͢Δ

  104. DID_RECOVER "QQ4UPSF #JMMJOH3FUSZ 4FSWFS

  105. DID_RECOVER "QQ4UPSF #JMMJOH3FUSZ 4FSWFS %*% @3&$07&3

  106. DID_RECOVER "QQ4UPSF #JMMJOH3FUSZ 4FSWFS ༗ޮظݶͱαϒεΫϦϓγϣϯͷঢ়ଶΛߋ৽͢Δ %*% @3&$07&3

  107. ࠓळ͔Β৽͘͠௥Ճ͞ΕΔunified_receipt • WWDC19ʮIn-App Purchases and Using Server-to-Server Notificationsʯ ʹͯൃද •

    unified_receipt ͱ͍͏৽͍͠ϑΟʔϧυ͕௥Ճ͞ΕΔ • /verifyReceipt Λୟ͔ͳ͍ͱಘΒΕͳ͔ͬͨϑΟʔϧυΛऔಘͰ͖Δ • ΋͏ latest_receipt ͱ latest_receipt_info Λࢀর͢Δඞཁ͕ͳ͘ɺ / verifyReceiptΛୟ͘ඞཁ΋ͳ͍ • (receiptِ͕૷͞ΕΔՄೳੑΛߟ͑Δͱ/verifyReceiptΛୟ͍͓͖͍ͯͨ ؾ࣋ͪʹͳΔ͕ɺՌͨͯ͠…) New
  108. ࠓळ͔Β৽͘͠௥Ճ͞ΕΔGrace Period • WWDC19 ʮIn-App Purchases and Using Server-to-Server Notificationsʯʹͯൃද

    • Billing ErrorʹΑΔղ໿ϢʔβʔΛݮΒ͢΂͘ɺ༗ޮظݶʹରͯ࣋ͨͤ͠Δ༛༧ظؒ • ࣮͸WWDC18ͷηογϣϯʮEngineering SubscriptionsʯͰ͸ࣗલͰͷ࣮૷Λ ਪ঑͞Ε͍ͯͨ • ΈͯͶͰ͸ࣗલͰ࣮૷ࡁΈʂ • Grace Periodظؒத΋αʔϏεΛఏڙͯ͋͛͠Δ͜ͱͰɺղ໿཰ΛݮΒͭͭ͠ɺͦ ͷظؒ෼ͷ௥Ճใु΋ಘΔ͜ͱ͕Ͱ͖Δ • Appleͷ౷ܭͱͯ͠͸ 16೔ؒ ͕ߋ৽ʹࣦഊͨ͠Ϣʔβʔͷ80%ΛऔΓ໭ͤΔظؒͷ Α͏Ͱɺͦ͜ΛGrace Periodͱͯ͠ఆΊ͍ͯΔ New
  109. Grace Periodͷ࣮૷ํ๏ • WWDCͷηογϣϯͰड़΂ΒΕ͍ͯͨͷ͸ҎԼͷ3Step ͚ͩͰ͋Δ 1. App Store ConnectͰGrace PeriodΛߏ੒

    2. /verifyReceipt ͷ৽͍͠ϑΟʔϧυ grace_period_expires_date ΛϋϯυϦϯά 3. Graceظؒ·ͰαʔϏεΛఏڙ͠ଓ͚ΔΑ͏ʹ࣮૷
  110. Status Pollingʹ͍ͭͯ 5.

  111. Status Pollingͱ͸ʁ • ظݶ੾ΕલޙͷϨγʔτΛ /verifyReceipt ʹରͯ͠tokenͷΑ͏ʹ౤͛Δ͜ ͱͰ࠷৽ϨγʔτΛऔಘͯ͠dbͷঢ়ଶΛߋ৽͢Δ͜ͱΛࢦ͢ • Ϩγʔτ͸ΞϓϦͷىಈ(͋Δ͍͸αʔόʔؒ௨஌)ʹΑͬͯͷΈߋ৽͞ΕΔ ͷͰɺ΋͠WebͰར༻Ͱ͖ΔαʔϏεΛఏڙ͍ͯ͠Δ৔߹ɺStatus

    Polling Ͱ࠷৽ͷঢ়ଶΛҡ࣋͢Δඞཁ͕͋Δ • ΈͯͶϓϨϛΞϜͰ͸Web্ͷػೳΛఏڙ͍ͯͨͨ͠Ί
 ࣮૷͓ͯ͘͠ඞཁ͕͋ͬͨ • ͪͳΈʹ͜ͷख๏͸WWDC18 ʮEngineering SubscriptionsʯʹΑͬͯޠΒ ΕΔͷΈͰυΩϡϝϯτԽ͞Ε͍ͯͳ͍
  112. ͍ͭStatus PollingΛ࣮ߦ͢΂͖͔ • WWDC2018 ʮEngineering SubscriptionsʯͰ͸ҎԼͷΑ͏ʹظݶ͕੾ΕΔલޙͷλ ΠϛϯάͰ͢ΔΑ͏ʹݴΘΕ͍ͯΔ • ΈͯͶͰ͸Grace Periodத͓ΑͼGrace

    Period͕ऴྃͯ͠1೔ޙͷϢʔβʔʹରͯ͠ຖ ே࣮ߦ͍ͯ͠Δ IUUQTEFWFMPQFSBQQMFDPNWJEFPTQMBZXXED
  113. Sandbox؀ڥʹ͓͚Δ
 ಈ࡞֬ೝ 6.

  114. Sandbox؀ڥ • App Store ConnectͰςελʔΞΧ΢ϯτΛ࡞੒͢ Δ͜ͱͰςετ؀ڥͰಈ࡞֬ೝ͕Ͱ͖Δ • ʮUsers and Accessʯͷϖʔδ͔Β؆୯ʹ࡞੒Մೳ

    • ֤SandboxϢʔβʔʹରͯ͠طଘͷApple IDʹඥͮ ͚ΒΕ͍ͯͳ͍ϝʔϧΞυϨεΛઃఆ • νʔϜͰڞ༗͓ͯ͘͠ͱΑ͍
  115. SandboxͰൃߦ͞ΕΔϨγʔτ • SandboxͰൃߦ͞ΕΔϨγʔτ͸ҎԼͷରԠ දͷΑ͏ʹొ࿥ظ͕ؒ୹ॖ͞ΕΔ IUUQTIFMQBQQMFDPNBQQTUPSFDPOOFDUEFWFFE

  116. Sandbox؀ڥʁຊ൪؀ڥʁʁ • αʔόʔؒ௨஌ • ઃఆͰ͖ΔURL͸̍ͭͳͷͰɺຊ൪αʔόʔʹͷΈ௨஌͸POST͞ΕΔ • POST͞Εͨ௨஌ͷenvironmentΛݟͯ `Sandbox` Ͱ͋Ε͹։ൃαʔόʔ΁Ϧμ ΠϨΫτ͢Δඞཁ͕͋Δ

  117. Sandbox؀ڥʁຊ൪؀ڥʁʁ • αʔόʔؒ௨஌ • ઃఆͰ͖ΔURL͸̍ͭͳͷͰɺຊ൪αʔόʔʹͷΈ௨஌͸POST͞ΕΔ • POST͞Εͨ௨஌ͷenvironmentΛݟͯ `Sandbox` Ͱ͋Ε͹։ൃαʔόʔ΁Ϧμ ΠϨΫτ͢Δඞཁ͕͋Δ

    • /verifyReceipt • ຊ൪: https://buy.itunes.apple.com/verifyReceipt
 Sandbox: https://sandbox.itunes.apple.com/verifyReceipt
 • Appleͷ৹ࠪ͸Sandbox؀ڥͰߦΘΕΔ •ʮΈͯͶ: ຊ൪ + Receipt: Sandboxʯ ͷঢ়گ͕ੜ·ΕΔ • Ұ౓ϨγʔτΛຊ൪ʹPOSTͯ͠20007ͷΤϥʔίʔυ͕ฦ͖ͬͯͨΒSandbox ʹ౤͛௚͢ඞཁ͕͋Δ
  118. ެ։લʹຊ൪؀ڥͷϨγʔτΛऔಘ͍ͨ͠ • TestflightͰ഑৴ͯ͠΋Ϩγʔτ͸SandboxͰ ൃߦ͞Εͨ΋ͷʹͳΔ • લड़ͷ௨ΓɺAppleͷ৹ࠪ΋SandboxͰൃߦ ͞ΕͨϨγʔτΛ࢖༻ • ͭ·ΓɺϦϦʔε͢Δ·Ͱຊ൪ͷϨγʔτΛ ॲཧͰ͖ͳ͍

  119. Promotion CodeΛ࢖ͬͯຊ൪֬ೝ • ਃ੥ͷ௨ͬͨΞϓϦͳͲΛެ։લͰ΋഑෍͢Δ͜ͱ͕Ͱ ͖Δͷ͕Promotion Code • ʮજࡏސ٬΍ϨϏϡʔهࣄ࡞੒ऀ΁ͷ഑෍ͳͲϓϩϞʔ γϣϯͷͨΊͷ࢖༻ʯ͕૝ఆ͞Ε͍ͯΔ •

    ͕ɺ͜ΕͳΒຊ൪؀ڥͷϨγʔτ͕खʹೖΔʂ • ΈͯͶͰ͸͜ΕʹΑΓαʔόʔଆͷͪΐͬͱͨ͠όάΛ ϦϦʔεલʹચ͍ग़ͨ͠
  120. ϦδΣΫτʹ͍ͭͯ
 ؾΛ͚͍ͭͨϙΠϯτ 7.

  121. RestoreϘλϯ͸ඞਢ • Auto-Renewable(or Non-Renewing or Non-Consumable) ͷ՝ۚͷ৔߹͸RestoreػೳΛ࣮૷͢Δඞཁ͕͋Δ • ResotreϘλϯ͕ͳ͍ͱϦδΣΫτ͞ΕΔ •

    Restoreͷ࣮૷ʹ͸2ύλʔϯ͋Δ 1. Restore Completed Transactions 2. Refresh Receipt
  122. 1. Restore Completed Transactions • finishTransaction() ʹΑͬͯ׬ྃͤͯ͞͠·ͬ ͨtransactionΛ෮ݩ͢Δํ๏ SKPaymentQueue.default().restoreCompletedTransactions() •

    restore͕׬ྃͨ͠ΒϨγʔτΛόϦσʔγϣ ϯʹ௨্ͨ͠ͰfinishTransaction() ͯ͋͛͠Δ
  123. 2. Refresh Receipt • Apple͔Β࠷৽ͷϨγʔτΛཁٻͯ͠ϩʔΧϧʹอଘ͢Δ • ৽͘͠transactionΛൃߦ͸͠ͳ͍ // Keep a

    strong reference to the product request. var request: SKProductsRequest! func requestProductInformation(with productIdentifiers: [String]) { let productIdentifiers = Set(productIdentifiers) request = SKReceiptRefreshRequest( receiptProperties: [SKReceiptPropertyIsExpired: false] ) request.delegate = self request.start() }
  124. 2. Refresh Receipt • Apple͔Β࠷৽ͷϨγʔτΛཁٻͯ͠ϩʔΧϧʹอଘ͢Δ • ৽͘͠transactionΛൃߦ͸͠ͳ͍ // Keep a

    strong reference to the product request. var request: SKProductsRequest! func requestProductInformation(with productIdentifiers: [String]) { let productIdentifiers = Set(productIdentifiers) request = SKReceiptRefreshRequest( receiptProperties: [SKReceiptPropertyIsExpired: false] ) request.delegate = self request.start() } validationʹ੒ޭ͠ͳ͍ݶΓfinishTransaction() Λݺͼग़͢͜ͱ͸ͳ͍ͷͰɺΈͯͶͰ͸Refresh ReceiptʹΑͬͯRestoreΛ࣮૷͍ͯ͠Δ
  125. ߪೖγʔϯʹදࣔ͢΂͖৘ใΛ࿙Εͳ͘ ྻڍ͢Δ

  126. ߪೖγʔϯʹදࣔ͢΂͖৘ใΛ࿙Εͳ͘ ྻڍ͢Δ • αϒεΫϦϓγϣϯͷ໊લɺظؒɺαϒεΫϦϓγϣϯͷ֤ظؒʹఏڙ͞ΕΔίϯςϯπ΍α ʔϏε

  127. ߪೖγʔϯʹදࣔ͢΂͖৘ใΛ࿙Εͳ͘ ྻڍ͢Δ • αϒεΫϦϓγϣϯͷ໊લɺظؒɺαϒεΫϦϓγϣϯͷ֤ظؒʹఏڙ͞ΕΔίϯςϯπ΍α ʔϏε • Ϣʔβʔ΁ͷ੥ٻํ๏ɺϢʔβʔ͕αϒεΫϦϓγϣϯΛ؅ཧ͢Δํ๏

  128. ߪೖγʔϯʹදࣔ͢΂͖৘ใΛ࿙Εͳ͘ ྻڍ͢Δ • αϒεΫϦϓγϣϯͷ໊લɺظؒɺαϒεΫϦϓγϣϯͷ֤ظؒʹఏڙ͞ΕΔίϯςϯπ΍α ʔϏε • Ϣʔβʔ΁ͷ੥ٻํ๏ɺϢʔβʔ͕αϒεΫϦϓγϣϯΛ؅ཧ͢Δํ๏ • ߪೖ֬ఆ࣌ʹɺࢧ෷͍͸ϢʔβʔͷApple IDΞΧ΢ϯτʹ՝ۚ͞ΕΔ͜ͱ

  129. ߪೖγʔϯʹදࣔ͢΂͖৘ใΛ࿙Εͳ͘ ྻڍ͢Δ • αϒεΫϦϓγϣϯͷ໊લɺظؒɺαϒεΫϦϓγϣϯͷ֤ظؒʹఏڙ͞ΕΔίϯςϯπ΍α ʔϏε • Ϣʔβʔ΁ͷ੥ٻํ๏ɺϢʔβʔ͕αϒεΫϦϓγϣϯΛ؅ཧ͢Δํ๏ • ߪೖ֬ఆ࣌ʹɺࢧ෷͍͸ϢʔβʔͷApple IDΞΧ΢ϯτʹ՝ۚ͞ΕΔ͜ͱ

    • ݱࡏͷظ͕ؒऴྃ͢Δগͳ͘ͱ΋24࣌ؒલʹϢʔβʔ͕Ωϟϯηϧ͠ͳ͍ݶΓɺαϒεΫ Ϧϓγϣϯ͸ࣗಈతʹߋ৽͞ΕΔ͜ͱ
  130. ߪೖγʔϯʹදࣔ͢΂͖৘ใΛ࿙Εͳ͘ ྻڍ͢Δ • αϒεΫϦϓγϣϯͷ໊લɺظؒɺαϒεΫϦϓγϣϯͷ֤ظؒʹఏڙ͞ΕΔίϯςϯπ΍α ʔϏε • Ϣʔβʔ΁ͷ੥ٻํ๏ɺϢʔβʔ͕αϒεΫϦϓγϣϯΛ؅ཧ͢Δํ๏ • ߪೖ֬ఆ࣌ʹɺࢧ෷͍͸ϢʔβʔͷApple IDΞΧ΢ϯτʹ՝ۚ͞ΕΔ͜ͱ

    • ݱࡏͷظ͕ؒऴྃ͢Δগͳ͘ͱ΋24࣌ؒલʹϢʔβʔ͕Ωϟϯηϧ͠ͳ͍ݶΓɺαϒεΫ Ϧϓγϣϯ͸ࣗಈతʹߋ৽͞ΕΔ͜ͱ • ݱࡏͷظ͕ؒऴྃ͢Δલͷ24࣌ؒҎ಺ʹɺΞΧ΢ϯτʹߋ৽ֹ͕ۚ՝ۚ͞ΕΔ͜ͱ
  131. ߪೖγʔϯʹදࣔ͢΂͖৘ใΛ࿙Εͳ͘ ྻڍ͢Δ • αϒεΫϦϓγϣϯͷ໊લɺظؒɺαϒεΫϦϓγϣϯͷ֤ظؒʹఏڙ͞ΕΔίϯςϯπ΍α ʔϏε • Ϣʔβʔ΁ͷ੥ٻํ๏ɺϢʔβʔ͕αϒεΫϦϓγϣϯΛ؅ཧ͢Δํ๏ • ߪೖ֬ఆ࣌ʹɺࢧ෷͍͸ϢʔβʔͷApple IDΞΧ΢ϯτʹ՝ۚ͞ΕΔ͜ͱ

    • ݱࡏͷظ͕ؒऴྃ͢Δগͳ͘ͱ΋24࣌ؒલʹϢʔβʔ͕Ωϟϯηϧ͠ͳ͍ݶΓɺαϒεΫ Ϧϓγϣϯ͸ࣗಈతʹߋ৽͞ΕΔ͜ͱ • ݱࡏͷظ͕ؒऴྃ͢Δલͷ24࣌ؒҎ಺ʹɺΞΧ΢ϯτʹߋ৽ֹ͕ۚ՝ۚ͞ΕΔ͜ͱ • Ϣʔβʔ͸App StoreͷΞΧ΢ϯτઃఆͰαϒεΫϦϓγϣϯΛ؅ཧ͓ΑͼΩϟϯηϧͰ ͖Δ͜ͱ
  132. ߪೖγʔϯʹදࣔ͢΂͖৘ใΛ࿙Εͳ͘ ྻڍ͢Δ • αϒεΫϦϓγϣϯͷ໊લɺظؒɺαϒεΫϦϓγϣϯͷ֤ظؒʹఏڙ͞ΕΔίϯςϯπ΍α ʔϏε • Ϣʔβʔ΁ͷ੥ٻํ๏ɺϢʔβʔ͕αϒεΫϦϓγϣϯΛ؅ཧ͢Δํ๏ • ߪೖ֬ఆ࣌ʹɺࢧ෷͍͸ϢʔβʔͷApple IDΞΧ΢ϯτʹ՝ۚ͞ΕΔ͜ͱ

    • ݱࡏͷظ͕ؒऴྃ͢Δগͳ͘ͱ΋24࣌ؒલʹϢʔβʔ͕Ωϟϯηϧ͠ͳ͍ݶΓɺαϒεΫ Ϧϓγϣϯ͸ࣗಈతʹߋ৽͞ΕΔ͜ͱ • ݱࡏͷظ͕ؒऴྃ͢Δલͷ24࣌ؒҎ಺ʹɺΞΧ΢ϯτʹߋ৽ֹ͕ۚ՝ۚ͞ΕΔ͜ͱ • Ϣʔβʔ͸App StoreͷΞΧ΢ϯτઃఆͰαϒεΫϦϓγϣϯΛ؅ཧ͓ΑͼΩϟϯηϧͰ ͖Δ͜ͱ • Appͷར༻ن໿΁ͷϦϯΫ
  133. ߪೖγʔϯʹදࣔ͢΂͖৘ใΛ࿙Εͳ͘ ྻڍ͢Δ • αϒεΫϦϓγϣϯͷ໊લɺظؒɺαϒεΫϦϓγϣϯͷ֤ظؒʹఏڙ͞ΕΔίϯςϯπ΍α ʔϏε • Ϣʔβʔ΁ͷ੥ٻํ๏ɺϢʔβʔ͕αϒεΫϦϓγϣϯΛ؅ཧ͢Δํ๏ • ߪೖ֬ఆ࣌ʹɺࢧ෷͍͸ϢʔβʔͷApple IDΞΧ΢ϯτʹ՝ۚ͞ΕΔ͜ͱ

    • ݱࡏͷظ͕ؒऴྃ͢Δগͳ͘ͱ΋24࣌ؒલʹϢʔβʔ͕Ωϟϯηϧ͠ͳ͍ݶΓɺαϒεΫ Ϧϓγϣϯ͸ࣗಈతʹߋ৽͞ΕΔ͜ͱ • ݱࡏͷظ͕ؒऴྃ͢Δલͷ24࣌ؒҎ಺ʹɺΞΧ΢ϯτʹߋ৽ֹ͕ۚ՝ۚ͞ΕΔ͜ͱ • Ϣʔβʔ͸App StoreͷΞΧ΢ϯτઃఆͰαϒεΫϦϓγϣϯΛ؅ཧ͓ΑͼΩϟϯηϧͰ ͖Δ͜ͱ • Appͷར༻ن໿΁ͷϦϯΫ • ݱଘͷར༻ऀ͕αΠϯΠϯͨ͠ΓߪೖΛ෮ݩͨ͠Γ͢Δํ๏
  134. ߪೖγʔϯʹදࣔ͢΂͖৘ใΛ࿙Εͳ͘ ྻڍ͢Δ • αϒεΫϦϓγϣϯͷ໊લɺظؒɺαϒεΫϦϓγϣϯͷ֤ظؒʹఏڙ͞ΕΔίϯςϯπ΍α ʔϏε • Ϣʔβʔ΁ͷ੥ٻํ๏ɺϢʔβʔ͕αϒεΫϦϓγϣϯΛ؅ཧ͢Δํ๏ • ߪೖ֬ఆ࣌ʹɺࢧ෷͍͸ϢʔβʔͷApple IDΞΧ΢ϯτʹ՝ۚ͞ΕΔ͜ͱ

    • ݱࡏͷظ͕ؒऴྃ͢Δগͳ͘ͱ΋24࣌ؒલʹϢʔβʔ͕Ωϟϯηϧ͠ͳ͍ݶΓɺαϒεΫ Ϧϓγϣϯ͸ࣗಈతʹߋ৽͞ΕΔ͜ͱ • ݱࡏͷظ͕ؒऴྃ͢Δલͷ24࣌ؒҎ಺ʹɺΞΧ΢ϯτʹߋ৽ֹ͕ۚ՝ۚ͞ΕΔ͜ͱ • Ϣʔβʔ͸App StoreͷΞΧ΢ϯτઃఆͰαϒεΫϦϓγϣϯΛ؅ཧ͓ΑͼΩϟϯηϧͰ ͖Δ͜ͱ • Appͷར༻ن໿΁ͷϦϯΫ • ݱଘͷར༻ऀ͕αΠϯΠϯͨ͠ΓߪೖΛ෮ݩͨ͠Γ͢Δํ๏ • ϓϥΠόγʔϙϦγʔ΁ͷϦϯΫ
  135. ࠷ऴతͳΈͯͶͷߪೖϖʔδ

  136. ϦϦʔεલʹ༨༟Λ࣋ͬͯਃ੥͓ͯ͜͠͏ • ϦδΣΫτ͸ඞͣ͞ΕΔ৺࣋ͪͰϦϦʔεͷ εέδϡʔϦϯά͸͓ͯ͘͠ • ΈͯͶͰ͸Ծਃ੥ΛϦϦʔε༧ఆΑΓ
 2, 3िؒલʹ͸࣮ࢪ͍ͯͨ͠

  137. ·ͱΊ 8.

  138. ·ͱΊ • ෳࡶͳཁ͕݅͋ΔΘ͚Ͱ΋ͳ͍ͷʹʮAuto-Renewable SubscriptionsʯͰ͋Δͱ͍͏͚ͩͰ࣮૷͢Δ͜ͱ͸݁ߏଟ͍ • αʔόʔؒ௨஌ʹ৽͍͠௨஌λΠϓ͕௥Ճ͞Εɺ࣮૷͸optional ͱݴΘΕ͍ͯΔ͕ɺ΄΅mustʹͳΓͭͭ͋Δ (ओ؍) • Grace

    Period͸ղ໿཰վળͱͦͷظؒใुΛ΋Β͑ΔͷͰɺ࣮ ૷͠ͳ͍ख͸ͳ͍ • ϦδΣΫτ͸ඞͣ͞ΕΔ΋ͷͱࢥͬͯϦϦʔεϓϥϯχϯά͢Δ
  139. Thank you!!!