Подтвердить что ты не робот

Следуя при покупке приложения, приложение запускается при запуске. productIdentifier = ноль?

У меня есть несколько пользователей, которые сообщили, что после попытки покупки приложения приложение теперь сбой при запуске. Я попросил их удалить и переустановить приложение, которое не сработало, и попытался попросить их войти в режим полета, чтобы остановить любое сетевое сообщение, которое не сработало.

Я не могу реплицировать ошибку в любом случае на своих устройствах, и моя покупка в приложении проходит очень хорошо в песочнице и в производственных режимах. Моя мысль заключается в том, что каким-то образом их транзакция получила нулевой идентификатор productIdentifier, который вызывает сбой при загрузке, но я не уверен, какие методы наблюдателей транзакций вызываются при запуске приложения, и я могу исправить проблему для них.

Можно ли каким-либо образом "очистить" очередь транзакций или иным образом проверить для nil productidentifiers при запуске и разрешить этим пользователям снова использовать приложение? Я сделал несколько сотен покупок приложений, используя приведенный ниже код, и это только недавно началось. Какой из вспомогательных методов вызывается при запуске приложения?

В AppDelegate.m

[[SKPaymentQueue defaultQueue] addTransactionObserver:[MovieClockIAPHelper sharedHelper]];

В app helper code:

- (id)initWithProductIdentifiers:(NSSet *)productIdentifiers {
    if ((self = [super init])) {

        // Store product identifiers
        _productIdentifiers = [productIdentifiers retain];

        // Check for previously purchased products

        NSMutableSet * purchasedProducts = [NSMutableSet set];
        for (NSString * productIdentifier in _productIdentifiers) {

            BOOL productPurchased = [[NSUserDefaults standardUserDefaults] boolForKey:productIdentifier];

            if (productPurchased) {
                [purchasedProducts addObject:productIdentifier];
                NSLog(@"Previously purchased: %@", productIdentifier);
            }
            else{
            NSLog(@"Not purchased: %@", productIdentifier);
            }
        }
        self.purchasedProducts = purchasedProducts;

    }
    return self;
}

- (void)requestProducts {

    self.request = [[[SKProductsRequest alloc] initWithProductIdentifiers:_productIdentifiers] autorelease];
    _request.delegate = self;
    [_request start];

}

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {

    NSLog(@"Received products results...");   
    self.products = response.products;
    self.request = nil;    

    [[NSNotificationCenter defaultCenter] postNotificationName:kProductsLoadedNotification object:_products];    
}


- (void)restoreCompletedTransactions {
    [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}

- (void)provideContent:(NSString *)productIdentifier {

    NSLog(@"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 {

    NSLog(@"completeTransaction...");

    [self recordTransaction: transaction];
    [self provideContent: transaction.payment.productIdentifier];
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];

}

- (void)restoreTransaction:(SKPaymentTransaction *)transaction {

    NSLog(@"restoreTransaction...");


    [self recordTransaction: transaction];
    [self provideContent: transaction.originalTransaction.payment.productIdentifier];
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];

}

- (void)failedTransaction:(SKPaymentTransaction *)transaction {

    if (transaction.error.code != SKErrorPaymentCancelled)
    {
        NSLog(@"Transaction error: %@", transaction.error.localizedDescription);
    }

    [[NSNotificationCenter defaultCenter] postNotificationName:kProductPurchaseFailedNotification object:transaction];

    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];

}

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
    NSLog(@"in the payment queue");

    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;
        }
        }

}

-(void)buyProduct:(SKProduct *)product
{
    NSLog(@"In buyproduct Buying %@...", product.productIdentifier);

    SKPayment *payment = [SKPayment paymentWithProduct:product];

    [[SKPaymentQueue defaultQueue] addPayment:payment];
}

- (void)dealloc
{
    [_productIdentifiers release];
    _productIdentifiers = nil;
    [_products release];
    _products = nil;
    [_purchasedProducts release];
    _purchasedProducts = nil;
    [_request release];
    _request = nil;
    [super dealloc];
}

