---
title: "Activar compras usando paywalls en el SDK de iOS"
description: "Guía de inicio rápido para configurar Adapty en la gestión de suscripciones in-app."
---

Para activar las compras in-app, necesitas entender tres conceptos clave:

- [**Productos**](product) – cualquier cosa que los usuarios pueden comprar (suscripciones, consumibles, acceso de por vida)
- [**Paywalls**](paywalls): configuraciones que definen qué productos ofrecer. En Adapty, los paywalls son la única manera de recuperar productos, pero este diseño te permite modificar ofertas, precios y combinaciones de productos sin tocar el código de tu app.
- [**Placements**](placements) – dónde y cuándo muestras los paywalls en tu app (como `main`, `onboarding`, `settings`). Configuras los paywalls para los placements en el dashboard y luego los solicitas por ID de placement en tu código. Esto facilita ejecutar pruebas A/B y mostrar distintos paywalls a diferentes usuarios.

Adapty te ofrece tres formas de activar las compras en tu app. Elige la que mejor se adapte a los requisitos de tu aplicación:

| Implementación             | Complejidad | Cuándo usar                                                                                                                                                                                                                                         |
|----------------------------|-------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Adapty Paywall Builder     | ✅ Fácil    | [Creas un paywall completo y listo para compras en el editor sin código](quickstart-paywalls). Adapty lo renderiza automáticamente y gestiona todo el flujo de compra, la validación de recibos y la gestión de suscripciones de forma transparente. |
| Paywalls creados manualmente | 🟡 Medio   | Implementas la UI del paywall en el código de tu app, pero aun así obtienes el objeto paywall desde Adapty para mantener flexibilidad en las ofertas de productos. Consulta la [guía](ios-quickstart-manual).                                        |
| Modo observador            | 🔴 Difícil  | Ya tienes tu propia infraestructura de gestión de compras y quieres seguir usándola. Ten en cuenta que el modo observador tiene sus limitaciones en Adapty. Consulta el [artículo](observer-vs-full-mode).                                           |

:::important
**Los pasos a continuación muestran cómo implementar un paywall creado en el Paywall Builder de Adapty.**

Si no quieres usar el Paywall Builder, consulta la [guía para gestionar compras en paywalls creados manualmente](making-purchases).
:::

Para mostrar un paywall creado en el Paywall Builder de Adapty, solo necesitas hacer lo siguiente en el código de tu app:

1. **Obtener el paywall**: Obtén el paywall desde Adapty.
2. **Mostrar el paywall y Adapty gestionará las compras por ti**: Muestra el contenedor del paywall que obtuviste en tu app.
3. **Gestionar las acciones de los botones**: Asocia las interacciones del usuario con el paywall a la respuesta de tu app. Por ejemplo, abre enlaces o cierra el paywall cuando los usuarios pulsen botones.

## Antes de empezar \{#before-you-start\}

Antes de comenzar, completa estos pasos:

1. [Conecta tu app al App Store](initial_ios) en el Adapty Dashboard.
2. [Crea tus productos](create-product) en Adapty.
3. [Crea un paywall y añade productos](create-paywall).
4. [Crea un placement y añade tu paywall](create-placement).
5. [Instala y activa el SDK de Adapty](sdk-installation-ios) en el código de tu app.

:::tip
La forma más rápida de completar estos pasos es seguir la [guía de inicio rápido](quickstart) o crear paywalls y placements usando la [CLI para desarrolladores](developer-cli-quickstart).
:::

## 1. Obtener el paywall creado en el Paywall Builder \{#1-get-the-paywall-created-in-the-paywall-builder\}

Tus paywalls están asociados a placements configurados en el dashboard. Los placements te permiten mostrar distintos paywalls a diferentes audiencias o ejecutar [pruebas A/B](ab-tests).

Para obtener un paywall creado en el Paywall Builder de Adapty, debes:

1. Obtener el objeto `paywall` por el ID de [placement](placements) usando el método `getPaywall` y comprobar si es un paywall creado en el builder.

2. Obtener la configuración de vista del paywall usando el método `getPaywallConfiguration`. La configuración de vista contiene los elementos de UI y el estilo necesarios para mostrar el paywall.

:::important
Para obtener la configuración de vista, debes activar el toggle **Show on device** en el Paywall Builder. De lo contrario, obtendrás una configuración de vista vacía y el paywall no se mostrará.
:::

