Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

ࣗݾ঺հ • גࣜձࣾϛΫγΟ • Ո଒ΞϧόϜΈͯͶ / ΞϓϦ։ൃάϧʔϓ
 iOS(Swift, obj-c) > Android(Kotlin, Java) == Rails(ruby) • VTuber͕޷͖ • WWDC 2019 ࢀՃ͠·ͨ͠ ✈ ϩΫωϜ@rockname

Slide 3

Slide 3 text

ࠓ೔࿩͢͜ͱ 1. Auto-Renewable Subscriptionsͱ͸ʁ 2. ΈͯͶʹ͓͚ΔಋೖͷܦҢ 3. جຊతͳ࣮૷ํ๏ 4. αʔόʔؒ௨஌ʹ͍ͭͯ 5. Status Pollingʹ͍ͭͯ 6. Sandbox؀ڥʹ͓͚Δಈ࡞֬ೝ 7. ϦδΣΫτʹ͍ͭͯؾΛ͚͍ͭͨϙΠϯτ 8. ·ͱΊ

Slide 4

Slide 4 text

ࠓ೔࿩͞ͳ͍͜ͱ • Subscription Offers • Promoted In-App Purchases • Sales and TrendsͷϝτϦΫεͷݟํ

Slide 5

Slide 5 text

Auto-Renewable Subscriptionsͱ͸ʁ 1.

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

ΈͯͶʹ͓͚ΔಋೖͷܦҢ 2.

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

8/15ʹϦϦʔε

Slide 17

Slide 17 text

جຊతͳ࣮૷ํ๏ 3.

Slide 18

Slide 18 text

લ४උ • App಺՝ۚΛ࡞੒ • Reference Name / Product ID • Price / Duration • Subscription Display Name • Subscription GroupΛ࡞੒ • Reference Name • Subscription Group Display Name ʮ"QQ4UPSF$POOFDUϔϧϓʯΑΓ IUUQTIFMQBQQMFDPNBQQTUPSFDPOOFDUEFWGDF App Store Connect্ͰϓϩμΫτΛ࡞੒

Slide 19

Slide 19 text

ߪಡ։࢝·Ͱͷγʔέϯε

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

No content

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

֤εςοϓͷ࣮૷ํ๏ʹ͍ͭͯ

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

Transaction ObserverͷηοτΞοϓ • transactionΛॲཧ͢ΔͨΊʹ͸·ͣObserverΛੜ ੒ͯ͠payment queueʹ௥Ճ͢Δඞཁ͕͋Δ • payment queue͔ΒͷΠϕϯτΛऔΓ͜΅͞ͳ͍ ͨΊʹ΋Observer͸ΞϓϦىಈ௚ޙʹ௥Ճ͢Δ IUUQTEFWFMPQFSBQQMFDPNEPDVNFOUBUJPOTUPSFLJUJO BQQ@QVSDIBTF TFUUJOH@VQ@UIF@USBOTBDUJPO@PCTFSWFS@BOE@QBZNFOU@RVFVF

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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͸γϯάϧτϯͰ࡞Δ

Slide 34

Slide 34 text

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ʹ௥Ճ

Slide 35

Slide 35 text

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͔Β࡟আ

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

// 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() } ϦΫΤετ͸ڧࢀরͰอ࣋͢Δඞཁ͕͋Δ

Slide 41

Slide 41 text

// 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Ληοτͯ͠ϦΫΤετΛ։࢝

Slide 42

Slide 42 text

// 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. } }

Slide 43

Slide 43 text

// 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ʹදࣔ

Slide 44

Slide 44 text

// 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ʹඈ͹͍ͯ͠Δ

Slide 45

Slide 45 text

No content

Slide 46

Slide 46 text

UIʹϓϩμΫτ৘ใΛදࣔ • Human Interface GuidelineΛ ख़ಡͯ͠ద੾ͳ৘ใΛදࣔ͢Δ • ৘ใ͕࿙Ε͍ͯͨΒଈϦδΣΫ τͳͷͰཁ஫ҙ (ৄ͘͠͸ޙ΄ Ͳ࿩͠·͢) IUUQTEFWFMPQFSBQQMFDPNEFTJHOIVNBOJOUFSGBDFHVJEFMJOFT TVCTDSJQUJPOTPWFSWJFX

Slide 47

