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>

0 ответов

Другие вопросы по тегам