```swift

func loadPaywall() async {
let paywall = try await Adapty.getPaywall("YOUR_PLACEMENT_ID")

    guard paywall.hasViewConfiguration else {
        print("Paywall doesn't have view configuration")
        return
    }
    
    paywallConfiguration = try await AdaptyUI.getPaywallConfiguration(forPaywall: paywall)
}
```

## 2. Mostrar el paywall \{#2-display-the-paywall\}

Ahora que tienes la configuración del paywall, basta con añadir unas pocas líneas para mostrarlo.

<Tabs groupId="current-os" queryString>

<TabItem value="swiftui" label="SwiftUI" default>

En SwiftUI, al mostrar el paywall también necesitas gestionar eventos. Algunos son opcionales, pero `didFailPurchase`, `didFinishRestore`, `didFailRestore` y `didFailRendering` son obligatorios. Para hacer pruebas, puedes copiar el código del fragmento de abajo para registrar estos errores.

:::tip
Gestionar `didFinishPurchase` no es obligatorio, pero es útil cuando quieres realizar acciones tras una compra exitosa. Si no implementas ese callback, el paywall se cerrará automáticamente.
:::

```swift
.paywall(
    isPresented: $paywallPresented,
    paywallConfiguration: paywallConfiguration,
    didFailPurchase: { product, error in
        print("Purchase failed: \(error)")
    },
    didFinishRestore: { profile in
        print("Restore finished successfully")
    },
    didFailRestore: { error in
        print("Restore failed: \(error)")
    },
    didFailRendering: { error in
        paywallPresented = false
        print("Rendering failed: \(error)")
    },
    showAlertItem: $alertItem
)
```
</TabItem>

<TabItem value="uikit" label="UIKit" default>

```swift

func presentPaywall(with config: AdaptyUI.PaywallConfiguration) {
    let paywallController = AdaptyUI.paywallController(
        with: config,
        delegate: self
    )
    
    present(paywallController, animated: true)
}

```
</TabItem>
</Tabs>

:::info
Para más detalles sobre cómo mostrar un paywall, consulta nuestra [guía](ios-present-paywalls).
:::

## 3. Gestionar las acciones de los botones \{#3-handle-button-actions\}

Cuando los usuarios pulsan botones en el paywall, el SDK de iOS gestiona automáticamente las compras, la restauración, el cierre del paywall y la apertura de enlaces.

Sin embargo, otros botones tienen IDs personalizados o predefinidos y requieren gestionar las acciones en tu código. O puede que quieras sobreescribir su comportamiento predeterminado.

Por ejemplo, aquí se muestra el comportamiento predeterminado del botón de cierre. No necesitas añadirlo al código, pero aquí puedes ver cómo hacerlo si fuera necesario.

:::tip
Lee nuestras guías sobre cómo gestionar [acciones](handle-paywall-actions) y [eventos](ios-handling-events) de botones.
:::

<Tabs groupId="current-os" queryString>

<TabItem value="swiftui" label="SwiftUI" default>

```swift

didPerformAction: { action in
    switch action {
        case let .close:
            paywallPresented = false // default behavior
        default:
            break
    }
}
```
</TabItem>

<TabItem value="uikit" label="UIKit" default>

```swift
func paywallController(_ controller: AdaptyPaywallController,
                       didPerform action: AdaptyUI.Action) {
    switch action {
        case let .close:
            controller.dismiss(animated: true) // default behavior
        break
    }
}
```
</TabItem>
</Tabs>

## Próximos pasos \{#next-steps\}

---
no_index: true
---
import Callout from '../../../components/Callout.astro';