Slide 47 text

No content

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

App Store΁ߪೖΛϦΫΤετ • Ϣʔβʔͷબ୒ͨ͠ϓϩμΫτ͔Βࢧ෷͍Ϧ ΫΤετΛ࡞੒ • ࢧ෷͍ϦΫΤετΛpayment queueʹ௥Ճ let payment = SKPayment(product: selectedProduct) SKPaymentQueue.default().add(payment)

Slide 50

Slide 50 text

No content

Slide 51

Slide 51 text

TransactionΛॲཧ͢Δ • SKPaymentTransactionObserver#paymentQueue(_:updatedTransactio ns:) ʹtransaction͕ྲྀΕͯ͘Δ • transactionͷ SKPaymentTransactionState ʹԠͯ͡ద੾ʹॲཧ • transaction͸ finishTransaction() ͠ͳ͍͔͗Γqueueʹ࢒Γଓ͚Δ • ߪೖ్தʹΞϓϦΛऴྃͤͯ͞͠·ͬͨϢʔβʔ͸࣍ճىಈ࣌ʹ෮ ؼͰ͖Δ • updatedTransactions Λ͍ͭͰ΋ॲཧͯ݁͠ՌΛϢʔβʔʹ൓өͤ͞ Δ͜ͱ͕Ͱ͖Δঢ়ଶΛߏங͢Δඞཁ͕͋Δ

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

No content

Slide 60

Slide 60 text

ϨγʔτͷόϦσʔγϣϯ (Appଆ) • ߪೖ͕׬ྃ͢ΔͱϨγʔτ͕ൃߦ͞ΕΔ • Auto-Renewable Subscriptionͷ৔߹ɺ̍ͭͷϨγʔ τʹߪೖ৘ใ͕௥ه͞Ε͍ͯ͘ • Bundle.main.appStoreReceiptURL ʹϨγʔτͷσʔλ ͕ଘࡏ͢ΔͷͰऔಘ • base64Encodingͨ͠ϨγʔτͷDataΛαʔόʔʹPOST

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

// 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) } } Ϩγʔτ͕ଘࡏ͍ͯ͠Ε͹औಘ

Slide 63

Slide 63 text

// 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

Slide 64

Slide 64 text

ϨγʔτͷόϦσʔγϣϯ(Serverଆ) • Appleͷఏڙ͢ΔAPIͷ /verifyReceipt ʹରͯ͠ઌͷ receipt-data ͱ password , exclude-old-transactionsΩʔΛ JSONͰPOST password͸ͪ͜Β͔Βऔಘ

Slide 65

Slide 65 text

/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͢Δͱྑ͍ɻ

Slide 66

Slide 66 text

No content

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

൪֎ฤ: ΤϥʔϋϯυϦϯά • ൃੜ͠͏ΔΤϥʔͷछྨ 1. transactionState ͕ .failed ͷঢ়ଶ 2. transactionState ͸ .purchased ͕ͩϨ γʔτͷόϦσʔγϣϯʹࣦഊ

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

2. transactionState͸ .purchased ͕ͩϨγʔ τͷόϦσʔγϣϯʹࣦഊ • ΈͯͶͷ৔߹2ύλʔϯͷΤϥʔΛϋϯυϦϯά 1. αʔόʔଆͰͷ༧ଌෆೳͳΤϥʔ 2. ड͚औͬͨϨγʔτ͕͢ͰʹϢʔβʔ(Ո଒)ͱ
 ඥ͍͍ͮͯΔ৔߹ͷΤϥʔ • restoreʹΑͬͯαϒεΫϦϓγϣϯΛ෮ݩ͢Δࡍ ʹൃੜ͠͏Δ (restoreʹ͍ͭͯ͸ޙ΄Ͳ࿩͠·͢)

Slide 73

Slide 73 text

• ӈͷΑ͏ͳAlertΛදࣔ͠ɺ͓໰ ͍߹Θͤ΁༠ಋͰ͖ΔΑ͏ʹ͠ ͍ͯΔ • ϝʔϥʔͷbodyʹ͸֘౰ͷ transactionIdentifierΛ෇༩ͯ͠ ϢʔβʔΛdb͔ΒḷΕΔΑ͏ʹ ͍ͯ͠Δ

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

