Botón "Restaurar transactions" Comportamiento del button cuando no hay nada que restaurar

Como se analizó en esta pregunta y en cualquier otro lugar, Apple ahora requiere que las aplicaciones incluyan un medio para que el usuario restablezca las transactions completadas para las compras en la aplicación.

Estoy todo por esto. La primera versión de mi aplicación de alguna manera hizo que pasara la revisión sin ella (no tenía conocimiento de esta regla en ese momento y / o aún no se aplicaba), pero luego comencé a recibir muchos correos electrónicos de los usuarios preguntando sobre el contenido faltante (existen las Pautas de almacenamiento de datos también y no se hace copy de security de los contenidos descargables).

Digamos que incluyo un button 'restaurar' en algún lugar de mi interfaz de usuario, que cuando se llaman llamadas:

[[SKPaymentQueue defaultQueue] restreCompletedTransactions]; 

Hasta aquí todo bien. Al usuario se le solicita su AppleID y / o contraseña, y comienza el process de restauración.

El problema que tengo es: Si no hay transactions para restaurar, después de la request de AppleID esencialmente no sucede nada en mi aplicación, y eso puede ser confuso para el usuario o hacer que la aplicación parezca no responde o está rota.

Me gustaría poder mostrar una vista de alerta a lo largo de las líneas de "Todas las compras están actualizadas" o algo así.

¿Hay algo que pueda hacer en mi código de Transaction Observer para detectar este caso?

¿Alguien piensa que sería un mal layout, UX-wise?

También podría implementar las siguientes funciones de delegado:

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

Entonces sabría cuándo finalizó el process de restauración o si falló. Puede mezclar el uso de queue.transactions.count en paymentQueueRestoreCompletedTransactionsFinished para ver si se restauraron las transactions.

Recuerde manejar el SKPaymentTransactionStateRestonetworking en

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

Es posible que también desee manejar las transactions restauradas de la misma manera que lo hizo con SKPaymentTransactionStatePurchased las transactions.

Estaba interesado en la networkingacción correcta / mejor para restaurar la compra.

He visto suficientes alertas de "Error desconocido", simplemente usando [error localizedDescription] dentro -(void)paymentQueue:restreCompletedTransactionsFailedWithError: (todo: llenar el radar)

Así que eché un vistazo a cómo lo hace Apple. La única aplicación de Apple con compras no integradas en la aplicación en este momento es GarageBand (diciembre de 2014).

En lugar de "Restaurar compra", "Restaurar compras anteriores" o … van con "Already Purchased?" .

Comprar pantalla 1

Pero aquí está la pantalla que más me interesa, el resultado de presionar "Already Purchased?" cuando no hay nada que restaurar:

Comprar pantalla 2

"There are no items available to restre at this time." No es revolucionario, pero supera al "Error desconocido"

Entonces veamos -(void)paymentQueue:restreCompletedTransactionsFailedWithError:

iOS :

 - (void)paymentQueue:(SKPaymentQueue *)queue restreCompletedTransactionsFailedWithError:(NSError *)error { if ([error.domain isEqual:SKErrorDomain] && error.code == SKErrorPaymentCancelled) { return; } UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"There are no items available to restre at this time.", @"") message:nil delegate:nil cancelButtonTitle:NSLocalizedString(@"OK", @"") otherButtonTitles:nil]; [alert show]; } 

OS X :

No estoy contento con el mismo text en OS X. Un NSAlert con solo el text del post y ningún text informativo simplemente parece vacío e incorrecto.

Una opción para mí es dejar que el usuario sepa que necesita comprarlo, con algo así como "To use it, you need to buy “%@”." .

Otra opción que se me ocurrió es dejarlos en el browser Historial de compras . Descubrí que puedes vincularlo directamente con itms://phobos.apple.com/purchaseHistory . Con toda sinceridad, comprar historial en iTunes Store es una mierda, te llevará por siempre encontrar algo.

Pero tal vez ayude a reasegurar a la gente que no tratemos de hacer que recompren algo. Asum siempre que sus clientes no saben o no pueden distinguir entre No Consumibles y Consumibles. Y no sabe que no se les puede cobrar dos veces por un No Consumible.

 - (void)paymentQueue:(SKPaymentQueue *)queue restreCompletedTransactionsFailedWithError:(NSError *)error { if ([error.domain isEqual:SKErrorDomain] && error.code == SKErrorPaymentCancelled) { return; } NSAlert *alert = nil; alert = [NSAlert alertWithMessageText:NSLocalizedString(@"There are no items available to restre 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 shanetworkingWorkspace] openURL:purchaseHistory]; } } 

Ejemplo en OS X

Ejemplo en OS X

Pruebas de notas (OS X, itunesconnect sandbox user):

Cuando el usuario hace clic en cancelar:

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

Cuando no hay nada que restaurar:

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

Esto sigue siendo un problema en el último SDK / xCode 8.0, Swift 3: si un usuario que no ha realizado ninguna compra intenta "restaurar", el siguiente método:

 SKPaymentQueue.default().restreCompletedTransactions() 

no activa el método de delegado habitual que maneja las compras / restauración:

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

Curiosamente, el método que probablemente debería atrapar el error tampoco se llama:

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

Y, en cambio, se desencadena el método opcional, como si la restauración funcionara bien:

 func paymentQueueRestoreCompletedTransactionsFinished() 

Esto puede hacer que la aplicación parezca que está colgando / no hace nada.

Como se discutió en las otras respuestas, la causa de esto es que SKPaymentQueue no contiene ninguna transacción.

en Swift, este problema se puede superar mediante el uso de lo siguiente:

 //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 eg use notification centre: NotificationCenter.default.post(name: "restreFailedNoPrevIAP", object: nil) } } 

Es importante destacar que si un usuario realizó compras previas, la queue de transacción no estará vacía, por lo tanto, se invocará al método de delegado updateTransaction y procesará la request de restauración normalmente.

Me encontré con el mismo problema en la aplicación en la que estoy trabajando ahora. Mi solución es utilizar un timer X segundo. Comienza cuando tocas el button "Restaurar compras" y se reinicia si entra un evento de transacción restaurado. Una vez que llega a la marca X segundo tengo una window emergente que dice "Compras restauradas". Entonces, si no tiene transactions, solo debería esperar X segundos. Espero que ayude.