<Callout type="tip">
¿Tienes preguntas o estás teniendo algún problema? Consulta nuestro [foro de soporte](https://adapty.featurebase.app/) donde encontrarás respuestas a preguntas frecuentes o podrás plantear las tuyas. ¡Nuestro equipo y la comunidad están aquí para ayudarte!
</Callout>

Tu paywall está listo para mostrarse en la app. [Prueba tus compras en modo sandbox](test-purchases-in-sandbox) para asegurarte de que puedes completar una compra de prueba desde el paywall.

Ahora necesitas [comprobar el nivel de acceso de los usuarios](ios-check-subscription-status) para asegurarte de mostrar un paywall o dar acceso a las funciones de pago a los usuarios correctos.

## Ejemplo completo \{#full-example\}

Aquí puedes ver cómo integrar todos los pasos de esta guía en tu app.

<Tabs groupId="current-os" queryString>

<TabItem value="swiftui" label="SwiftUI" default>

```swift

struct ContentView: View {
  @State private var paywallPresented = false
  @State private var alertItem: AlertItem?
  @State private var paywallConfiguration: AdaptyUI.PaywallConfiguration?
  @State private var isLoading = false
  @State private var hasInitialized = false
  
  var body: some View {
    VStack {
      if isLoading {
        ProgressView("Loading...")
      } else {
        Text("Your App Content")
      }
    }
    .task {
      guard !hasInitialized else { return }
      await initializePaywall()
      hasInitialized = true
    }
    .paywall(
      isPresented: $paywallPresented,
      configuration: paywallConfiguration,
      didPerformAction: { action in
        switch action.type {
          case let .close:
              paywallPresented = false
          default:
              break
        }
      },
      didFailPurchase: { product, error in
        print("Purchase failed: \(error)")
      },
      didFinishRestore: { profile in
        print("Restore finished successfully")
      },
      didFailRestore: { error in
        print("Restore failed: \(error)")
      },
      didFailRendering: { error in
        print("Rendering failed: \(error)")
      },
      showAlertItem: $alertItem
    )
  }
  
  private func initializePaywall() async {
    isLoading = true
    defer { isLoading = false }
    
    await loadPaywall()
    paywallPresented = true
    }
  }
  
  private func loadPaywall() async {
    do {
      let paywall = try await Adapty.getPaywall("YOUR_PLACEMENT_ID")
      guard paywall.hasViewConfiguration else {
        print("Paywall doesn't have view configuration")
        return
      }
      paywallConfiguration = try await AdaptyUI.getPaywallConfiguration(forPaywall: paywall)
    } catch {
      print("Failed to load paywall: \(error)")
    }
  }
}

```
</TabItem>

<TabItem value="uikit" label="UIKit" default>

```swift

class ViewController: UIViewController {
  private var paywallConfiguration: AdaptyUI.PaywallConfiguration?
  
  override func viewDidLoad() {
    super.viewDidLoad()
    
    Task {
      await initializePaywall()
    }
  }
  
  private func initializePaywall() async {
    do {
      paywallConfiguration = try await loadPaywall()
            
      if let paywallConfiguration {
        await MainActor.run {
          presentPaywall(with: paywallConfiguration)
        }
      }
    } catch {
      print("Error initializing paywall: \(error)")
    }
  }
  
  private func loadPaywall() async throws -> AdaptyUI.PaywallConfiguration? {
    let paywall = try await Adapty.getPaywall("YOUR_PLACEMENT_ID")
    
    guard paywall.hasViewConfiguration else {
      print("Paywall doesn't have view configuration")
      return nil
    }
    
    return try await AdaptyUI.getPaywallConfiguration(forPaywall: paywall)
  }
  
  private func presentPaywall(with config: AdaptyUI.PaywallConfiguration) {
    let paywallController = AdaptyUI.paywallController(with: config, delegate: self)
    present(paywallController, animated: true)
  }
}

// MARK: - AdaptyPaywallControllerDelegate

extension ViewController: AdaptyPaywallControllerDelegate {
  func paywallController(_ controller: AdaptyPaywallController,
                       didPerform action: AdaptyUI.Action) {
    switch action {
        case let .close:
            controller.dismiss(animated: true)
        break
    }
 }
  
  func paywallController(_ controller: AdaptyUI.PaywallController,
                         didFailPurchase product: AdaptyPaywallProduct,
                         error: AdaptyError) {
    print("Purchase failed for \(product.vendorProductId): \(error)")
    
    guard error.adaptyErrorCode != .paymentCancelled else {
      return // Don't show alert for user cancellation
    }
    
    let message = switch error.adaptyErrorCode {
      case .paymentNotAllowed:
        "Purchases are not allowed on this device."
      default:
        "Purchase failed. Please try again."
    }
    
    let alert = UIAlertController(title: "Purchase Error", message: message, preferredStyle: .alert)
    let okAction = UIAlertAction(title: "OK", style: .default) { _ in }
    alert.addAction(okAction)
    present(alert, animated: true)
  }
  
  func paywallController(_ controller: AdaptyUI.PaywallController,
                         didFinishRestore profile: AdaptyProfile) {
    print("Restore finished successfully")
    controller.dismiss(animated: true)
  }
  
  func paywallController(_ controller: AdaptyUI.PaywallController,
                         didFailRestore error: AdaptyError) {
    print("Restore failed: \(error)")
  }
  
  func paywallController(_ controller: AdaptyUI.PaywallController,
                         didFailRendering error: AdaptyError) {
    print("Rendering failed: \(error)")
    controller.dismiss(animated: true)
  }
}

```
</TabItem>
</Tabs>