αʔόʔؒ௨஌ͱ͸ʁ • App Store͔ΒϦΞϧλΠϜʹsubscriptionͷঢ়ଶมԽͷ௨஌ ΛHTTP POSTͰड͚औΔ࢓૊Έ (statusUpdateNotifications ͱݺ͹Εͯͨ) • Ϩεϙϯεʹ200Λฦ͞ͳ͍ݶΓ3ճ·ͰϦτϥΠͯ͘͠ΕΔ • ࣮૷͸optional͕ͩϨγʔτͷঢ়ଶΛ࠷৽ʹอͬͨΓϢʔ βʔʹରͯ͠offerΛग़ͤΔΑ͏ʹ͢ΔͨΊʹ΋΍͓͍ͬͯͨ ํ͕͍͍

Slide 76

Slide 76 text

AppStoreConnectͰURLΛઃఆ • ͪ͜ΒͰ༻ҙ͓͍ͯͨ͠POSTΛड͚औΔURLΛ AppStoreConnectͰೖྗ IUUQTIFMQBQQMFDPNBQQTUPSFDPOOFDUEFWBC

Slide 77

Slide 77 text

αʔόʔؒ௨஌Λड͚औΔ • 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: ࣗಈߋ৽ͷঢ়ଶΛߋ৽ͨ͠೔࣌

Slide 78

Slide 78 text

αʔόʔؒ௨஌Λड͚औΔ • 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ʹ౤͛Δϑϩʔʹ৐ͤΔ
 Α͏ʹ࣮૷

Slide 79

Slide 79 text

ͦΕͧΕͷ௨஌λΠϓͷछྨ */*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Λݟ͍ͯͭมߋ͕͋ͬ ͨͷ͔ɺݱࡏͷࣗಈߋ৽ͷঢ়ଶΛ֬ೝ͢Δɻ

Slide 80

Slide 80 text

ࠓळ͔Β௥Ճ͞ΕΔ৽͍͠௨஌λΠϓ • WWDC19 ʮIn-App Purchases and Using Server-to-Server Notificationsʯʹͯൃද • ҎԼͷ3͕ͭ৽͘͠ՃΘΔ • DID_FAIL_TO_RENEW • DID_RECOVER • PRICE_INCREASE_CONSENT • DID_RECOVER͸طଘͷRENEWAL௨஌λΠϓͱஔ͖׵ΘΔ New

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

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

Slide 83

Slide 83 text

INITIAL_BUY "QQ4UPSF 1VSDIBTF 4FSWFS

Slide 84

Slide 84 text

INITIAL_BUY "QQ4UPSF 1VSDIBTF 4FSWFS

Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

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

Slide 88

Slide 88 text

INITIAL_BUY "QQ4UPSF 1VSDIBTF 4FSWFS CBTFFODPEFE SFDFJQU */*5*"-@#6: WFSJGZ@SFDFJQU INITIAL_BUYͷ৘ใͱϢʔβʔͷ৘ใΛoriginal_transaction_identifier, web_order_line_item_idΛΩʔͱͯͭ͠ͳ͗߹ΘͤΔ ݱঢ়ΈͯͶͰ͸ड͚औͬͨINITIAL_BUYΛ อଘ͓͍ͯͯ͠ޙ͔Βಥ͖߹ΘͤΔͱ͍͏ ͜ͱ͸͍ͯ͠·ͤΜ

Slide 89

Slide 89 text

CANCEL (Upgrade) "QQ4UPSF 6QHSBEF 4FSWFS

Slide 90

Slide 90 text

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

Slide 91

Slide 91 text

CANCEL (Cancel Subscription) "QQ4UPSF $BODFM4VCTDSJQUJPO 4FSWFS

Slide 92

Slide 92 text

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

Slide 93

Slide 93 text

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

Slide 94

Slide 94 text

INTERACTIVE_RENEWAL "QQ4UPSF 6QHSBEF 4FSWFS

Slide 95

Slide 95 text

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

Slide 96

Slide 96 text

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

Slide 97

Slide 97 text

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

Slide 98

Slide 98 text

DID_CHANGE_RENEWAL_STATUS "QQ4UPSF 4XJUDIBVUPSFOFXJOH 4FSWFS

Slide 99

Slide 99 text

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

Slide 100

Slide 100 text

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

Slide 101

Slide 101 text

