レシートの確認に RMStore を使用しています。なお、実際の購入部分にはRMStoreを使用していません。このプロセスは、レシートが無効な場合にエラーをスローし、コンテンツを配信しないという点で、成功と失敗をうまく処理しています。テストとして強制的に失敗するようにバンドルを意図的に変更しました。ただし、私の質問は失敗のプロセスと Apple が送信する確認に関するものです。
問題は、このプロセスが検証の失敗を検出するため、コンテンツがユーザーに送信されないことですが、Apple はその後、購入が成功したことを示すダイアログ ボックスを返します。良いニュースは、購入が成功せず、コンテンツが配信されていないことですが、混乱を招くため、Apple からのこのダイアログ ボックスが表示されないようにしたいと考えています。
これが私のチェックの実装です。今のところ、失敗ブロック内でさらに多くのことを行う前に、失敗シナリオをテストしているだけです。
- (void)completeTransaction:(SKPaymentTransaction *)transaction {
NSLog(@"completeTransaction...");
RMStoreAppReceiptVerificator *verifyReceipt = [[RMStoreAppReceiptVerificator alloc]init];
[verifyReceipt verifyTransaction:transaction success:^{
[self provideContentForProductIdentifier:transaction.payment.productIdentifier];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}failure:^(NSError *error){
NSLog(@"failure to verify: %@",error.description);
}];
}
Apple で成功ダイアログを作成するプロセスを停止する失敗ブロック内の方法はありますか?それとも、このチェックを早い段階で実行する必要がありますか?
アップデート:
これをさらに見てみると、上記のメソッドは状態によって呼び出されていますSKPaymentTransactionStatePurchased
。Apple ごとのその状態の定義は次のとおりです。
「App Store は支払いを正常に処理しました。アプリケーションは、ユーザーが購入したコンテンツを提供する必要があります。」
これは、対話を防ぐには遅すぎる可能性が高いことを示しています。以前の状態もありますが、受領確認は購入後、コンテンツの配信前に来る必要があると思います(そうしないと、確認する購入がありません)。これは、競合するメッセージに対処しなければならないだけの問題ですか、それとも何か不足していますか?
更新 2: コメントのリクエストごとにいくつかのメソッドを追加する
@interface IAPHelper () <SKProductsRequestDelegate, SKPaymentTransactionObserver>
@end
@implementation IAPHelper
{
SKProductsRequest * _productsRequest;
RequestProductsCompletionHandler _completionHandler;
NSSet * _productIdentifiers;
NSMutableSet * _purchasedProductIdentifiers;
NSDictionary *_mappingDict;
}
- (id)initWithProductIdentifiers:(NSSet *)productIdentifiers andMappings:(NSDictionary *)mappingDict
{
if ((self = [super init])) {
// Store product identifiers & mappings
_productIdentifiers = productIdentifiers;
_mappingDict = mappingDict;
// Add self as transaction observer
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}
return self;
}
- (void)requestProductsWithCompletionHandler:(RequestProductsCompletionHandler)completionHandler {
// 1
_completionHandler = [completionHandler copy];
// 2
_productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:_productIdentifiers];
_productsRequest.delegate = self;
[_productsRequest start];
}
- (BOOL)productPurchased:(NSString *)productIdentifier {
return [_purchasedProductIdentifiers containsObject:productIdentifier];
}
- (void)buyProduct:(SKProduct *)product {
NSLog(@"Buying %@...", product.productIdentifier);
SKPayment * payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
#pragma mark - SKProductsRequestDelegate
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
NSLog(@"Loaded list of products...");
_productsRequest = nil;
NSArray * skProducts = response.products;
for (SKProduct * skProduct in skProducts) {
NSLog(@"Found product: %@ %@ %0.2f",
skProduct.productIdentifier,
skProduct.localizedTitle,
skProduct.price.floatValue);
}
if (_completionHandler)
{
_completionHandler(YES, skProducts);
_completionHandler = nil;
}
}
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {
NSLog(@"Failed to load list of products.");
_productsRequest = nil;
if (_completionHandler)
{
_completionHandler(NO, nil);
_completionHandler = nil;
}
}
これが呼び出す特定のメソッドですcompleteTransaction
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction * transaction in transactions) {
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchased:
[self completeTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
[self failedTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
[self restoreTransaction:transaction];
default:
break;
}
};
}