iOS 用アプリにて 決済機能を追加する際に、かなりハマりポイントがありましたので、注意する点について述べたいと思います。
前提条件
・Windows10
・Visual Studio 2015 Community Update3
・Xamarin 4.2.0.703 (NuGet Xamarin.Forms 2.3.2.127)
・macOS Sierra 10.12 / Xcode8 / Xamarin.iOS 10.0.1.8
・iTunes Connect にて テスターの設定が完了していること
1.デバッグはシミュレータではなく、実機で行う
シミュレータで購入履歴を復元しようとすると、Sandbox テストの場合、エラーになってしまいます。
SKPaymentTransactionObserverを継承したクラスにて、以下のメソッドが発生します。エラーの内容は 「Cannot connect to iTunes Store. 」 iTunes Storeに接続ができないといわれてしまいます。
その場合、以下のメソッドにてエラー内容が渡っています。
public override void RestoreCompletedTransactionsFailedWithError(SKPaymentQueue queue, NSError error)
また、テストアカウントではない正規のAppleIDを実機に埋め込んでいる場合は「code 0 : iTunes Store に接続できません」というエラーが返ってきますのでご注意ください。
2.プログラムの発生順序について
購入履歴を正常に復元した場合
public void RestoreProducts()
{
SKPaymentQueue.DefaultQueue.RestoreCompletedTransactions();
}
↓非同期
public override void SKPaymentTransactionObserver.UpdatedTransactions(SKPaymentQueue queue, SKPaymentTransaction[] transactions)
↓
public void RestoreTransaction(SKPaymentTransaction transaction)
{
SKPaymentQueue.DefaultQueue.FinishTransaction(transaction);
}
↓登録イベント発生
this._restoreProductsObserver = NSNotificationCenter.DefaultCenter.AddObserver(InAppService.InAppRestoreProductsNotification,
(notification) =>
{
// Notify anyone who needed to know that products were restored
if (this.OnRestoreProducts != null)
{
this.OnRestoreProducts();
}
});
※上記だと購入履歴が無い場合に呼び出されませんので、
SKPaymentTransactionObserver.RestoreCompletedTransactionsFinished(SKPaymentQueue queue)
からOnRestoreCompleted等のイベントを発生させたほうが良いでしょう。
購入手続きが正常に行われた場合
public void PurchaseProduct(string productId)
{
var payment = SKPayment.PaymentWithProduct(productId);
SKPaymentQueue.DefaultQueue.AddPayment(payment);
}
↓非同期
public override void SKPaymentTransactionObserver.UpdatedTransactions(SKPaymentQueue queue, SKPaymentTransaction[] transactions)
↓
public void PurchaseTransaction(SKPaymentTransaction transaction)
{
SKPaymentQueue.DefaultQueue.FinishTransaction(transaction);
}
↓登録イベント発生
this._purchaseProductObserver = NSNotificationCenter.DefaultCenter.AddObserver(InAppService.InAppPurchaseProductNotification,
(notification) =>
{
// Notify anyone who needed to know that product was purchased
if (this.OnPurchaseProduct != null)
{
this.OnPurchaseProduct();
}
});
購入履歴を復元できなかった場合(エラーの場合)
public void RestoreProducts()
{
SKPaymentQueue.DefaultQueue.RestoreCompletedTransactions();
}
↓非同期
public override void RestoreCompletedTransactionsFailedWithError(SKPaymentQueue queue, NSError error)
3.SKPaymentTransactionState について
<State>
Purchasing:購入処理中
Purchased:購入処理完了
Failed :失敗
Restored :購入履歴を取得完了
Deferred : ペアレンタルコントロールで保留中
public override void UpdatedTransactions(SKPaymentQueue queue, SKPaymentTransaction[] transactions)
{
foreach (SKPaymentTransaction transaction in transactions)
{
switch (transaction.TransactionState)
{
case SKPaymentTransactionState.Purchasing:
break;
case SKPaymentTransactionState.Purchased:
this._inAppService.PurchaseTransaction(transaction);
break;
case SKPaymentTransactionState.Failed:
this._inAppService.FailedTransaction(transaction);
break;
case SKPaymentTransactionState.Restored:
this._inAppService.RestoreTransaction(transaction);
break;
default:
break;
}
}
}
Deferred が iOS8 から追加になっていますが、default: に落ちるのであれば現状は問題ないでしょう。
4.Subscriptions の有効期間について
SandBoxにてテストを実施する際、Subscriptions の有効期間が実際とは異なります。
有効期間は以下の通りです。
本番環境 |
SandBox |
1週間 |
3分 |
1ヵ月 |
5分 |
2ヵ月 |
10分 |
3ヵ月 |
15分 |
6ヵ月 |
30分 |
1年 |
1時間 |
AppStoreに配布されてからはiPhoneの設定から購読の停止ができますが、Sandboxでは停止することができません。自動更新はされませんので年間購読であれば1時間待つしかありません。
その後有効期間を迎えても、UpdatedTransactionsによって購読が継続の処理(自動更新)が行われます。それが6回発生しますので、結局6時間待つことになっています。おそらく本番と同じ仕様なのでしょう。
だったら停止(キャンセル)処理ができるようにしておいて欲しいですね。。。
5.Apple の無駄な仕様について
これはAppleの審査チーム(iTune Store Review Team)から言われたことですが、必ず復元ボタンを用意しなければいけないということです。
端末初期化や機種変更時などの対策として、購入履歴のデータをアプリ内に復元する方法は必要ですが、iOSの場合はボタンとして存在しないと Review にて Reject されます。いちいちボタンを押させるという無駄な行為で、手間ですが、そういう規則だそうです。私は自動で復元する機能を搭載したアプリを審査に出しましたが、Rejectされ、電話で議論しましたが、一歩も応じませんでした。
6.In-App Purchase Shared Secret (App内課金共有シークレット) の取得方法
iTunes Connect の マイApp のページにて取得します。
詳しくは以下のページにて取得場所をご紹介しています。
In-App Purchase Shared Secret (App内課金共有シークレット) の取得方法について | iTunes Connect
7.レシート取得時のステータスについて
以下のURLに記載ありますが、
https://developer.apple.com/jp/documentation/ValidateAppStoreReceipt.pdf
status |
説明 |
0 |
正常に接続できています。 |
21000 |
App Storeは、提供したJSONオブジェクトを読むことができません。 |
21002 |
receipt-dataプロパティのデータが不正であるか、または欠落しています。 |
21003 |
レシートを認証できません。 |
21004 |
この共有秘密鍵は、アカウントのファイルに保存された共有秘密鍵と一致し
ません。自動更新型の購読に用いる、iOS 6型のトランザクションレシートの場合の
み。
|
21005 |
レシートサーバは現在利用できません。 |
21006 |
このレシートは有効ですが、定期購読の期限が切れています。ステータス
コードがサーバに返される際、レシートデータもデコードされ、応答の一部
として返されます。自動更新型の購読に用いる、iOS 6型のトランザクションレシートの場合のみ。 |
21007 |
テスト環境のレシートを、実稼働環境に送信して検証しようとしました。こ
れはテスト環境に送信してください。 |
21008 |
実稼働環境のレシートを、テスト環境に送信して検証しようとしました。こ
れは実稼働環境に送信してください。 |
status ==21007 の場合、SandBoxに送信するようにプログラムすることが iTunes Connect の審査上、必須となっています。
レシートに関するコーディングについては以下のURLにてご説明しております。
Xamarin.iOS でレシートを取得するサンプルコード | Xamarin.forms
当ブログの内容をまとめた Xamarin逆引きメニュー は以下のURLからご覧になれます。
https://itblog.dynaspo.com/blog-entry-81.html
- 関連記事
-