DID_FAIL_TO_RENEW "QQ4UPSF #JMMJOH&SSPS 4FSWFS

Slide 102

Slide 102 text

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

Slide 103

Slide 103 text

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

Slide 104

Slide 104 text

DID_RECOVER "QQ4UPSF #JMMJOH3FUSZ 4FSWFS

Slide 105

Slide 105 text

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

Slide 106

Slide 106 text

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

Slide 107

Slide 107 text

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

Slide 108

Slide 108 text

ࠓळ͔Β৽͘͠௥Ճ͞ΕΔ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

Slide 109

Slide 109 text

Grace Periodͷ࣮૷ํ๏ • WWDCͷηογϣϯͰड़΂ΒΕ͍ͯͨͷ͸ҎԼͷ3Step ͚ͩͰ͋Δ 1. App Store ConnectͰGrace PeriodΛߏ੒ 2. /verifyReceipt ͷ৽͍͠ϑΟʔϧυ grace_period_expires_date ΛϋϯυϦϯά 3. Graceظؒ·ͰαʔϏεΛఏڙ͠ଓ͚ΔΑ͏ʹ࣮૷

Slide 110

Slide 110 text

Status Pollingʹ͍ͭͯ 5.

Slide 111

Slide 111 text

Status Pollingͱ͸ʁ • ظݶ੾ΕલޙͷϨγʔτΛ /verifyReceipt ʹରͯ͠tokenͷΑ͏ʹ౤͛Δ͜ ͱͰ࠷৽ϨγʔτΛऔಘͯ͠dbͷঢ়ଶΛߋ৽͢Δ͜ͱΛࢦ͢ • Ϩγʔτ͸ΞϓϦͷىಈ(͋Δ͍͸αʔόʔؒ௨஌)ʹΑͬͯͷΈߋ৽͞ΕΔ ͷͰɺ΋͠WebͰར༻Ͱ͖ΔαʔϏεΛఏڙ͍ͯ͠Δ৔߹ɺStatus Polling Ͱ࠷৽ͷঢ়ଶΛҡ࣋͢Δඞཁ͕͋Δ • ΈͯͶϓϨϛΞϜͰ͸Web্ͷػೳΛఏڙ͍ͯͨͨ͠Ί
 ࣮૷͓ͯ͘͠ඞཁ͕͋ͬͨ • ͪͳΈʹ͜ͷख๏͸WWDC18 ʮEngineering SubscriptionsʯʹΑͬͯޠΒ ΕΔͷΈͰυΩϡϝϯτԽ͞Ε͍ͯͳ͍

Slide 112

Slide 112 text

͍ͭStatus PollingΛ࣮ߦ͢΂͖͔ • WWDC2018 ʮEngineering SubscriptionsʯͰ͸ҎԼͷΑ͏ʹظݶ͕੾ΕΔલޙͷλ ΠϛϯάͰ͢ΔΑ͏ʹݴΘΕ͍ͯΔ • ΈͯͶͰ͸Grace Periodத͓ΑͼGrace Period͕ऴྃͯ͠1೔ޙͷϢʔβʔʹରͯ͠ຖ ே࣮ߦ͍ͯ͠Δ IUUQTEFWFMPQFSBQQMFDPNWJEFPTQMBZXXED

Slide 113

Slide 113 text

Sandbox؀ڥʹ͓͚Δ
 ಈ࡞֬ೝ 6.

Slide 114

Slide 114 text

Sandbox؀ڥ • App Store ConnectͰςελʔΞΧ΢ϯτΛ࡞੒͢ Δ͜ͱͰςετ؀ڥͰಈ࡞֬ೝ͕Ͱ͖Δ • ʮUsers and Accessʯͷϖʔδ͔Β؆୯ʹ࡞੒Մೳ • ֤SandboxϢʔβʔʹରͯ͠طଘͷApple IDʹඥͮ ͚ΒΕ͍ͯͳ͍ϝʔϧΞυϨεΛઃఆ • νʔϜͰڞ༗͓ͯ͘͠ͱΑ͍

Slide 115

Slide 115 text

SandboxͰൃߦ͞ΕΔϨγʔτ • SandboxͰൃߦ͞ΕΔϨγʔτ͸ҎԼͷରԠ දͷΑ͏ʹొ࿥ظ͕ؒ୹ॖ͞ΕΔ IUUQTIFMQBQQMFDPNBQQTUPSFDPOOFDUEFWFFE

