StoreKit 2のAppStore.sync()検証

iPhone などの iOSアプリにおいて、StoreKit 2を用いたリストア(復元)処理の検証に関して、筆者の体験を紹介する。

筆者のマシン
Mac mac mini (M1, 2020)
OS Monterey バージョン 12.4
XCode バージョン 13.4.1
Swift バージョン 5.6.1


ここでは次の手順で説明する。

  1. はじめに
  2. リストア(復元)ボタンの追加
  3. TestFlightでの検証
  4. App Storeで公開・動作確認

はじめに

iOSアプリの App内課金処理を StoreKit 2 で実装してApp Store の審査に提出した際、リストア(復元)のボタンを設置していないと言う理由で、Review での却下(Reject)を受けた。

理由は「Guideline 3.1.1 – Business – Payments – In-App Purchase」で、メッセージを日本語に訳すと、大まかには次のとおり。

お客様のアプリでは、復元可能なアプリ内課金(in-app purchases)を提供していますが、アプリ内課金プログラミングガイドの「購入商品の復元」に明記されているように、ユーザーが以前に購入したアプリ内課金を復元できる「購入商品の復元」機能(”Restore Purchases” feature)が含まれていないことがわかりました。

余談だが、下記をざっと読んだ感じでは、私にはその必要性は認識できなかった。
In-App Purchase Programming Guide“Restoring Purchase Products” section

筆者が審査に提出したアプリは、起動時に最新の購入状況を読み込むものであったが、Rejectメッセージには次のステップが明記されていた。
内容を日本語に訳すと、大まかには次のとおり。

アプリ内課金で購入した商品を復元するには、「復元」(”Restore”)ボタンを用意し、ユーザーが「復元」ボタンをタップすると復元処理が開始されるようにすることが適切です。なお、起動時に自動的に復元されるようにしても、この問題は解決しません。

つまり、起動時に自動的に最新の購入アイテムを復元していても、明示的な”Restore”ボタンなどを設置することが求められた。
確かに、Implementing a store in your app using the StoreKit APIからDLできるサンプルアプリには、購入したアイテムを復元するための明示的なボタン「Restore Puchases」がある。

リストア(復元)ボタンの追加

rejectされたアプリにはアイテム購入画面があるのだが、その画面の下部の方に、「購入情報の復元(リストア)」と言うボタンを設けた。
そして、そのボタンがタップされたときの処理として、上記サンプルアプリのコードおよび AppStore.sync()のAPI を参考にして次の処理を追加した。


AppStore.sync()
// 加えて、この後ろに、最新の購入済みのアイテムを反映した画面を表示する処理を実装

TestFlightでの検証

動作確認のために、TestFlightへアプリをアップロードし、手元の2台の実機で動作の確認を行った。
流れは次のとおり。

  1. 実機AとBで、アイテム購入画面を表示させておく
    • この時、いずれのアイテム購入画面でも、アイテムは未購入の状態である
  2. 実機Aにて、SandBoxテストユーザAでアイテムを購入する
    • 筆者のアプリでは購入後に画面が更新され、購入済みであることが分かるようにしている。この時実機Aでは、期待していたように購入済みの画面となった
  3. 実機B(アイテム購入画面では、未購入の状態が表示されている)で、「購入情報の復元(リストア)」ボタンをタップする
    • 認証ダイアログに従い、SandBoxテストユーザAで認証した
    • 期待する結果は、購入済みのアイテムを反映した画面となることだった。しかし、画面の見た目は変化なし

ここで、APIの説明や先のサンプルアプリのコードを確認したが、実装に不足な点は見当たらなかった。

試しに、AppStore.sync()のエラーをcatchした際のログを画面に表示するようにして、TestFlightへアップして検証した。
上記3の「購入情報の復元(リストア)」ボタンをタップでは下記エラーが出ていることがわかった。

The operation couldn’t be completed.(StoreKit.StoreKitErrr error 2.)
// 日本語では「リクエストを完了できません。」

TestFlight版アプリではSandBoxユーザを用いて検証したが、ネットでは一部挙動が怪しいと言う記事もあったので、本番のApp Storeでは動くと言う前提で、やむを得ず審査に提出をした。

ちなみに、上記3の後、実機Bで購入(復元ではない)を操作すると、認証後に「すでに購入済みです。無料で入手できます」と言う旨のメッセージが出て、購入済みであることが反映された。

App Storeで公開・動作確認

審査が通過したので、App Storeからリリース版をDLし、TestFlight版アプリで検証した上記操作を試した(この時は自分のApple IDで課金アイテムを購入)。

  1. 実機AとBで、アイテム購入画面を表示させておく
    • この時、いずれのアイテム購入画面でも、アイテムは未購入の状態である
  2. 実機Aにて、アイテムを購入する(勿論、自分のApple IDで)
    • この時実機Aでは、期待していたように購入済みの画面となった
  3. 実機Bで、「購入情報の復元(リストア)」ボタンをタップする
    • 認証ダイアログに従い、自分のApple IDで認証した
    • 期待の通り、画面が更新され、購入済みの画面となった

これらより、AppStore.sync()を呼び出すことにより、本番の App Store では適切に復元(リストア)できることが確認できた。

TestFlight検証時がたまたま良くなかったのか、SandBoxテストユーザではリストア検証できない仕様なのかは分からなかったが、
StoreKit2 でのリストア処理はAppStore.sync()で問題なし!と言うことが分かった。

以上

シェアする

  • このエントリーをはてなブックマークに追加

フォローする