tutuapp - no se pudo verificar la app ios 11
¿Cómo agregar una compra en la aplicación a una aplicación de iOS? (4)
¿Cómo agregar una compra en la aplicación a una aplicación de iOS? ¿Cuáles son todos los detalles y hay algún código de muestra?
Está pensado para ser un juego de todo tipo de cómo agregar compras dentro de la aplicación a las aplicaciones de iOS
Sé que llego bastante tarde para publicar esto, pero comparto experiencias similares cuando aprendí las cuerdas del modelo IAP.
La compra desde la aplicación es uno de los flujos de trabajo más completos en iOS implementado por el marco de Storekit. La documentación completa es bastante clara si tiene paciencia para leerla, pero tiene un carácter técnico bastante avanzado.
Para resumir:
1 - Solicite los productos: use las clases SKProductRequest y SKProductRequestDelegate para emitir una solicitud de ID de producto y recibirlos de nuevo desde su propia tienda de itunesconnect.
Estos SKProducts deben utilizarse para completar la interfaz de usuario de su tienda que el usuario puede usar para comprar un producto específico.
2 - Emisión de solicitud de pago: use SKPayment y SKPaymentQueue para agregar el pago a la cola de transacciones.
3 - Supervise la cola de transacciones para la actualización de estado: use el método de Transacciones actualizadas del Protocolo SKPaymentTransactionObserver para monitorear el estado:
SKPaymentTransactionStatePurchasing - don''t do anything
SKPaymentTransactionStatePurchased - unlock product, finish the transaction
SKPaymentTransactionStateFailed - show error, finish the transaction
SKPaymentTransactionStateRestored - unlock product, finish the transaction
4 - Restaurar el flujo de botones: use restorePompletedTransactions de SKPaymentQueue para lograr esto: el paso 3 se ocupará del resto, junto con los siguientes métodos de SKPaymentTransactionObserver:
paymentQueueRestoreCompletedTransactionsFinished
restoreCompletedTransactionsFailedWithError
Here hay un tutorial paso a paso (escrito por mí como resultado de mis propios intentos de entenderlo) que lo explica. Al final, también proporciona un ejemplo de código que puede utilizar directamente.
Here hay otro que creé para explicar ciertas cosas que solo el texto podría describir de mejor manera.
Simplemente traduce el código Jojodmo a Swift:
class InAppPurchaseManager: NSObject , SKProductsRequestDelegate, SKPaymentTransactionObserver{
//If you have more than one in-app purchase, you can define both of
//of them here. So, for example, you could define both kRemoveAdsProductIdentifier
//and kBuyCurrencyProductIdentifier with their respective product ids
//
//for this example, we will only use one product
let kRemoveAdsProductIdentifier = "put your product id (the one that we just made in iTunesConnect) in here"
@IBAction func tapsRemoveAds() {
NSLog("User requests to remove ads")
if SKPaymentQueue.canMakePayments() {
NSLog("User can make payments")
//If you have more than one in-app purchase, and would like
//to have the user purchase a different product, simply define
//another function and replace kRemoveAdsProductIdentifier with
//the identifier for the other product
let set : Set<String> = [kRemoveAdsProductIdentifier]
let productsRequest = SKProductsRequest(productIdentifiers: set)
productsRequest.delegate = self
productsRequest.start()
}
else {
NSLog("User cannot make payments due to parental controls")
//this is called the user cannot make payments, most likely due to parental controls
}
}
func purchase(product : SKProduct) {
let payment = SKPayment(product: product)
SKPaymentQueue.defaultQueue().addTransactionObserver(self)
SKPaymentQueue.defaultQueue().addPayment(payment)
}
func restore() {
//this is called when the user restores purchases, you should hook this up to a button
SKPaymentQueue.defaultQueue().addTransactionObserver(self)
SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
}
func doRemoveAds() {
//TODO: implement
}
/////////////////////////////////////////////////
//////////////// store delegate /////////////////
/////////////////////////////////////////////////
// MARK: - store delegate -
func productsRequest(request: SKProductsRequest, didReceiveResponse response: SKProductsResponse) {
if let validProduct = response.products.first {
NSLog("Products Available!")
self.purchase(validProduct)
}
else {
NSLog("No products available")
//this is called if your product id is not valid, this shouldn''t be called unless that happens.
}
}
func paymentQueueRestoreCompletedTransactionsFinished(queue: SKPaymentQueue) {
NSLog("received restored transactions: /(queue.transactions.count)")
for transaction in queue.transactions {
if transaction.transactionState == .Restored {
//called when the user successfully restores a purchase
NSLog("Transaction state -> Restored")
//if you have more than one in-app purchase product,
//you restore the correct product for the identifier.
//For example, you could use
//if(productID == kRemoveAdsProductIdentifier)
//to get the product identifier for the
//restored purchases, you can use
//
//NSString *productID = transaction.payment.productIdentifier;
self.doRemoveAds()
SKPaymentQueue.defaultQueue().finishTransaction(transaction)
break;
}
}
}
func paymentQueue(queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
switch transaction.transactionState {
case .Purchasing: NSLog("Transaction state -> Purchasing")
//called when the user is in the process of purchasing, do not add any of your own code here.
case .Purchased:
//this is called when the user has successfully purchased the package (Cha-Ching!)
self.doRemoveAds() //you can add your code for what you want to happen when the user buys the purchase here, for this tutorial we use removing ads
SKPaymentQueue.defaultQueue().finishTransaction(transaction)
NSLog("Transaction state -> Purchased")
case .Restored:
NSLog("Transaction state -> Restored")
//add the same code as you did from SKPaymentTransactionStatePurchased here
SKPaymentQueue.defaultQueue().finishTransaction(transaction)
case .Failed:
//called when the transaction does not finish
if transaction.error?.code == SKErrorPaymentCancelled {
NSLog("Transaction state -> Cancelled")
//the user cancelled the payment ;(
}
SKPaymentQueue.defaultQueue().finishTransaction(transaction)
case .Deferred:
// The transaction is in the queue, but its final status is pending external action.
NSLog("Transaction state -> Deferred")
}
}
}
}
RMStore es una biblioteca liviana de iOS para compras dentro de la aplicación. Envuelve la API de StoreKit y le proporciona bloques prácticos para solicitudes asíncronas. Comprar un producto es tan fácil como llamar a un solo método.
Para los usuarios avanzados, esta biblioteca también proporciona verificación de recibos, descargas de contenido y persistencia de transacciones.
La mejor manera de hacer que una compra en la aplicación funcione para iOS 10
(y iOS 9, 8 and 7
) en Xcode 5+ es hacer lo siguiente:
- Vaya a itunes.connect.apple.com e inicie sesión
- Haga clic en
My Apps
luego haga clic en la aplicación que desea agregar la compra a - Haga clic en el encabezado
Features
y luego seleccioneIn-App Purchases
a la izquierda. - Haga clic en el icono
+
en el centro - Para este tutorial, vamos a agregar una compra dentro de la aplicación para eliminar los anuncios, así que elija
non-consumable
. Si fuera a enviar un artículo físico al usuario, o si le da algo que pueda comprar más de una vez, elegiríaconsumable
. - Para el nombre de referencia, ponga lo que quiera (pero asegúrese de saber cuál es)
- Para la identificación del producto,
tld.websitename.appname.referencename
esto funcionará mejor, así que, por ejemplo, podría usarcom.jojodmo.blix.removeads
- Elija
cleared for sale
y luego elija nivel de precio como 1 (99 ¢). El nivel 2 sería de $ 1.99, y el nivel 3 sería de $ 2.99. La lista completa está disponible si hace clic enview pricing matrix
Le recomiendo que utilice el nivel 1, ya que generalmente es lo más que alguien pagará para eliminar los anuncios. - Haga clic en el botón azul para
add language
e ingrese la información. Todo esto se mostrará al cliente, así que no ponga nada que no quiera que vean. - Para
hosting content with Apple
elige no - Puede dejar las notas de revisión en blanco POR AHORA .
- Omita la
screenshot for review
PARA AHORA , todo lo que omitamos volveremos a. - Clic en Guardar''
La identificación de su producto puede tardar algunas horas en registrarse en iTunesConnect
, así que tenga paciencia.
Ahora que ha configurado la información de compra en la aplicación en iTunesConnect, ingrese a su proyecto Xcode y diríjase al administrador de aplicaciones (el ícono en forma de página azul en la parte superior donde se encuentran sus métodos y archivos de encabezado) haga clic en su aplicación debajo de los objetivos (debe ser el primero) luego ve a general. En la parte inferior, debería ver linked frameworks and libraries
haga clic en el pequeño símbolo más y agregue el marco StoreKit.framework
Si no hace esto, la compra en la aplicación NO funcionará!
Si está utilizando Objective-C como el idioma de su aplicación, puede omitir estos cinco pasos. De lo contrario, si está utilizando Swift, haga lo siguiente:
Cree un nuevo archivo
.h
(encabezado) yendo aFile
>New
>File...
( Comando ⌘ + N ). Este archivo se denominará "Su archivo.h
" en el resto del tutorial.Cuando se le solicite, haga clic en Crear encabezado de puente . Este será nuestro archivo de cabecera puente. Si no se le solicita, vaya al paso 3. Si se le solicita, omita el paso 3 y vaya directamente al paso 4.
Cree otro archivo
.h
llamadoBridge.h
en la carpeta principal del proyecto. Luego, vaya al Administrador de aplicaciones (el ícono azul de la página), seleccione su aplicación en la sección deTargets
y haga clic enBuild Settings
. Busque la opción que dice Swift Compiler - Code Generation y luego configure la opción de encabezado de puente de Objective-C enBridge.h
En su archivo de encabezado puente, agregue la línea
#import "MyObjectiveCHeaderFile.h"
, dondeMyObjectiveCHeaderFile
es el nombre del archivo de encabezado que creó en el paso uno. Así, por ejemplo, si nombró su archivo de encabezado InAppPurchase.h , agregaría la línea#import "InAppPurchase.h"
a su archivo de encabezado de puente.Cree un nuevo archivo de Métodos de Objective-C (
.m
) yendo aFile
>New
>File...
( Comando ⌘ + N ). Asígnele el mismo nombre que el archivo de encabezado que creó en el paso 1. Por ejemplo, si llamó al archivo en el paso 1 InAppPurchase.h , llamaría a este nuevo archivo InAppPurchase.m . Este archivo se denominará "Su archivo.m
" en el resto del tutorial.
Ahora vamos a entrar en la codificación real. Agregue el siguiente código en su archivo .h
:
BOOL areAdsRemoved;
- (IBAction)restore;
- (IBAction)tapsRemoveAds;
A continuación, debe importar el marco de trabajo de StoreKit
a su archivo .m
, así como agregar SKProductsRequestDelegate
y SKPaymentTransactionObserver
después de su declaración @interface
:
#import <StoreKit/StoreKit.h>
//put the name of your view controller in place of MyViewController
@interface MyViewController() <SKProductsRequestDelegate, SKPaymentTransactionObserver>
@end
@implementation MyViewController //the name of your view controller (same as above)
//the code below will be added here
@end
y ahora agregue lo siguiente en su archivo .m
, esta parte se complica, así que sugiero que lea los comentarios en el código:
//If you have more than one in-app purchase, you can define both of
//of them here. So, for example, you could define both kRemoveAdsProductIdentifier
//and kBuyCurrencyProductIdentifier with their respective product ids
//
//for this example, we will only use one product
#define kRemoveAdsProductIdentifier @"put your product id (the one that we just made in iTunesConnect) in here"
- (IBAction)tapsRemoveAds{
NSLog(@"User requests to remove ads");
if([SKPaymentQueue canMakePayments]){
NSLog(@"User can make payments");
//If you have more than one in-app purchase, and would like
//to have the user purchase a different product, simply define
//another function and replace kRemoveAdsProductIdentifier with
//the identifier for the other product
SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:kRemoveAdsProductIdentifier]];
productsRequest.delegate = self;
[productsRequest start];
}
else{
NSLog(@"User cannot make payments due to parental controls");
//this is called the user cannot make payments, most likely due to parental controls
}
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
SKProduct *validProduct = nil;
int count = [response.products count];
if(count > 0){
validProduct = [response.products objectAtIndex:0];
NSLog(@"Products Available!");
[self purchase:validProduct];
}
else if(!validProduct){
NSLog(@"No products available");
//this is called if your product id is not valid, this shouldn''t be called unless that happens.
}
}
- (void)purchase:(SKProduct *)product{
SKPayment *payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
- (IBAction) restore{
//this is called when the user restores purchases, you should hook this up to a button
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
- (void) paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{
NSLog(@"received restored transactions: %i", queue.transactions.count);
for(SKPaymentTransaction *transaction in queue.transactions){
if(transaction.transactionState == SKPaymentTransactionStateRestored){
//called when the user successfully restores a purchase
NSLog(@"Transaction state -> Restored");
//if you have more than one in-app purchase product,
//you restore the correct product for the identifier.
//For example, you could use
//if(productID == kRemoveAdsProductIdentifier)
//to get the product identifier for the
//restored purchases, you can use
//
//NSString *productID = transaction.payment.productIdentifier;
[self doRemoveAds];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
}
}
}
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
for(SKPaymentTransaction *transaction in transactions){
//if you have multiple in app purchases in your app,
//you can get the product identifier of this transaction
//by using transaction.payment.productIdentifier
//
//then, check the identifier against the product IDs
//that you have defined to check which product the user
//just purchased
switch(transaction.transactionState){
case SKPaymentTransactionStatePurchasing: NSLog(@"Transaction state -> Purchasing");
//called when the user is in the process of purchasing, do not add any of your own code here.
break;
case SKPaymentTransactionStatePurchased:
//this is called when the user has successfully purchased the package (Cha-Ching!)
[self doRemoveAds]; //you can add your code for what you want to happen when the user buys the purchase here, for this tutorial we use removing ads
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
NSLog(@"Transaction state -> Purchased");
break;
case SKPaymentTransactionStateRestored:
NSLog(@"Transaction state -> Restored");
//add the same code as you did from SKPaymentTransactionStatePurchased here
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
//called when the transaction does not finish
if(transaction.error.code == SKErrorPaymentCancelled){
NSLog(@"Transaction state -> Cancelled");
//the user cancelled the payment ;(
}
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
}
}
}
Ahora desea agregar su código para lo que sucederá cuando el usuario finalice la transacción. Para este tutorial, usamos la eliminación de adiciones, tendrá que agregar su propio código para lo que sucede cuando se carga la vista de banner.
- (void)doRemoveAds{
ADBannerView *banner;
[banner setAlpha:0];
areAdsRemoved = YES;
removeAdsButton.hidden = YES;
removeAdsButton.enabled = NO;
[[NSUserDefaults standardUserDefaults] setBool:areAdsRemoved forKey:@"areAdsRemoved"];
//use NSUserDefaults so that you can load whether or not they bought it
//it would be better to use KeyChain access, or something more secure
//to store the user data, because NSUserDefaults can be changed.
//You''re average downloader won''t be able to change it very easily, but
//it''s still best to use something more secure than NSUserDefaults.
//For the purpose of this tutorial, though, we''re going to use NSUserDefaults
[[NSUserDefaults standardUserDefaults] synchronize];
}
Si no tiene anuncios en su aplicación, puede usar cualquier otra cosa que desee. Por ejemplo, podríamos hacer que el color del fondo sea azul. Para ello nos gustaría utilizar:
- (void)doRemoveAds{
[self.view setBackgroundColor:[UIColor blueColor]];
areAdsRemoved = YES
//set the bool for whether or not they purchased it to YES, you could use your own boolean here, but you would have to declare it in your .h file
[[NSUserDefaults standardUserDefaults] setBool:areAdsRemoved forKey:@"areAdsRemoved"];
//use NSUserDefaults so that you can load wether or not they bought it
[[NSUserDefaults standardUserDefaults] synchronize];
}
Ahora, en algún lugar de su método viewDidLoad
, querrá agregar el siguiente código:
areAdsRemoved = [[NSUserDefaults standardUserDefaults] boolForKey:@"areAdsRemoved"];
[[NSUserDefaults standardUserDefaults] synchronize];
//this will load wether or not they bought the in-app purchase
if(areAdsRemoved){
[self.view setBackgroundColor:[UIColor blueColor]];
//if they did buy it, set the background to blue, if your using the code above to set the background to blue, if your removing ads, your going to have to make your own code here
}
Ahora que ha agregado todo el código, vaya a su archivo .xib
o storyboard
, y agregue dos botones, uno que dice "comprar" y el otro que dice "restaurar". tapsRemoveAds
los tapsRemoveAds
IBAction
al botón de compra que acaba de realizar y restore
IBAction
al botón de restauración. La acción de restore
verificará si el usuario ha comprado previamente la compra en la aplicación, y le dará la compra en la aplicación de forma gratuita si aún no la tiene.
Luego, ingrese a iTunesConnect , y haga clic en Users and Roles
luego haga clic en el encabezado de Sandbox Testers
, y luego haga clic en el símbolo +
a la izquierda donde dice Testers
. Solo puede poner cosas al azar para el nombre y el apellido, y el correo electrónico no tiene que ser real, solo debe ser capaz de recordarlo. Introduzca una contraseña (que tendrá que recordar) y complete el resto de la información. Le recomendaría que haga de la Date of Birth
una fecha que haga que el usuario tenga 18 años o más. App Store Territory
TIENE que estar en el país correcto. A continuación, cierre sesión en su cuenta de iTunes existente (puede volver a iniciar sesión después de este tutorial).
Ahora, ejecute su aplicación en su dispositivo iOS, si intenta ejecutarla en el simulador, la compra siempre tendrá un error, TIENE QUE ejecutarla en su dispositivo iOS. Una vez que se ejecuta la aplicación, toque el botón de compra. Cuando se le solicite iniciar sesión en su cuenta de iTunes, inicie sesión como el usuario de prueba que acabamos de crear. A continuación, cuando se le solicite que confirme la compra de 99 ¢ o lo que sea que establezca también el nivel de precio, HAGA UNA PANTALLA DE LA PANTALLA. Esto es lo que va a usar para su screenshot for review
en iTunesConnect. Ahora cancela el pago.
Ahora, vaya a iTunesConnect , luego vaya a My Apps
> the app you have the In-app purchase on
> In-App Purchases
. Luego haga clic en su compra en la aplicación y haga clic en editar bajo los detalles de compra en la aplicación. Una vez que haya hecho eso, importe la foto que acaba de tomar en su iPhone a su computadora, y cárguela como captura de pantalla para revisar, luego, en las notas de revisión, coloque el correo electrónico y la contraseña de USUARIO . Esto ayudará a Apple en el proceso de revisión.
Después de hacer esto, vuelva a la aplicación en su dispositivo iOS, aún inicie sesión como la cuenta de usuario de prueba y haga clic en el botón de compra. Esta vez, confirme el pago No se preocupe, esto NO le cobrará NINGUNA cuenta, las cuentas de usuario de prueba obtienen todas las compras en la aplicación de forma gratuita Una vez que haya confirmado el pago, asegúrese de que lo que sucede cuando el usuario compra su producto realmente sucede Si no es así, será un error con su método doRemoveAds
. Una vez más, recomiendo cambiar el fondo a azul para probar la compra desde la aplicación, aunque esta no debería ser su compra real dentro de la aplicación. Si todo funciona y eres bueno para irte! ¡Solo asegúrese de incluir la compra en la aplicación en su nuevo binario cuando lo cargue en iTunesConnect!
Aquí hay algunos errores comunes:
Registrado: No Products Available
Esto podría significar tres cosas:
- No colocó el ID de compra correcto en la aplicación en su código (para el identificador
kRemoveAdsProductIdentifier
en el código anterior) - No borró su compra en la aplicación para la venta en iTunesConnect
- No esperó a que el ID de compra en la aplicación se registrara en iTunesConnect . Espere un par de horas desde la creación de la ID, y su problema debe resolverse.
- No completó el llenado de su información de Acuerdos, Impuestos y Banca.
Si no funciona la primera vez, ¡no te sientas frustrado! ¡No te rindas! Me tomó aproximadamente 5 horas seguidas antes de que pudiera hacer que esto funcionara, y aproximadamente 10 horas buscando el código correcto. Si usa el código de arriba exactamente, debería funcionar bien. Siéntase libre de comentar si tiene alguna pregunta en absoluto .
Espero que esto ayude a todos aquellos que esperan agregar una compra desde la aplicación a su aplicación iOS. ¡Aclamaciones!