> For the complete documentation index, see [llms.txt](https://docs.payments.thalescloud.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.payments.thalescloud.io/nfc-wallet-sdk-android/es/additional-features/customize-ppse.md).

# Personalizar PPSE

## Resumen

Tal como se define en EMV Book B, el PPSE (Proximity Payment System Environment) es el punto de entrada para los pagos sin contacto. Cada tarjeta digital tiene su propio PPSE, definido en el perfil del token. Contiene la lista de identificadores de aplicación (AID) compatibles, con las etiquetas de aplicación y prioridades correspondientes.

NFC Wallet SDK proporciona **la API de gestión del PPSE.** Te permite que tu aplicación de billetera digital:

* Obtener el **PPSE** (PPSE predeterminado definido en el perfil de la tarjeta digital).
* Obtener el **PPSE auxiliar** (PPSE definido en el perfil auxiliar de la tarjeta digital para tarjetas de doble marca).
* Personalizar un nuevo PPSE (**PPSE personalizado**).
* Obtener o restablecer el **PPSE personalizado**.

NFC Wallet SDK usa el **PPSE personalizado** cuando está definido para una transacción sin contacto.

{% hint style="info" %}
Use **API de gestión del PPSE** para aplicar tu política en un programa de billetera digital de doble marca.

**NFC Wallet SDK** usa solo el **PPSE** o el **PPSE personalizado**. No usa el **PPSE auxiliar**.
{% endhint %}

## Integración del SDK

La **API de gestión del PPSE** incluye el `PpseFciTemplate` la clase y estas `DigitalizedCard` operaciones:

* `DigitalizedCard.getPpse()`: Obtiene el PPSE predeterminado definido en el perfil del token.
* `DigitalizedCard.getAuxiliaryPpse()`: Obtiene el PPSE definido en el perfil auxiliar de la tarjeta digital (tarjetas de doble marca).
* `DigitalizedCard.getCustomPpse()`: Obtiene el PPSE personalizado. Devuelve `null` si no está definido.
* `DigitalizedCard.setCustomPpse()`: Establece un PPSE personalizado. Pasa `null` para borrarlo.

{% hint style="warning" %}
El SDK valida automáticamente la plantilla PPSE cuando llamas a `DigitalCard.setCustomPPSE`.

Consulte [Reglas de validación](#validation-rules).
{% endhint %}

### Creación de un PPSE personalizado

Crea un PPSE personalizado con `PpseFciTemplate` de una de estas formas:

* Usa una plantilla PPSE existente.
* Usa bytes sin procesar del PPSE.
* Créalo desde cero.

#### Método 1: Crear PPSE a partir de una plantilla existente

Usa este enfoque cuando quieras comenzar con el PPSE de la tarjeta digital y hacer modificaciones específicas.

**Cuándo usarlo:**

* Quieres personalizar campos específicos del PPSE existente, como la prioridad o las etiquetas.
* Quieres conservar la estructura PPSE predeterminada mientras realizas cambios selectivos.
* Necesitas una plantilla base para la personalización.

{% code title="Establecer una plantilla PPSE personalizada" %}

```kotlin
try {
    // Obtener la plantilla PPSE principal.
    val ppse = card.getPpse()

    // Extraer las entradas del directorio.
    val directoryEntryList =
        ppse.proprietaryTemplate.issuerDiscretionaryData.directoryEntryList
    val targetAid = byteArrayOf(
        0xA0.toByte(),
        0x00.toByte(),
        0x00.toByte(),
        0x00.toByte(),
        0x03.toByte(),
        0x10.toByte(),
        0x10.toByte()
    )

    directoryEntryList.forEach { entry ->
        if (entry.applicationIdentifier.contentEquals(targetAid)) {
            entry.priority = byteArrayOf(0x02.toByte())
        }
    }

    // Guardar la plantilla actualizada.
    card.setCustomPpse(ppse)
} catch (e: InternalComponentException) {
    Log.d("PPSE", "Código de error: ${e.getmErrorCode()} Mensaje de error: ${e.message}")
}
```

{% endcode %}

#### Método 2: Crear PPSE a partir de bytes sin procesar

Usa este enfoque cuando ya tengas disponibles los datos completos de la respuesta PPSE en formato BER-TLV.

**Cuándo usarlo:**

* Ya tienes los datos completos de la respuesta PPSE como bytes sin procesar.

{% code title="Crear a partir de bytes sin procesar" %}

```kotlin
// Datos completos de la respuesta PPSE en formato BER-TLV
// Nota: .toByte() se usa para valores > 0x7F para gestionar el tipo byte con signo de Kotlin
val fciData = byteArrayOf(
    0x6F, 0x50, 0x84.toByte(), 0x0E, 0x32, 0x50, 0x41, 0x59, 0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46,
    0x30, 0x31, 0xA5.toByte(), 0x3E, 0xBF.toByte(), 0x0C, 0x3B, 0x61, 0x2F, 0x4F, 0x07, 0xA0.toByte(), 0x00, 0x00, 0x00, 0x03,
    0x10, 0x10, 0x50, 0x0B, 0x56, 0x69, 0x73, 0x61, 0x20, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74, 0x87.toByte(),
    0x01, 0x01, 0x9F.toByte(), 0x2A, 0x01, 0x03, 0x9F.toByte(), 0x0A, 0x04, 0x00, 0x01, 0x01, 0x02, 0xDF.toByte(),
    0x02, 0x03, 0x03, 0x04, 0x05, 0xDF.toByte(), 0x01, 0x02, 0x03, 0x04, 0x9F.toByte(), 0x02, 0x02, 0x01, 0x03,
    0x9F.toByte(), 0x01, 0x02, 0x01, 0x02
)

// Construir PpseFciTemplate a partir de bytes sin procesar
val template = PpseFciTemplate(fciData)

// Guardar el PPSE personalizado
try {
    digitalCard.setCustomPpse(template)
} catch (e: InternalComponentException) {
    Log.d("PPSE", "Código de error: ${e.getmErrorCode()} Mensaje de error: ${e.message}")
}
```

{% endcode %}

#### Método 3: Crear PPSE desde cero

Usa este enfoque cuando necesites construir una estructura PPSE de forma programática definiendo cada componente de manera individual.

**Cuándo usarlo:**

* Estás creando datos PPSE sin datos de bytes existentes.
* Necesitas definir las entradas del directorio, los AID, las etiquetas y otros componentes PPSE de forma programática.
* Quieres una construcción con seguridad de tipos y validación en tiempo de compilación.
* Prefieres objetos estructurados en lugar de bytes sin procesar.

`DigitalizedCard` expone la respuesta PPSE como `PpseFciTemplate`. Puedes crear tu propio `PpseFciTemplate`. El siguiente ejemplo muestra cómo crearlo.

{% code title="Crear desde cero usando PpseFciTemplate" %}

```kotlin
val dfName = byteArrayOf(
    0x32, 0x50, 0x41, 0x59, 0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46, 0x30, 0x31
)

// Crear entrada del directorio
val aid = byteArrayOf(0xA0.toByte(), 0x00, 0x00, 0x00, 0x03, 0x10, 0x10)
val label = byteArrayOf(0x56, 0x69, 0x73, 0x61, 0x20, 0x43, 0x72, 0x65, 0x64, 0x69, 0x74)
val kernelId = byteArrayOf(0x03)
val asrpd = byteArrayOf(0x00, 0x01, 0x01, 0x02)
val priority = byteArrayOf(0x01)
val entry = DirectoryEntry(aid, label, kernelId, asrpd, priority, null, HashMap())

val entries = arrayListOf(entry)

val issuerData = FciIssuerDiscretionaryData(entries, HashMap())
val proprietaryTemplate = FciProprietaryTemplate(issuerData)

// Crear la plantilla con parámetros explícitos
val template = PpseFciTemplate(dfName, proprietaryTemplate)

// Guardar el PPSE personalizado
try {
    digitalCard.setCustomPpse(template)
} catch (e: InternalComponentException) {
    Log.d("PPSE", "Código de error: ${e.getmErrorCode()} Mensaje de error: ${e.message}")
}
```

{% endcode %}

### Borrar un PPSE personalizado

Pasa `null` para eliminar el PPSE personalizado y restaurar la respuesta PPSE predeterminada.

{% code title="Borrar una plantilla PPSE personalizada" %}

```kotlin
try {
    card.setCustomPpse(null)
} catch (e: InternalComponentException) {
    Log.d("PPSE", "Código de error: ${e.getmErrorCode()} Mensaje de error: ${e.message}")
}
```

{% endcode %}

### Reglas de validación

NFC Wallet SDK valida el PPSE personalizado cuando llamas a `DigitalizedCard.setCustomPpse()`. Garantiza que el PPSE personalizado cumpla los requisitos de EMV y la codificación BER-TLV.

#### Límites de tamaño

* La carga útil BER-TLV serializada debe tener 256 bytes o menos.
* Las claves de etiquetas personalizadas dentro de `BF0C` o `61` no deben exceder 2 bytes.

#### Etiquetas requeridas

Tu `PpseFciTemplate` debe incluir:

1. Nombre DF — Etiqueta `84`
2. Al menos una entrada de directorio — Etiqueta `61` dentro de `BF0C`
3. Un identificador de aplicación en cada entrada de directorio — Etiqueta `4F`

Si la validación falla, el SDK lanza `InternalComponentException` con el código de error `ERROR_CODE_INVALID_PPSE_DATA`.

#### Restricciones de bloqueo de AID

Bloquear un AID con `LockStatus.LOCKED` solo es compatible con tarjetas Visa de una sola marca.

Si estableces `LockStatus.LOCKED` para una tarjeta no compatible, el SDK lanza `InternalComponentException`.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.payments.thalescloud.io/nfc-wallet-sdk-android/es/additional-features/customize-ppse.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
