Saltar a contenido

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)
    }
}

Referencias