LoginSignup
30
33

More than 5 years have passed since last update.

StoreKit の覚書

Last updated at Posted at 2015-11-13

iOS における StoreKit が意味わからなさすぎるのでひとまず覚書
なにに使えるかは知らない

後から内容を180度修正する可能性もある
それくらいわけがわからない
情報も少ない・・・つらい

※ちなみに自分は消耗型の課金のみ扱ってるので、他の場合は知らない

SKErrorUnknown と SKErrorPaymentCancelled は同じようなもん

主に課金周りの処理で、キャンセルボタンを押したら SKErrorPaymentCancelled
ホームボタンを押しちゃったりしたら SKErrorUnknown が返ってくる
という認識だったが、
これらは iOSのバージョン毎にしっちゃかめっちゃかである
ということがわかった

iOS7,iOS8,iOS9 で検証したが、例えば A の操作を行ったとして

  • iOS7 では SKErrorPaymentCancelled が返ったかと思ったら
  • iOS8 では SKErrorUnknown が返り
  • iOS9 では A の操作そのものができない

色んな状況での返りをテキストにしたためたが、
結局 SKErrorUnknown と SKErrorPaymentCancelled が返ったら
課金処理エラーです とか、どっちも同じアラートだせばいいじゃん? って結論になった(現時点)

[購入する]を選んだ後の通信エラーの判断

SKErrorUnknown と SKErrorPaymentCancelled は同じやん?
って言っておきながら、同じじゃない特例もあった

購入するを選んだ後に、すぐさま機内モードにしたりしてネットを切断すると
-paymentQueue:updatedTransactions: にて、SKPaymentTransactionStateFailed がすぐ返ってくる
この時のtransaction.errorの中身がまた iOS 毎に違う

  • iOS7 では transaction.error.codeSKErrorUnknown
  • iOS8, iOS9 ではそもそも transaction.errornull

ちなみに、ネットの接続状態を確認できる Reachability を使用しても、
この時点で通信状態の変化は読み取れない
仕方ないね

※ 2015/12/02 追記
NSURLConnection でどっかのURLに同期接続して、404でもなんでもとにかくネット接続できてるかどうかで判断する方法をとりました
どっかのURLといってグーグル先生とかを選ぶと普通にやばいので自鯖のURLで
NSData にも同期通信するメソッドはあったけど、こっちはステータスコードがとれないのでNG
他に良い方法あると思うんだけど、考える頭がないので応急処置(´・ω・`)

トランザクションをフィニッシュして、エラーを確認して処理を変えてる場合
iOS8 と iOS9 ではエラーそのものが確認できないので
失敗してんのに成功したと思われんじゃない? なんかやばいんじゃない? っていうお話

※ 2015/12/02 ↓に通信エラー時のことについて追記

購入中に通信エラー起こしたら、すぐ復元処理を行ったほうがいい

※現状 iOS8 のみでテスト中

上の章の続き
ここでいう復元処理ってのは -restoreCompletedTransactions を呼び出す
という意味

復元処理は消耗型アイテムには関係ないで〜 ってどっかに書いてあった気がしますが
「[購入する]ボタン選択直後に通信エラーを起こした場合」という状況においてはリストアは必要だ」
と思いました

という内容を↓にずらずら記載
書いてるうちにどんどん長くなったので推敲してないけど
めんどくさいんで一旦うpしましょう(´・ω・`)




購入中通信エラーを起こした時のトランザクションの状態は前章に書いた通りです

そのトランザクションを -finishTransaction: すれば、[SKPaymentQueue defaultQueue].transactions の中身はゼロになる
この辺までは通常の失敗処理と同じ
なんだけど・・・

