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

Как восстановить правильную транзакцию при использовании автообновляемых покупок в приложении?

Этот вопрос касается Auto-Renewable IAP и того, как они должны быть восстановлены. Эти ссылки: this и это не помогли мне, к сожалению.

В моем приложении у меня есть пользователи, подписавшиеся на Автоматически обновляемые покупки в приложениях. Они могут подписаться на 1, 6 или 12 месяцев.

Когда они подписываются, квитанция транзакции отправляется на мой сервер для проверки позже. Я не проверять получение сразу же, так как это замедлит работу пользователя (для проверки запросов на проверку ячеек для яблок мне требуется 1 - 2 секунды). Вместо этого я использую наивный подход и предоставляю контент, на который подписаны пользователи, без прямой проверки квитанции. Я планирую задание cron для проверки каждой пользовательской квитанции один раз в день и отмены привилегий при устаревших квитанциях.

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

Когда я пытаюсь восстановить покупки в режиме песочницы, используя:

[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];

Я получаю не только текущие подписки, но и все предыдущие подписки (включая устаревшие) в обратном вызове:

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

В настоящее время я пробовал свои IAP примерно 30 раз, а это означает, что указанному выше методу отправлено 30 различных транзакций (устаревших и активных). Для каждой из этих транзакций я загружаю квитанцию ​​о транзакциях на свой веб-сервис для последующей проверки.

Теперь. В случае, если последняя транзакция имеет устаревшую квитанцию ​​(но вторая - последняя транзакция была действительно действительна), она перезапишет текущую (действительную) квитанцию ​​для текущего пользователя и, таким образом, отменит права пользователя для пользователя.

В основном, моя проблема заключается в том, что при вызове restoreCompletedTransactions я получаю список как устаревших, так и активных транзакций. И на стороне сервера они могут аннулировать друг друга. Оптимально, я хотел бы получить только одну транзакцию (наиболее актуальную) и отправить ее на мой сервер для последующей проверки.

В целом, я думаю, мой главный вопрос:

Как я могу убедиться, что восстановлена ​​только активная (то есть самая последняя) транзакция?

4b9b3361

Ответ 1

Мое решение: получить квитанцию ​​и подтвердить ее против ваших идентификаторов продукта. Использование SKPaymentQueue.defaultQueue().restoreCompletedTransactions() для автоматически возобновляемых подписки не имеет смысла, потому что:

  • занимает слишком много времени, потому что он требует, чтобы проверка валидации приема вызывалась слишком много раз (один раз для каждой транзакции в прошлом).
  • может привести к тому, что действительная проверка транзакции будет перезаписана последующей неудачной транзакцией.

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

Ответ 2

Я считаю, что вам придется обработать квитанцию ​​и посмотреть "Оригинальную дату покупки и дату истечения срока подписки" (https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/Subscriptions.html) каждой покупки в квитанции, чтобы узнать, активна ли какая-либо покупка. Вы можете обработать квитанцию ​​либо с помощью сервера, либо с помощью Apple, чтобы получить JSON для получения. Или, если вы работаете с iOS7, вы можете проверить квитанцию ​​на устройстве, а также получить JSON (например, см. Полное решение для ЛОКАЛЬНО проверять поступления и пакеты в приложении квитанции на iOS 7). Если вы работаете с iOS7, у вас будет одна квитанция со всеми покупками, содержащимися в ней, с помощью:

[[NSBundle mainBundle] appStoreReceiptURL]

Ответ 3

Используя uniqueID, используя KeyChains, мы можем сохранить receipt.

-(NSString*)checkUniqueIDInKeyChains {
    NSString *uniqueID = [apDelegate.keyChain objectForKey:(__bridge id)kSecValueData];
    return uniqueID;
 }

 -(void)saveUniqIDinKeyChain:(NSString*)uniqueID {
     [apDelegate.keyChain setObject:uniqueID forKey:(__bridge id)kSecValueData];
 }

-(NSString *)generateUUID {
    //Check for the UDID in the keychain , if not present create else take it from keychain.
    CFUUIDRef theUUID = CFUUIDCreate(NULL);
    CFStringRef string = CFUUIDCreateString(NULL, theUUID);
    CFRelease(theUUID);
    return (__bridge NSString *)string;
 }

-(NSDateFormatter*)getDateFormatter {
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:@"GMT"]];
    [dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]];
    [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
    return dateFormatter;
}

Приобретите product, проверив receipt.

-(BOOL)isPurchaseExpired:(NSDate*)expireDate {
    NSDateFormatter *dateFormatter = [self getDateFormatter];
    NSString *expireDateString = [[NSUserDefaults standardUserDefaults] objectForKey:@"purchaseExpireDate"];
    expireDate = [dateFormatter dateFromString:[expireDateString substringToIndex:18]];
    NSComparisonResult result = [expireDate compare:[dateFormatter dateFromString:      [dateFormatter stringFromDate:[NSDate date]]]];

    NSLog(@"\n %@ \n %@ ", expireDate, [dateFormatter dateFromString:[dateFormatter stringFromDate:[NSDate date]]]);
    if (result ==  NSOrderedAscending) {
        NSLog(@"Current Date is Greater than the Purchased, allowing user to access the content");
        return YES;
    }
    else if (result == NSOrderedDescending) {
        NSLog(@"Current date is Smaller than the Purchase Date");
        return NO;
    }
    else {
        NSLog(@"Current and Purchase Dates are Equal , allowing user to access the content");
        return YES;
    }
}