Compras In-App¶
Conceptos de compras In-App¶
¿Qué es una compra In-App?¶
Permite vender directamente una funcionalidad dentro de una app.
Los datos de la compra (precio, identificador) se definen en iTunes Connect.
Se implementa con el API StoreKit:
- StoreKit pregunta al usuario si confirma la transacción a través del acceso seguro del App Store.
- La app recibe la confirmación de la compra y debe desbloquear dinámicamente la funcionalidad.
- La app debe guardar la información de que el usuario ha comprado esa nueva funcionalidad, aunque el usuario siempre puede recuperar la compra.
Ejemplos de uso¶
Las compras In-App son una de las formas de monetización más usadas en la actualidad
Por ejemplo:
- Podemos dar una versión básica gratuita y vender funcionalidades adicionales premium.
- Podemos permitir la suscripción a contenidos periódicos que se pueden descargar
- Ofertas de niveles adicionales en juegos
- Compras de mercancías virtuales en juegos on-line
Tipos de compras In-App - Compras¶
- No-consumibles
- Ítems que permanecen disponibles de forma indefinida en todos los dispositivos del usuario.
- Ejemplos: libros, niveles de un juego, funcionalidades premium de un app.
- Consumibles
- Ítems que se consumen durante el tipo de ejecución del app.
- Ejemplos: minutos de llamadas de voz sobre IP, o servicios de un sólo uso como transcripción de voz.
Tipos de compras In-App - Suscripciones¶
- Suscripciones auto-renovables
- Como los no-consumibles, las suscripciones permanecen disponibles en todos los dispositivos. Tienen una fecha de expiración, en la que el sistema renueva automáticamente la compra.
- Suscripciones no-renovables
- Suscripciones en las que no se entrega contenido periódico.
- Ejemplos: acceso a una base de datos de fotos históricas.
- Suele acompañarse de una cuenta de usuario en un servidor.
- La duración y la expiración de la suscripción se realizan desde la app (y el servidor).
Requisitos para activar las In-App¶
Las compras In-App sólo pueden probarse y activarse con una cuenta de desarrollador de pago.
Es necesario acceso a iTunes Connect para configurar las compras.
No es posible hacerlo con el equipo de la universidad.
Haremos una demo con una cuenta de desarrollador.
Contratos¶
¡Cuidado!: Para poder probar las compras In-App hay que tener todos los contratos en regla.
Servicios a activar en la app¶
Bundle identifier y App Id¶
Configuración In-App desde iTunes Connect¶
Datos del app¶
Pantalla para añadir nuevos In-Apps¶
Seleccionar el tipo de In-App¶
Características del In-App¶
- Nombre de referencia: aparece en la ventana de compra
- ID del producto: identificador del In-App para reconocerlo en el app
- Precio
- Datos para la revisión de Apple
Características del In-App¶
Usuarios de prueba¶
Para probar las compras In-App debemos crear usuarios de prueba de sandbox en iTunes Connect.
En el dispositivo de prueba hay que iniciar la sesión en el App Store con ese usuario de prueba.
Demo¶
Vamos a ver un ejemplo de aplicación que contiene una pantalla sorpresa cuyo acceso se activa con una compra In-App.
Está disponible en este enlace
Código para implementar las compras In-App¶
El proceso de compra en un vistazo¶
Debemos implementar los protocolos
SKProductsRequestDelegate
y
SKPaymentTransactionObserver
.
Clase auxiliar InApp¶
Creamos un protocolo InAppDelegate
y una clase InApp
donde
gestionaremos la interacción con StoreKit
:
import Foundation
import StoreKit
protocol InAppDelegate {
func compraRecibida()
}
class InApp: NSObject, SKProductsRequestDelegate, SKPaymentTransactionObserver {
var productDetailsList: [SKProduct] = []
var productIdentiferList: [String] = []
var delegate: InAppDelegate?
override init() {
super.init()
SKPaymentQueue.default().add(self)
// Cargamos la lista de productos
productIdentiferList.append("ejemplo3")
let request = SKProductsRequest.init(productIdentifiers: Set(productIdentiferList))
request.delegate = self
request.start()
}
// Método para lanzar la petición de compra al usuario
func lanzarPago() {
if (self.productDetailsList.count > 0 && SKPaymentQueue.canMakePayments()) {
let producto = productDetailsList[0]
let pago = SKPayment(product: producto)
SKPaymentQueue.default().add(pago)
print("Comprando...")
} else {
print("No existen productos")
}
}
// Método al que se llama cuando el usuario compra el InApp
func paymentQueue(_ queue: SKPaymentQueue,
updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
switch transaction.transactionState {
case .purchased:
print("Purchased")
delegate?.compraRecibida()
SKPaymentQueue.default().finishTransaction(transaction)
case .failed:
print("Failed")
print("Error de transacción: \(String(describing: transaction.error?.localizedDescription))")
SKPaymentQueue.default().finishTransaction(transaction)
case .restored:
print("Restored")
delegate?.compraRecibida()
SKPaymentQueue.default().finishTransaction(transaction)
default:
print("Otro")
}
}
}
// Método al que se llama cuando se han recibido los productos
func productsRequest(_ request: SKProductsRequest,
didReceive response: SKProductsResponse) {
print("Hemos recibido \(response.products.count) productos")
productDetailsList = response.products
for invalidProductId in response.invalidProductIdentifiers {
print("Producto invalido id: \(invalidProductId)")
}
}
}
Clase ViewController¶
En la clase ViewController
adoptamos nuestro protocolo
InAppDelegate
y definimos su método compraRecibida()
al que se va
a llamar cuando se haya recibido y validado la compra.
import UIKit
class ViewController: UIViewController, InAppDelegate {
@IBOutlet weak var botonSorpresa: UIButton!
let inApp = InApp()
override func viewDidLoad() {
// Actualizamos el delgado de inApp con la propia
// instacia, para que se llame al método compraRecibida
inApp.delegate = self
// Escondemos el botón sorpresa, que sólo estará visible
// para los que hagan la compra
botonSorpresa.isHidden = true
// Comprobamos si hemos comprado antes el inApp
if UserDefaults.standard.bool(forKey: "inAppComprado") {
botonSorpresa.isHidden = false
} else {
botonSorpresa.isHidden = true
}
super.viewDidLoad()
}
// Método del protocolo al que se va a llamar cuando se reciba
// la compra. Hacemos visible el botón sorpresa.
func compraRecibida() {
botonSorpresa.isHidden = false
}
// La acción asociada al botón de compra llama
// al método lanzarPago de la instancia de nuestra
// clase InApp
@IBAction func hazCompra(_ sender: UIButton) {
print("Click botón de compra")
inApp.lanzarPago()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// Acción para mostrar la pantalla sorpresa
@IBAction func sorpresa(_ sender: UIButton){
performSegue(withIdentifier: "Sorpresa", sender: view)
}
}