Поведение кнопки "Восстановить транзакции", когда нет ничего, что можно было бы восстановить
Как обсуждалось в этом вопросе и во всем мире, 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 секунд. Надеюсь, что это поможет.