> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fintoc.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Integración con WebView

> Referencia para integrar el Widget como un WebView en tu aplicación móvil

Incorpora el Widget de Fintoc dentro de tu aplicación iOS o Android usando un WebView nativo, configurado a través de parámetros de query en la URL.

## Integración

Para integrar el Widget mediante un WebView en iOS y Android, carga la siguiente URL:

```text theme={null}
https://webview.fintoc.com/widget.html
```

La configuración del widget se debe pasar a través de un query string en lugar de usar JavaScript del lado del cliente.

<Info>
  **¿Usas React Native?**

  ¡Revisa nuestra librería de npm [`@fintoc/fintoc-react-native`](https://github.com/fintoc-com/fintoc-react-native) para integrar el WebView a tu aplicación rápidamente!
</Info>

## Cómo funciona

Al incluir el WebView de Fintoc en tu aplicación móvil, debes pasar los siguientes query params para configurarlo, según el producto que quieras usar:

```text theme={null}
https://webview.fintoc.com/widget.html
  ?public_key=YOUR_PUBLIC_KEY
  &holder_type=individual
  &product=payments
  &country=cl
  &session_token=YOUR_SESSION_TOKEN
```

| Parámetro       | Tipo     | Descripción                                                                                                                                                                                                                                                                                   |
| --------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `public_key`    | `string` | Identificador de tu aplicación dentro de Fintoc. Fintoc asigna cada `Link` creado con la clave a la organización o usuario propietario de la clave.<br />La clave también determina el entorno. Las claves de sandbox comienzan con `pk_test_`, y las de producción comienzan con `pk_live_`. |
| `holder_type`   | `string` | Tipo de cuenta que se conectará a Fintoc. Uno de `business` o `individual`. No es necesario si `product` es `payments` (Payment Initiation).                                                                                                                                                  |
| `product`       | `string` | Producto y tipo de `Link` que se creará. Uno de `movements`, `subscriptions`, `invoices` o `payments`.                                                                                                                                                                                        |
| `country`       | `string` | Código ISO 3166-1 alfa-2 en minúsculas del país al que te conectas. Uno de `cl` o `mx`. Por defecto es `cl`. No es necesario si `product` es `payments` (Payment Initiation).                                                                                                                 |
| `webhook_url`   | `string` | URL que recibe una solicitud después de que Fintoc crea un `Link`. La solicitud incluye el `link_token` del objeto `Link`. Solo los productos `movements` e `invoices` usan este parámetro.                                                                                                   |
| `session_token` | `string` | Token que tu backend crea con una [Checkout Session](/es/api/payments-api/checkout-sessions/checkout-sessions-create). El Widget usa `session_token` para cargar y configurar el flujo de pago. Solo el producto `payments` usa este parámetro.                                               |
| `widget_token`  | `string` | Token que tu backend crea para inicializar y configurar el Widget para el producto `subscriptions`.                                                                                                                                                                                           |
| `link_token`    | `string` | Identificador de un `Link` existente. Inclúyelo para configurar el Widget para un `Link` ya creado con el producto `movements`.                                                                                                                                                               |

También puedes construir el query string por separado antes de añadirlo a la URL del WebView:

```text theme={null}
public_key=YOUR_PUBLIC_KEY&holder_type=individual&product=movements&country=cl&link_token=YOUR_LINK_TOKEN
```

## Ejemplo de uso

Los siguientes snippets muestran la configuración del WebView en Android y iOS:

```kotlin theme={null}
override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  setContentView(R.layout.activity_main)
  supportActionBar?.hide()

  val widgetInitializationUrl = generateWidgetInitializationUrl()

  // Modify WebView settings. Some settings may not be applicable
  // or necessary for your integration.
  val fintocWebview = findViewById<WebView>(R.id.webview)
  val webSettings = fintocWebview.settings
  webSettings.javaScriptEnabled = true
  webSettings.javaScriptCanOpenWindowsAutomatically = true
  webSettings.domStorageEnabled = true
  webSettings.cacheMode = WebSettings.LOAD_NO_CACHE
  webSettings.useWideViewPort = true

  fintocWebview.loadUrl(widgetInitializationUrl.toString())
}

private fun generateWidgetInitializationUrl(): Uri {
  val builder = Uri.parse("https://webview.fintoc.com/widget.html")
    .buildUpon()
    .appendQueryParameter("holder_type", "individual")
    .appendQueryParameter("product", "payments")
    .appendQueryParameter("public_key", "YOUR_PUBLIC_KEY")
    .appendQueryParameter("session_token", "YOUR_SESSION_TOKEN")
  return builder.build()
}
```

```swift theme={null}
import UIKit
import WebKit

class ViewController: UIViewController, WKNavigationDelegate, UIScrollViewDelegate, WKUIDelegate {

    private var webView: WKWebView!

    override func loadView() {
        let webConfiguration = WKWebViewConfiguration()
        webView = WKWebView(frame: .zero, configuration: webConfiguration)
        webView.uiDelegate = self
        view = webView
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        webView.navigationDelegate = self
        webView.allowsBackForwardNavigationGestures = false
        webView.scrollView.bounces = false
        webView.isMultipleTouchEnabled = false
        webView.configuration.preferences.javaScriptCanOpenWindowsAutomatically = true

        // Disable zoom.
        webView.scrollView.delegate = self
        webView.scrollView.minimumZoomScale = 1.0
        webView.scrollView.maximumZoomScale = 1.0

        let url = generateInitializationURL()
        webView.load(URLRequest(url: url))
    }

    override var prefersStatusBarHidden: Bool {
        return true
    }

    @objc(scrollViewWillBeginZooming:withView:) func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
        scrollView.pinchGestureRecognizer?.isEnabled = false
    }

    func webView(
        _ webView: WKWebView,
        createWebViewWith configuration: WKWebViewConfiguration,
        for navigationAction: WKNavigationAction,
        windowFeatures: WKWindowFeatures
    ) -> WKWebView? {
        guard navigationAction.targetFrame == nil,
              let url = navigationAction.request.url else { return nil }

        UIApplication.shared.open(url)
        return nil
    }

    func generateInitializationURL() -> URL {
        let params = [
            "holder_type": "individual",
            "product": "payments",
            "public_key": "YOUR_PUBLIC_KEY",
            "session_token": "YOUR_SESSION_TOKEN",
        ]
        var components = URLComponents()
        components.scheme = "https"
        components.host = "webview.fintoc.com"
        components.path = "/widget.html"
        let queryItems = params.map { URLQueryItem(name: $0, value: $1) }
        components.queryItems = queryItems
        return components.url!
    }

    func webView(
      _ webView: WKWebView,
      decidePolicyFor navigationAction: WKNavigationAction,
      decisionHandler: @escaping ((WKNavigationActionPolicy) -> Void)
    ) {
      guard let url = navigationAction.request.url else {
        decisionHandler(.allow)
        return
      }
      let linkScheme = "fintocwidget"
      let actionScheme = url.scheme
      let actionType = url.host ?? ""
      if actionScheme == linkScheme {
        switch actionType {
        case "succeeded":
          print("Succeeded")
        case "exit":
          print("Exited")
        case "event":
          print("Widget event detected: \(url)")
        default:
          print("Another widget action detected: \(actionType)")
        }
        decisionHandler(.cancel)
        return
      } else {
        decisionHandler(.allow)
      }
    }
}
```

Fíjate que el ejemplo en Swift tiene un método `webView`. Este método define lo que sucede cuando un usuario hace clic en un enlace dentro del WebView. En el ejemplo, el enlace se abre en Safari, pero puedes personalizar este comportamiento a tu gusto (los enlaces podrían abrirse dentro de la misma aplicación, por ejemplo). Esto es importante porque, al usar el producto de [Payment Initiation](/es/guides/payments/overview-payment-initiation), después de finalizar el flujo de pago el usuario puede hacer clic en un enlace para descargar el comprobante de la transacción. Permite que estos enlaces se abran para que el usuario pueda descargar el comprobante.

## Redirecciones del WebView

Una vez integrado el WebView, puedes interactuar con sus eventos usando redirecciones.

| Método      | URL de redirección                                     | Descripción                                                                                                                                                              |
| :---------- | :----------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `onSuccess` | `fintocwidget://succeeded`                             | Se dispara después de que el flujo finalice exitosamente.                                                                                                                |
| `onExit`    | `fintocwidget://exit`                                  | Se dispara después de que tu usuario cierre el Widget antes de finalizar.                                                                                                |
| `onEvent`   | `fintocwidget://event/{event_name}?queryparam={value}` | Se dispara para cada evento disponible en el Widget. Para más información sobre estos eventos, consulta [Eventos del Widget](/es/guides/resources/widget/widget-events). |

<Warning>
  **Maneja `onEvent` en un WebView**

  El WebView habilita `onEvent` por defecto. Maneja la redirección `fintocwidget://event/{event_name}` para que tu aplicación reciba los eventos del Widget.
</Warning>

Para usar estos métodos en Android e iOS, puedes usar los siguientes snippets:

```kotlin theme={null}
webview.webViewClient = object : WebViewClient() {
  override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
    val parsedUri = url?.let(Uri::parse) ?: return false
    if (parsedUri.scheme == "fintocwidget") {
      val action = parsedUri.host
      if (action == "succeeded") {
        // onSuccess
      }
      if (action == "exit") {
        // onExit
      }
      if (action == "event") {
        // onEvent
      }
      return true
    }
    return false
  }
}
```

```java theme={null}
webview.setWebViewClient(new WebViewClient() {
  public boolean shouldOverrideUrlLoading(WebView view, String url) {
    Uri parsedUri = Uri.parse(url);
    if ("fintocwidget".equals(parsedUri.getScheme())) {
      String action = parsedUri.getHost();
      if ("succeeded".equals(action)) {
        // onSuccess
      }
      if ("exit".equals(action)) {
        // onExit
      }
      if ("event".equals(action)) {
        // onEvent
      }
      return true;
    }
    return false;
  }
});
```

```swift theme={null}
func webView(
  _ webView: WKWebView,
  decidePolicyFor navigationAction: WKNavigationAction,
  decisionHandler: @escaping ((WKNavigationActionPolicy) -> Void)
) {
  guard let url = navigationAction.request.url else {
    decisionHandler(.allow)
    return
  }
  let linkScheme = "fintocwidget"
  let actionScheme = url.scheme
  let actionType = url.host ?? ""
  if actionScheme == linkScheme {
    switch actionType {
    case "succeeded":
      // onSuccess
      break
    case "exit":
      // onExit
      break
    case "event":
      // onEvent
      break
    default:
      print("Widget action detected: \(actionType)")
    }
    decisionHandler(.cancel)
    return
  } else {
    decisionHandler(.allow)
  }
}
```

<Warning>
  **Agrega el URL scheme `fintocwidget` en iOS**

  Antes de integrar el Widget de Fintoc con tu aplicación iOS, registra `fintocwidget` como un URL scheme en el archivo `Info.plist` de la aplicación. Esta configuración le permite a tu aplicación manejar las redirecciones del Widget.
</Warning>

```xml theme={null}
<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>fintocwidget</string>
    </array>
    <key>CFBundleURLName</key>
    <string>your.bundle.id</string>
  </dict>
</array>
```

## Prueba la integración

Carga el WebView con una `public_key` que empiece con `pk_test_` para ejecutar el flujo contra el entorno de sandbox. Completa el flujo con las [credenciales de prueba](/es/guides/resources/test-mode) de Fintoc y luego confirma que tu aplicación recibe la redirección `fintocwidget://succeeded`.