その後、ネット接続有効にした状態で「ホームボタン1回押下でホーム->アプリに戻る」
手順を踏むと、[iTunes Storeにサインイン]ダイアログが表示されちゃう
(このダイアログのタイトル長いし、正式名称がわからんので、以後とりあえず認証ダイアログとよびます
サインインダイアログだと他とかぶる(´・ω・`))

認証ダイアログが開く条件は

  1. リクエストを投げる(SKProductsRequest、SKReceiptRefreshRequestとか)
  2. リストア(-restoreCompletedTransaction)した時(確か出た)
  3. フィニッシュしてないトランザクションが端末に残ってる時に、特定手順を踏む(通信切断状態ならなにも起きない)
    • [SKPaymentQueue defaultQueue] を初めて呼んだ時
    • [SKPaymentQueue defaultQueue] を呼んだ後・・・
      • ホームに行ってからアプリに戻ってくる
      • 通信状態の切り替え(機内モードをOFFにしてからONに戻した時とか)
      • なんか時間経過すると?

とりあえずこういう感じ
この認証ダイアログってのはレシートの同期が必要な時によばれてんのかなーと
でもこのダイアログって、それぞれ同じ認証してるわけじゃないっぽいし、レシート更新リクエストで認証しても、商品投げる時にまた認証求められるし、でも別の認証ダイアログだと商品購入の認証しなくて済んだり・・・
と、深く調べようとするとなんだこれ状態になるんだけど
(自分もそのあたりはまとめるの諦めた)
とにかく3番目の条件だけは、未処理のトランザクションが残ってる限り何度でも出続ける
(´・ω・`)やばくない?




じゃあトランザクションを finish!! すれば出てこなくなるんでしょう
と思ったんだけど、最初の方に言った通り
「購入中通信エラーした時の [SKPaymentQueue defaultQueue].transactions の中身はゼロ」なんだよね・・・
トランザクションの量を確認できる唯一のプロパティの中身を見ても、トランザクションが残ってるかどうかわかんないんだよね・・・
Key-Value Coding とかで、transactions の変化を逐一チェックしようと思ったけど効果なかったしね・・・
(あと細かいところだと、購入中通信エラー時は通信状態の切り替えを行ってもダイアログが表示されないです
アプリを再起動したら通信状態の切り替えでダイアログでたかなって思う)

(´・ω・`)もうやだ

トランザクションがゼロなのを復元する方法は、

  • リストア処理する
  • 手順を踏んで表示したダイアログで認証する
  • 失敗したリクエストと同じリクエストを投げる

以上
リストアは言わずもがな
認証ダイアログで認証した時は、transactionState が購入完了状態になってて、リストア時とは状態が異なるけど、多分そこが違うだけ
-paymentQueueRestoreCompletedTransactionsFinished: とか専用のメソッドが呼ばれるかどうかの違いくらい
同じリクエストを投げた時は、購入するを選ぶことで[この App 内課金はすでに購入済みです。]ダイアログが表示される

正しく処理が書けていれば、復元処理を強制させなくても、同じリクエストを選ぶだけで購入処理は完了させられる

だけども、
120円商品のリクエストをミスった!
その後なんの処理もしないで今度は480円商品のリクエストを投げて、またミスった!
を繰り返すと、端末に復元待ちのトランザクションがどんどん溜まるわけで
例えば1万円弱の買い物をして、リクエスト失敗して
「それ多分復元待ちなんで、も一回同じ商品を選んでください」ってアラートだしたとして
ユーザーから見たら「え・・・また1万円課金するの? 失敗したらどうすんの・・・?」って思っちゃうと思うわけで
実際失敗したら目もあてられないわけで

名前忘れたけども、どこかのサイトに
「複数の商品を1度に購入しない! トランザクションは1つずつ確実に処理する! 失敗したら成功するまで繰り替えす!」
と書いてありました
これはトランザクションが複数溜まってると予期せぬ動作が発生するから(だったと思うの)で
この予期せぬ動作ってのは、これまで StoreKit いじってきて嫌という程体験したので、
StoreKit をいじる上での真理だと思いました。

(デバッグ中は停止させるタイミングによっては、普通にトランザクションが複数流れたりもして
トランザクションが1個しか流れないのを前提に作ってるとめんどくさいことになるけども)




以上のことから、見出しの通り、「購入中に通信エラー起こしたら、すぐ復元処理を行ったほうがいい」という考えに至りました

でも NSUserDefaults に復元フラグとか再処理フラグだかを立てといても、アプリの再インストールとかされるとおじゃんじゃんじゃん
もっかい同じリクエストを投げてもらうとか、復元ボタンを用意するとか
トランザクションのカウントはサーバーで行うとか?
ていうか課金処理ミスっといてそのままアプリ削除されたらもうユーザーが100%悪いよね!

(´・ω・`)もうやだ

30
33
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
30
33