Slide 116

Slide 116 text

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

Slide 117

Slide 117 text

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 ʹ౤͛௚͢ඞཁ͕͋Δ

Slide 118

Slide 118 text

ެ։લʹຊ൪؀ڥͷϨγʔτΛऔಘ͍ͨ͠ • TestflightͰ഑৴ͯ͠΋Ϩγʔτ͸SandboxͰ ൃߦ͞Εͨ΋ͷʹͳΔ • લड़ͷ௨ΓɺAppleͷ৹ࠪ΋SandboxͰൃߦ ͞ΕͨϨγʔτΛ࢖༻ • ͭ·ΓɺϦϦʔε͢Δ·Ͱຊ൪ͷϨγʔτΛ ॲཧͰ͖ͳ͍

Slide 119

Slide 119 text

Promotion CodeΛ࢖ͬͯຊ൪֬ೝ • ਃ੥ͷ௨ͬͨΞϓϦͳͲΛެ։લͰ΋഑෍͢Δ͜ͱ͕Ͱ ͖Δͷ͕Promotion Code • ʮજࡏސ٬΍ϨϏϡʔهࣄ࡞੒ऀ΁ͷ഑෍ͳͲϓϩϞʔ γϣϯͷͨΊͷ࢖༻ʯ͕૝ఆ͞Ε͍ͯΔ • ͕ɺ͜ΕͳΒຊ൪؀ڥͷϨγʔτ͕खʹೖΔʂ • ΈͯͶͰ͸͜ΕʹΑΓαʔόʔଆͷͪΐͬͱͨ͠όάΛ ϦϦʔεલʹચ͍ग़ͨ͠

Slide 120

Slide 120 text

ϦδΣΫτʹ͍ͭͯ
 ؾΛ͚͍ͭͨϙΠϯτ 7.

Slide 121

Slide 121 text

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

Slide 122

Slide 122 text

1. Restore Completed Transactions • finishTransaction() ʹΑͬͯ׬ྃͤͯ͞͠·ͬ ͨtransactionΛ෮ݩ͢Δํ๏ SKPaymentQueue.default().restoreCompletedTransactions() • restore͕׬ྃͨ͠ΒϨγʔτΛόϦσʔγϣ ϯʹ௨্ͨ͠ͰfinishTransaction() ͯ͋͛͠Δ

Slide 123

Slide 123 text

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

Slide 124

Slide 124 text

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Λ࣮૷͍ͯ͠Δ

Slide 125

Slide 125 text

ߪೖγʔϯʹදࣔ͢΂͖৘ใΛ࿙Εͳ͘ ྻڍ͢Δ

Slide 126

Slide 126 text

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

Slide 127

Slide 127 text

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

Slide 128

Slide 128 text

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

Slide 129

Slide 129 text

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

Slide 130

Slide 130 text

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

Slide 131

Slide 131 text

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

Slide 132

Slide 132 text

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

Slide 133

Slide 133 text

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

Slide 134

Slide 134 text

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

Slide 135

Slide 135 text

࠷ऴతͳΈͯͶͷߪೖϖʔδ

Slide 136

Slide 136 text

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

Slide 137

Slide 137 text

·ͱΊ 8.

Slide 138

Slide 138 text

·ͱΊ • ෳࡶͳཁ͕݅͋ΔΘ͚Ͱ΋ͳ͍ͷʹʮAuto-Renewable SubscriptionsʯͰ͋Δͱ͍͏͚ͩͰ࣮૷͢Δ͜ͱ͸݁ߏଟ͍ • αʔόʔؒ௨஌ʹ৽͍͠௨஌λΠϓ͕௥Ճ͞Εɺ࣮૷͸optional ͱݴΘΕ͍ͯΔ͕ɺ΄΅mustʹͳΓͭͭ͋Δ (ओ؍) • Grace Period͸ղ໿཰վળͱͦͷظؒใुΛ΋Β͑ΔͷͰɺ࣮ ૷͠ͳ͍ख͸ͳ͍ • ϦδΣΫτ͸ඞͣ͞ΕΔ΋ͷͱࢥͬͯϦϦʔεϓϥϯχϯά͢Δ

Slide 139

Slide 139 text

Thank you!!!