Поведение кнопки "Восстановить транзакции", когда нет ничего, что можно было бы восстановить

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

Я все для этого. Первая версия моего приложения каким-то образом прошла проверку без нее (я не знал об этом правиле в то время и/или пока не был применен), но затем я начал получать много сообщений электронной почты от пользователей спрашивая о недостающем контенте (также есть Руководство по хранению данных, а загружаемое содержимое не загружается).

Итак, скажем, я включаю кнопку "восстановить" где-то в моем пользовательском интерфейсе, что при звонках:

[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];

До сих пор так хорошо. Пользователь запрашивает свой AppleID и/или пароль, и начинается процесс восстановления.

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

Я хотел бы иметь возможность отображать предупреждение в соответствии с главой "Все покупки в актуальном состоянии" или что-то в этом роде.

Есть ли что-нибудь, что я могу сделать в коде Transaction Observer для обнаружения этого случая?

Кто-нибудь думает, что это будет плохой дизайн, UX-мудрый?

Ответы

Ответ 1

Вы также можете реализовать следующие функции делегата:

-(void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
-(void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error

Затем вы узнаете, когда процесс восстановления был завершен или если он не удался. Вы можете смешать использование queue.transactions.count в функции paymentQueueRestoreCompletedTransactionsFinished, чтобы узнать, были ли какие-либо транзакции восстановлены.

Не забудьте обработать SKPaymentTransactionStateRestored в

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

Вы также можете обрабатывать восстановленные транзакции таким же образом, как и с SKPaymentTransactionState. Приобретенные транзакции (ы).

Ответ 2

Это все еще проблема в последнем SDK/xCode 8.0, Swift 3 - если пользователь, который не совершил покупок, пытается "восстановить", следующий метод:

SKPaymentQueue.default().restoreCompletedTransactions()

не запускает обычный метод делегирования, который обрабатывает покупки/восстановление:

paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {...}

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

func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error){...}

И вместо этого запускается дополнительный метод, как если бы восстановление работало нормально:

func paymentQueueRestoreCompletedTransactionsFinished()

Это может привести к тому, что приложение будет выглядеть так, как будто оно висит/ничего не делает.

Как обсуждалось в других ответах, причина этого в том, что SKPaymentQueue не содержит транзакций.

в Swift, эту проблему можно преодолеть, используя следующее:

//Optional Method.
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue)
{

    let transactionCount = queue.transactions.count

    if transactionCount == 0
    {
        print("No previous transactions found")

        //You can add some method to update your UI, indicating this is the problem e.g. use notification centre:
        NotificationCenter.default.post(name: "restoreFailedNoPrevIAP", object: nil)

    }

}

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

Ответ 3

Меня заинтересовала правильная/лучшая формулировка для восстановления покупки.

Я видел достаточно предупреждений "Неизвестная ошибка", просто используя [error localizedDescription] внутри -(void)paymentQueue:restoreCompletedTransactionsFailedWithError:. (todo: заполнить радар)

Итак, я взглянул на то, как Apple это делает. Единственное приложение от Apple с нерасходуемыми покупками в приложении прямо сейчас - GarageBand (декабрь 2014 года).

Вместо "Восстановить покупку", "Восстановить предыдущие покупки" или... они идут с "Already Purchased?".

Purchase Screen 1

Но вот экран, который меня больше интересует, результат нажатия "Already Purchased?", когда ничего не восстановить:

Purchase Screen 2

"There are no items available to restore at this time." Не революционный, но превосходит "Неизвестную ошибку"

Итак, давайте посмотрим на -(void)paymentQueue:restoreCompletedTransactionsFailedWithError:.

IOS

- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error
{
    if ([error.domain isEqual:SKErrorDomain] && error.code == SKErrorPaymentCancelled)
    {
        return;
    }

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"There are no items available to restore at this time.", @"")
                                                    message:nil
                                                   delegate:nil
                                          cancelButtonTitle:NSLocalizedString(@"OK", @"")
                                          otherButtonTitles:nil];
    [alert show];
}

OS X:

Я не доволен одним и тем же текстом в OS X. NSAlert с просто messageText и no informativeText просто выглядит пустым и неправильным.

Один из вариантов для меня - сообщить пользователю, что ему нужно его купить, с чем-то вроде "To use it, you need to buy "%@".".

Другой вариант, с которым я столкнулся, - это позволить им браузеру История покупок. Я обнаружил, что вы можете напрямую ссылаться на него с помощью itms://phobos.apple.com/purchaseHistory. Во всей честности История покупок в iTunes Store - это кусок дерьма, он заставит вас навсегда найти что-то.

Но, возможно, это помогает перестраховывать людей, и мы не пытаемся заставить их выкупить что-то. Всегда предполагайте, что ваши клиенты не знают или не могут определить разницу между Нерасходуемыми и Расходуемыми. И не знаю, что они не могут дважды зарядиться для Нерасходуемого.

- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error
    {
    if ([error.domain isEqual:SKErrorDomain] && error.code == SKErrorPaymentCancelled)
    {
        return;
    }

    NSAlert *alert = nil;
    alert = [NSAlert alertWithMessageText:NSLocalizedString(@"There are no items available to restore at this time.", @"")
                            defaultButton:NSLocalizedString(@"OK", @"")
                          alternateButton:NSLocalizedString(@"Purchase History", @"")
                              otherButton:nil
                informativeTextWithFormat:@"You can see your purchase history in the iTunes Store."];
    NSModalResponse returnCode = [alert runModal];
    if (returnCode == NSAlertAlternateReturn)
    {
        NSURL *purchaseHistory = [NSURL URLWithString:@"itms://phobos.apple.com/purchaseHistory"];
        [[NSWorkspace sharedWorkspace] openURL:purchaseHistory];
    }
}

Пример для OS X

Example on OS X

Замечания по тестированию (OS X, пользователь изолированной песочницы itunesconnect):

Когда пользователь нажимает кнопку "Отмена":

- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error
Error Domain=SKErrorDomain Code=2 "The payment was canceled by the user" UserInfo=0x600000470a40 {NSLocalizedDescription=The payment was canceled by the user}

Если восстановить нечего:

- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error
Error Domain=SKErrorDomain Code=0 "Unknown Error." UserInfo=0x60800007fb80 {NSLocalizedDescription=Unknown Error.}

Ответ 4

Я столкнулся с той же проблемой в приложении, над которым я сейчас работаю. Мое обходное решение - использовать X-таймер. Он запускается, когда вы нажимаете кнопку "Восстановить покупки" и перезапускаетесь, если приходит восстановленное событие транзакции. Когда он достигает второй секунды X, у меня появляется всплывающее сообщение "Покупки восстановлены". Поэтому, если у вас нет транзакций, вам нужно только подождать X секунд. Надеюсь, что это поможет.