短縮版
Apple は、私が を使用していると言って私のアプリを拒否しSKReceiptRefreshRequest
ましたが、私のコード (下記) でそれを見つけることができません。
ロングバージョン
私は現在、アプリ ストアで自分のアプリを承認しようとしていて、いくつかの壁にぶつかっています。現在の主な問題は、私が領収書の検証を正しく実装していないと彼らが言っていることです。その後、開発者テクニカル サポートの担当者に案内されました。その後、彼は削除のプロセスに進みます - 憶測に基づいて、私のコードを見ることができず、アプリのレビュー部門と連絡が取れていないことが原因です.
最初に彼は言及SKReceiptRefreshRequest
し、壮大な統一の領収書. 私は使用していないことを彼に知らせましたSKReceiptRefreshRequest
。プロジェクト全体を検索しました。その後、さらにいくつかの削除を行い、最終的には、DTS 担当者が個人的にテストするためのプロビジョニング プロファイルと共に .IPA を送信することになりました。彼は、問題はないと報告し、アプリのレビュー部門に連絡して拒否の理由を見つけました。最後にいくつかの進歩。
そして彼はこう言って戻ってくる
"ここでの問題は、App Review が SKReceiptRefreshRequest の使用のためにアプリを拒否していることです。App Reviewer は、アプリがこの呼び出しを行う結果となるいくつかの一連の手順を使用しています。レビュアーがアプリ内購入アイテムにアクセスするための [購入] ボタン。
...
したがって、私の唯一の結論は、コードのどこかでこのメソッドのデリゲートを使用しているということです。SKReceiptRefreshRequest
私が困っているので、私がどこにいるのか、またはどこにいる可能性があるのか 教えてもらえますか?
より詳しい情報
コード
(セキュリティのため一部隠してあります)
#import "IAPHelper.h"
#import "SKProduct+LocalizedPrice.h"
#import ***
#import "NSString+NSStringAdditions.h"
#import ***
#import ***
#import ***
#import ***
@implementation IAPHelper
@synthesize productIdentifiers = _productIdentifiers;
@synthesize products = _products;
@synthesize purchasedProducts = _purchasedProducts;
@synthesize request = _request;
@synthesize localProducts = _localProducts;
@synthesize productsCategory = _productsCategory;
- (id)initWithProductIdentifiers:(NSSet *)productIdentifiers
{
if ((self = [super init]))
{
// Store product identifiers
_productIdentifiers = productIdentifiers;
// Check for previously purchased products
NSMutableSet * purchasedProducts = [NSMutableSet set];
_localProducts = [NSMutableArray new];
[_localProducts addObjectsFromArray:***];
[_localProducts addObjectsFromArray:***];
[_localProducts addObjectsFromArray:***];
_productsCategory = [NSMutableDictionary new];
[_productsCategory setObject:[self sortAndTrimProducts:***] forKey:***];
[_productsCategory setObject:[self sortAndTrimProducts:***] forKey:***];
[_productsCategory setObject:[self sortAndTrimProducts:***] forKey:***];
self.purchasedProducts = purchasedProducts;
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}
return self;
}
- (void)getProducts:(NSMutableArray*)array forId:(int)Id
{
for (NSString * productIdentifier in _productIdentifiers)
{
NSArray *stringByComponent = [productIdentifier componentsSeparatedByString:@"*"];
int identifier = [[stringByComponent objectAtIndex:*] integerValue];
BOOL productPurchased = [[NSUserDefaults standardUserDefaults] boolForKey:productIdentifier];
if (productPurchased)
{
[_purchasedProducts addObject:productIdentifier];
DDLogInfo(@"Previously purchased: %@", productIdentifier);
}
else
{
DDLogInfo(@"Not purchased: %@", productIdentifier);
}
if (identifier == Id)
{
[array addObject:productIdentifier];
}
}
}
-(NSMutableArray*)sortAndTrimProducts:(NSMutableArray*)array
{
NSArray *sortedProducts = [self sortProducts:array];
NSMutableArray *returnedArray = [NSMutableArray new];
for (NSString *string in sortedProducts)
{
NSArray *components = [string componentsSeparatedByString:@"*"];
int type = [[components objectAtIndex:*] integerValue];
switch (type)
{
case ***:
{
NSString *productName = [components objectAtIndex:*];
[returnedArray addObject:productName];
}
break;
case ***:
{
NSString *productName = [components objectAtIndex:*];
[returnedArray addObject:productName];
}
break;
case ***:
{
NSString *productName = [components objectAtIndex:*];
[returnedArray addObject:productName];
}
break;
default:
break;
}
}
return returnedArray;
}
- (NSArray*)sortProducts:(NSMutableArray*)array
{
NSArray *sortedArray;
sortedArray = [array sortedArrayUsingComparator:^NSComparisonResult(id a, id b)
{
***
}];
return sortedArray;
}
- (void)requestProducts
{
self.request = [[SKProductsRequest alloc] initWithProductIdentifiers:_productIdentifiers];
_request.delegate = self;
[_request start];
}
- (void)requestProductsWithCompletionHandler:(RequestProductsCompletionHandler)completionHandler
{
// 1
_completionHandler = [completionHandler copy];
// 2
_request = [[SKProductsRequest alloc] initWithProductIdentifiers:_productIdentifiers];
_request.delegate = self;
[_request start];
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
DDLogInfo(@"Received products results...%@",response.products);
self.products = response.products;
self.request = nil;
for( int i = 0; i < [_products count]; ++i )
{
if ( [_products objectAtIndex:i] )
{
DDLogInfo(@"Product title: %@" , [[_products objectAtIndex:i] localizedTitle]);
DDLogInfo(@"Product description: %@" , [[_products objectAtIndex:i] localizedDescription]);
DDLogInfo(@"Product price: %@" , [[_products objectAtIndex:i] localizedPrice]);
DDLogInfo(@"Product id: %@" , [[_products objectAtIndex:i] productIdentifier]);
}
for (NSString *invalidProductId in response.invalidProductIdentifiers)
{
DDLogError(@"Invalid product id: %@" , invalidProductId);
}
}
[[NSNotificationCenter defaultCenter] postNotificationName:kProductsLoadedNotification object:_products];
}
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error
{
DDLogError(@"Failed to load list of products. %@",error.localizedDescription);
_request = nil;
}
- (void)recordTransaction:(SKPaymentTransaction *)transaction
{
}
- (void)provideContent:(NSString *)productIdentifier
{
NSArray *formattedarrayFromString = [productIdentifier componentsSeparatedByString:@"*"];
NSString *type = [formattedarrayFromString objectAtIndex:*];
NSDictionary *dictionary = @{
@"data" : formattedarrayFromString,
@"ID" : productIdentifier,
};
if ( type.integerValue == 1 )
{
[[NSNotificationCenter defaultCenter] postNotificationName:*** object:nil userInfo:dictionary];
}
else
{
DDLogInfo(@"Toggling flag for: %@", productIdentifier);
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:productIdentifier];
[[NSUserDefaults standardUserDefaults] synchronize];
[_purchasedProducts addObject:productIdentifier];
[[NSNotificationCenter defaultCenter] postNotificationName:kProductPurchasedNotification object:productIdentifier];
}
}
- (void)completeTransaction:(SKPaymentTransaction *)transaction
{
DDLogInfo(@"completeTransaction...");
[self validateReceiptForTransaction:transaction];
[self recordTransaction: transaction];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
DDLogInfo(@"%@",response);
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
DDLogInfo(@"Succeeded! Received bytes of data"); // Deal with an error
}
- (void)restoreTransaction:(SKPaymentTransaction *)transaction
{
DDLogInfo(@"restoreTransaction...");
[self recordTransaction: transaction];
[self validateReceiptForTransaction:transaction];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void)failedTransaction:(SKPaymentTransaction *)transaction
{
if (transaction.error.code != SKErrorPaymentCancelled)
{
DDLogError(@"Transaction error: %@", transaction.error.localizedDescription);
}
[[NSNotificationCenter defaultCenter] postNotificationName:kProductPurchaseFailedNotification object:transaction];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (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;
}
}
}
- (BOOL)productPurchased:(NSString *)productIdentifier
{
DDLogInfo(@"%@",productIdentifier);
DDLogInfo(@"%@",_purchasedProducts);
return [_purchasedProducts containsObject:productIdentifier];
}
- (void)buyProduct:(SKProduct *)product
{
DDLogInfo(@"Buying %@...", product.productIdentifier);
SKPayment * payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
- (void)restoreCompletedTransactions
{
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
+ (NSString*) encode:(const uint8_t*) input length:(NSInteger) length
{
***
}
- (void)validateReceiptForTransaction:(SKPaymentTransaction *)transaction
{
MyVerificationController * verifier = [MyVerificationController sharedInstance];
[verifier verifyPurchaseForProduction:transaction completionHandler:^(BOOL success, NSError *error)
{
if(success)
{
DDLogInfo(@"successfully verified receipt!");
[self provideContent:transaction.payment.productIdentifier];
}
else
{
if (error.code == 21007)
{
[verifier verifyPurchaseForSandbox:transaction completionHandler:^(BOOL success, NSError *error)
{
if(success)
{
DDLogInfo(@"successfully verified receipt!");
[self provideContent:transaction.payment.productIdentifier];
}
else
{
DDLogError(@"Failed to validate receipt.");
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
[[NSNotificationCenter defaultCenter] postNotificationName:*** object:nil userInfo:nil];
}
}];
}
else
{
DDLogError(@"Failed to validate receipt.");
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
[[NSNotificationCenter defaultCenter] postNotificationName:*** object:nil userInfo:nil];
}
}
}];
}
@end
問題を引き起こしていると思われるすべての非消耗品は、私たちによって直接処理され、サーバー上のアカウントに関連付けられています。
上記のクラスで使用しているデリゲート
<SKProductsRequestDelegate, SKPaymentTransactionObserver,NSURLConnectionDelegate>