iphone - quitar - Cualquier experiencia(temprana) con suscripciones auto-renovables para iOS
como quitar suscripcion de itunes (4)
¿Tal vez los servidores de compra de sandbox auto-renovables están caídos? Las compras de elementos de espacio aislado de Consumible / No Consumible / Suscripción están funcionando, pero la compra auto-renovable devuelve este error:
Error Domain = SKErrorDomain Code = 0 "No se puede conectar a iTunes Store" UserInfo = 0x15b600 {NSLocalizedDescription = No se puede conectar a iTunes Store}
Apple finalmente presentó las llamadas suscripciones auto-renovables ayer. Como solo tengo pocas experiencias (solo de sandbox) con la compra desde la aplicación, no estoy seguro de haberlo entendido bien aquí. Parece que uno necesita una verificación del servidor de los recibos. Parece que la única forma de averiguar si la suscripción sigue siendo válida es almacenar los datos de la transacción original en el servidor. La guía de programación de manzanas con respecto a este tema es muy críptica para mí.
Mi expectativa era que solo podía trabajar con un cliente de iOS, solo preguntaba a iTunes a través de la API del kit de la tienda si él / ella ya compraba este producto (suscripción) y recibía una respuesta de sí / no junto con una fecha de vencimiento.
¿Alguien tiene experiencias con suscripciones auto-renovables o (porque parecen de alguna manera similares) productos no consumibles? ¿Hay algún buen tutorial sobre esto?
Gracias.
Lo tengo funcionando en la caja de arena, casi en vivo ...
Uno debe usar un servidor para verificar los recibos.
En el servidor, puede registrar el dispositivo udid con los datos del recibo, ya que los recibos siempre se generan de manera reciente, y funcionará en varios dispositivos, ya que los recibos siempre se generan de forma reciente.
En el dispositivo uno no necesita almacenar ningún dato sensible, y no debería :)
Uno debe verificar el último recibo con la tienda cada vez que aparece la aplicación. La aplicación llama al servidor y el servidor valida con la tienda. Siempre que la tienda devuelva una aplicación de recibo válida, se sirve la característica.
Desarrollé una aplicación Rails3.x para manejar el lado del servidor, el código real para la verificación se ve así:
APPLE_SHARED_PASS = "enter_yours"
APPLE_RECEIPT_VERIFY_URL = "https://sandbox.itunes.apple.com/verifyReceipt" #test
# APPLE_RECEIPT_VERIFY_URL = "https://buy.itunes.apple.com/verifyReceipt" #real
def self.verify_receipt(b64_receipt)
json_resp = nil
url = URI.parse(APPLE_RECEIPT_VERIFY_URL)
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
json_request = {''receipt-data'' => b64_receipt, ''password'' => APPLE_SHARED_PASS}.to_json
resp, resp_body = http.post(url.path, json_request.to_s, {''Content-Type'' => ''application/x-www-form-urlencoded''})
if resp.code == ''200''
json_resp = JSON.parse(resp_body)
logger.info "verify_receipt response: #{json_resp}"
end
json_resp
end
#App Store error responses
#21000 The App Store could not read the JSON object you provided.
#21002 The data in the receipt-data property was malformed.
#21003 The receipt could not be authenticated.
#21004 The shared secret you provided does not match the shared secret on file for your account.
#21005 The receipt server is not currently available.
#21006 This receipt is valid but the subscription has expired.
ACTUALIZAR
Mi aplicación fue rechazada porque los metadatos no indicaban claramente alguna información sobre las suscripciones auto renovables.
En sus metadatos en iTunes Connect (en la descripción de su aplicación): debe divulgar clara y visiblemente a los usuarios la siguiente información sobre su suscripción de renovación automática:
- Título de publicación o servicio
- Duración de la suscripción (período de tiempo y / o número de entregas durante cada período de suscripción)
- Precio de la suscripción y precio por emisión si corresponde
- El pago se cargará a la cuenta de iTunes en la confirmación de la compra
- La suscripción se renueva automáticamente a menos que la renovación automática se apague al menos 24 horas antes del final del período actual.
- La cuenta se cobrará por la renovación dentro de las 24 horas anteriores al final del período actual, e identificará el costo de la renovación.
- Las suscripciones pueden ser administradas por el usuario y la renovación automática se puede desactivar yendo a la configuración de la cuenta del usuario después de la compra.
- No se permite la cancelación de la suscripción actual durante el período de suscripción activa
- Enlaces a su política de privacidad y condiciones de uso
- Cualquier porción no utilizada de un período de prueba gratuito, si se ofrece, se perderá cuando el usuario compre una suscripción a esa publicación ".
ACTUALIZACIÓN II
La aplicación fue rechazada nuevamente. La AppStore verify url no verifica el recibo de la suscripción. No puedo reproducir este problema en la zona de pruebas, mi aplicación funciona sin problemas. La única manera de solucionar esto es enviar la aplicación nuevamente para su revisión y ver el registro del servidor.
ACTUALIZACIÓN III
Otro rechazo Mientras tanto, Apple documentó dos estados más:
#21007 This receipt is a sandbox receipt, but it was sent to the production service for verification.
#21008 This receipt is a production receipt, but it was sent to the sandbox service for verification.
Antes de enviar la aplicación para su revisión, no se debe cambiar el servidor a la URL de verificación de recibo de producción. si lo hace, uno obtiene el estado 21007 devuelto en la verificación.
Esta vez, el rechazo se lee así:
La aplicación inicia el proceso de Compra In App de una manera no estándar. Hemos incluido los siguientes detalles para ayudar a explicar el problema y esperamos que considere la posibilidad de revisar y volver a enviar su solicitud.
El nombre de usuario y la contraseña de iTunes se solicitan inmediatamente al iniciar la aplicación. Consulte la captura de pantalla adjunta para obtener más información.
No tengo idea de por qué sucede esto. ¿Aparece el cuadro de diálogo de contraseña porque se está restaurando una transacción anterior? o aparece en el momento de solicitar información de productos de la tienda de aplicaciones?
ACTUALIZAR IV
Lo tengo justo después de 5 rechazos. Mi código estaba haciendo el error más obvio. Uno realmente debe asegurarse de terminar siempre las transacciones cuando se entregan a la aplicación.
Si las transacciones no se terminan, se devuelven a la aplicación y las cosas van extrañamente mal.
Uno necesita iniciar un pago primero, así:
//make the payment
SKPayment *payment = [SKPayment paymentWithProductIdentifier:productIdentifier];
[[SKPaymentQueue defaultQueue] addPayment:payment];
Luego, la aplicación renunciará en breve a su estado activo y se llamará a este método en el delegado de la aplicación:
- (void)applicationWillResignActive:(UIApplication *)application
Mientras la aplicación está inactiva, la App Store abre sus diálogos. a medida que la aplicación se vuelve a activar:
- (void)applicationDidBecomeActive:(UIApplication *)application
El sistema operativo entrega la transacción a través de:
- (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];
break;
}
default:
break;
}
}
}
Y luego uno completa la transacción:
//a fresh purchase
- (void) completeTransaction: (SKPaymentTransaction *)transaction
{
[self recordTransaction: transaction];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
Vea, cómo uno llama al método finishTransaction
justo después de pasar la transacción recibida para recordTransaction
, que luego llama al servidor de aplicaciones y realiza la verificación de recibo de la suscripción con el App Store. Me gusta esto:
- (void)recordTransaction: (SKPaymentTransaction *)transaction
{
[self subscribeWithTransaction:transaction];
}
- (void)subscribeWithTransaction:(SKPaymentTransaction*)transaction {
NSData *receiptData = [transaction transactionReceipt];
NSString *receiptEncoded = [Kriya base64encode:(uint8_t*)receiptData.bytes length:receiptData.length];//encode to base64 before sending
NSString *urlString = [NSString stringWithFormat:@"%@/api/%@/%@/subscribe", [Kriya server_url], APP_ID, [Kriya deviceId]];
NSURL *url = [NSURL URLWithString:urlString];
ASIFormDataRequest *request = [[[ASIFormDataRequest alloc] initWithURL:url] autorelease];
[request setPostValue:[[transaction payment] productIdentifier] forKey:@"product"];
[request setPostValue:receiptEncoded forKey:@"receipt"];
[request setPostValue:[Kriya deviceModelString] forKey:@"model"];
[request setPostValue:[Kriya deviceiOSString] forKey:@"ios"];
[request setPostValue:[appDelegate version] forKey:@"v"];
[request setDidFinishSelector:@selector(subscribeWithTransactionFinished:)];
[request setDidFailSelector:@selector(subscribeWithTransactionFailed:)];
[request setDelegate:self];
[request startAsynchronous];
}
Anteriormente, mi código intentaba llamar a finishTransaction
solo después de que mi servidor verificara el recibo, pero para entonces la transacción ya se había perdido. así que asegúrese de finishTransaction
tan pronto como sea posible.
Otro problema con el que se puede topar es el hecho de que, cuando la aplicación está en la caja de arena, llama a la url de verificación de App Store de la zona de pruebas, pero cuando está en revisión, de alguna manera se encuentra entre mundos. Así que tuve que cambiar mi código de servidor así:
APPLE_SHARED_PASS = "83f1ec5e7d864e89beef4d2402091cd0" #you can get this in iTunes Connect
APPLE_RECEIPT_VERIFY_URL_SANDBOX = "https://sandbox.itunes.apple.com/verifyReceipt"
APPLE_RECEIPT_VERIFY_URL_PRODUCTION = "https://buy.itunes.apple.com/verifyReceipt"
def self.verify_receipt_for(b64_receipt, receipt_verify_url)
json_resp = nil
url = URI.parse(receipt_verify_url)
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
json_request = {''receipt-data'' => b64_receipt, ''password'' => APPLE_SHARED_PASS}.to_json
resp, resp_body = http.post(url.path, json_request.to_s, {''Content-Type'' => ''application/x-www-form-urlencoded''})
if resp.code == ''200''
json_resp = JSON.parse(resp_body)
end
json_resp
end
def self.verify_receipt(b64_receipt)
json_resp = Subscription.verify_receipt_for(b64_receipt, APPLE_RECEIPT_VERIFY_URL_PRODUCTION)
if json_resp!=nil
if json_resp.kind_of? Hash
if json_resp[''status'']==21007
#try the sandbox then
json_resp = Subscription.verify_receipt_for(b64_receipt, APPLE_RECEIPT_VERIFY_URL_SANDBOX)
end
end
end
json_resp
end
Así que, básicamente, uno siempre verifica con la URL de producción, pero si devuelve el código 21007, significa que se envió un recibo de la zona de pruebas a la URL de producción y luego simplemente se vuelve a intentar con la URL de la zona de pruebas. De esta forma, su aplicación funciona igual en el entorno limitado y el modo de producción.
Y, finalmente, Apple quería que agregara un botón RESTORE al lado de los botones de suscripción, para manejar el caso de varios dispositivos propiedad de un usuario. Este botón luego llama a [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
y la aplicación se entregará con transacciones restauradas (si corresponde).
Además, a veces las cuentas de usuario de prueba se contaminan de alguna manera y las cosas dejan de funcionar y es posible que aparezca un mensaje de "No se puede conectar a la tienda de iTunes" al suscribirse. Ayuda a crear un nuevo usuario de prueba.
Aquí está el resto del código relevante:
- (void) restoreTransaction: (SKPaymentTransaction *)transaction
{
[self recordTransaction: transaction];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void) failedTransaction: (SKPaymentTransaction *)transaction
{
if (transaction.error.code == SKErrorPaymentCancelled)
{
//present error to user here
}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
Te deseo una experiencia de programación de InAppPurchase fluida. :-)
Para determinar si un usuario tiene una suscripción válida, tiene que a) validar el recibo existente como se describe en el documento al que se vinculó, o b) hacer que el usuario vuelva a comprar la suscripción y obtener una respuesta de Apple.
Este último no necesita ninguna interacción del lado del servidor, pero está equivocado y es probable que lo rechacen, porque tendrá que pedirle al usuario que efectivamente "recompre" su producto cada vez que quiera verificar su sub.
Entonces, la única opción es, como recomienda Apple, almacenar y luego verificar el recibo de la tienda.
Ahora, supongo que en teoría podría guardar el recibo de la tienda en el dispositivo y verificarlo de esa manera. Sin embargo, creo que tendrías que estar loco para hacer esto, porque el nuevo sistema de verificación requiere un secreto compartido que tendrías que combinar con la aplicación en sí (una muy mala idea).
Lo que significa que la respuesta a su pregunta "¿puedo trabajar con un cliente de iOS solamente?" Es "técnicamente sí", pero hacerlo sería muy poco recomendable debido a una serie de problemas de seguridad. Afortunadamente, la arquitectura del lado del servidor que necesita para compilar es muy simple: solo vincula los recibos de iTunes con los UDID de los dispositivos y una API simple para comunicarse con ellos. Si no puede resolverlo, estoy seguro de que muy pronto los terceros que compran aplicaciones como Urban Airship agregarán subs de renovación automática a sus productos.
Vincular el UDID y la recepción funciona bien porque cuando el usuario realiza una compra en otro dispositivo, Apple restaura automáticamente sus compras anteriores. Así que puede guardar el recibo nuevamente, esta vez vinculado a un nuevo UDID.
no hay necesidad de almacenarlo en el servidor. puedes verificarlo localmente en el cliente. actualmente estamos codificando un script auto renovable
pero actualmente parece que los servidores están caídos o algo así. la verificación con servidores Apple no funciona