SKReceiptRefreshRequest делегат, вызывающий отклонение; не могу найти использование в моем коде
Укороченная версия
Apple отклонила мое приложение, сказав, что я использую SKReceiptRefreshRequest
, но я не могу найти его в своем коде (ниже).
Длинная версия
В настоящее время я пытаюсь одобрить свое приложение в магазине приложений и вхожу в несколько стен. В настоящее время основная проблема заключается в том, что они говорят, что я неправильно реализовал проверку квитанции, когда, исходя из их документов, я сделал, как они указали, насколько мне известно. Затем они направили меня к представителю службы технической поддержки разработчиков. Затем он переходит к процессу исключения, основанному на предположениях, которые связаны с тем, что я не вижу мой код и не общаюсь с отделом анализа приложений.
Во-первых, он упоминает SKReceiptRefreshRequest
и великая объединительная квитанция. Я сообщил ему, что я не использую SKReceiptRefreshRequest
; Я искал весь проект. Затем мы прошли еще одно исключение, и в итоге я отправил.IPA вместе с профилями обеспечения для представителя DTS для личного тестирования. Он сообщил, что не видит проблем и свяжется с отделом обзора приложений, чтобы выяснить причину отклонения. Наконец некоторый прогресс.
И он возвращается, говоря
" Проблема в том, что 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>