@end
4b9b3361

Ответ 1

У меня возникла аналогичная проблема, когда транзакция находится в SKPaymentTransactionStateRestored. Мое тестирование показало, что это может быть проблемой с IOS 7.0.3, но я не смог проверить это.

StoreKit сохраняет постоянный список транзакций, которые ваше приложение должно завершить. Как вы заметили, транзакция будет сообщаться при каждом запуске, пока она не будет завершена.

Решением, которое мы внедрили, является проверка, равен ли идентификатор продукта нулю перед использованием из точки входа:

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions

Даже когда мы получили транзакцию с идентификатором продукта nil, мы смогли успешно вызвать finishTransaction.

Надеюсь, это поможет.

Ответ 2

Один из моих пользователей пожаловался четыре дня назад по той же проблеме и смог отправить мне журнал сбоев. Он использует iOS 7.0.3 на iPhone 5,2. Сбой происходит после идентификации SKPaymentTransactionStateRestored при попытке построить словарь с свойством productIdentifier из оригиналаTransaction.payment:

NSDictionary* userInfoDict = @{@"productID":transaction.payment.productIdentifier};

Я думаю, что либо originalTransaction, либо его свойства payment или productIdentifier равны нулю. Я сохранил productIdentifier from transaction.payment.productIdentifier вместо этого из транзакции .originalTransaction.payment.productIdentifier при восстановлении и использовании этого как productIdentifier с этого момента:

case SKPaymentTransactionStateRestored:
{
  NSString *productID = transaction.originalTransaction.payment.productIdentifier;
  if (!productID) {
    productID = transaction.payment.productIdentifier;
  }
  [self handlePurchaseSuccessful:transaction.originalTransaction productIdentifier:productID];
}

Все еще ожидаем рассмотрения/обратной связи, если это устраняет проблему.

Ответ 3

Разрабатывая ответ Shawn, в - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions у вас, вероятно, есть такой код:

- (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;
        }     
    }
}

- (void) restoreTransaction: (SKPaymentTransaction *)transaction
{   
    /* Handle restore here */
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction]; 
}

Вы можете обрабатывать nil productIdentifiers в restoreTransaction:, добавив проверку, чтобы узнать, является ли productIdentifier нулем, например:

- (void) restoreTransaction: (SKPaymentTransaction *)transaction
{   
    if (!transaction.originalTransaction.payment.productIdentifier) {
        NSLog(@"productIdentifier is nil; Apple bug?");
        [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
        return;
    }

    /* Handle restore here */
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}

Этот метод исправил проблему для меня в моем приложении. При запуске приложения журнал "productIdentifier равен нулю, ошибка Apple?" и не потерпел крушение. Когда я вручную восстановил транзакции вручную, Apple отправила действительную транзакцию, и приложение работало как сконструированное.

Ответ 4

Я исправил эту проблему как указано Marimba выше, и это помогло нашим клиентам:

case SKPaymentTransactionStateRestored:
{
  NSString *productID = transaction.originalTransaction.payment.productIdentifier;
  if (productID == nil) {
    productID = transaction.payment.productIdentifier;
  }
  [self handlePurchaseSuccessful:transaction.originalTransaction productIdentifier:productID];
}

Ответ 5

У меня была та же проблема paymentQueue:updatedTransactions: вызывается с экземплярами SKPaymentTransaction с состоянием SKPaymentTransactionStateRestored и nil productIdentifier в originalTransaction.

Звучит очень странно и может быть ошибкой SDK 7.0.3.

Вы все еще компилируете SDK 6?

Я собираюсь повторно отправить свое приложение в магазин, чтобы узнать, исправлена ​​ли проблема, но только завершение таких транзакций, но я надеюсь, что другие транзакции с действительным идентификатором productIdentifier будут обработаны теперь, когда приложение не будет разбиваться, так что Я знаю, что восстановить.