Tocas la fila de VPN en Ajustes, ves un perfil que instaló otra persona y empiezas a buscar la llamada que añade uno. Esa llamada no existe. Una aplicación puede abrir un túnel propio mediante VpnService, pero las entradas de esa lista pertenecen a la plataforma y al cliente que las creó. Saber exactamente dónde está la línea te ahorra una semana persiguiendo clases ocultas.

Empieza por lo que muestra la pantalla de Ajustes

La lista de VPN es un registro de perfiles que instaló el sistema o un cliente del fabricante: PPTP, L2TP/IPsec, IKEv2 y las filas que haya empujado una aplicación OEM o un MDM. Cada fila lleva una dirección de servidor, credenciales y una implementación de protocolo que vive fuera de tu proceso. Cuando el usuario toca Conectar allí, el cliente de la plataforma levanta el túnel, no tu código. Por eso la fila sobrevive a un reinicio y por eso desinstalar tu aplicación nunca la elimina.

Desde el lado del usuario, la lista parece una superficie de API, un lugar donde añadir una VPN debería estar a un intent de distancia. No lo es. Los únicos puntos de entrada públicos que la tocan son intents de navegación, y todo lo que escribe en ella pertenece a la plataforma o a un componente privilegiado.

Consecuencia práctica: si un guion de soporte dice a los usuarios que añadan el perfil en Ajustes, tu aplicación no forma parte de ese flujo en absoluto.

Qué te da realmente VpnService

VpnService y VpnService.Builder describen un túnel que posee tu aplicación. Añades direcciones, rutas, servidores DNS y una MTU, delimitas el tráfico con addAllowedApplication() o addDisallowedApplication(), y luego establish() devuelve un ParcelFileDescriptor para una interfaz TUN. A partir de ahí la aplicación lee paquetes IP y escribe respuestas, lo que significa que el protocolo es tuyo para implementarlo o incrustarlo: OpenVPN, WireGuard, un transporte propio.

Nada en esa secuencia habla PPTP, L2TP/IPsec ni IKEv2. Builder no tiene ningún conmutador que diga usa el cliente L2TP del sistema, y no hay ninguna devolución de llamada que te permita conducir un perfil que la plataforma ya posee. Esa es la frontera real, y es una frontera de diseño, no un hueco de permisos.

Así que una aplicación puede ser sin duda un cliente VPN en Android. Solo que no puede ser un gestor de los clientes que vienen con el teléfono.

El diálogo de consentimiento no es decoración

Como tu túnel puede capturar el tráfico de otras aplicaciones, el sistema obliga a que el usuario lo apruebe explícitamente. prepare() devuelve un Intent que debes lanzar, la aprobación está ligada a tu paquete, y mientras el túnel está activo la barra de estado muestra un indicador permanente. Un segundo VPN que se levante desactiva el primero, porque Android ejecuta una VPN activa a la vez.

Esa regla de uno solo activo hace tropezar a la gente en las pruebas. Levantas tu túnel mientras hay un cliente corporativo conectado y concluyes que tu código está roto, cuando la plataforma simplemente cambió de cliente. Las aprobaciones se pueden revocar después, y prepare() puede devolver null en dispositivos donde falta la actividad de consentimiento, así que establish() sigue teniendo que manejar el fallo.

API ocultas e intents de ajustes

Las respuestas antiguas apuntan a clases com.android.internal e interfaces AIDL que usa el cliente integrado. No están en el SDK, cambian entre versiones sin aviso y las tiendas de aplicaciones tratan ese acceso como un riesgo. Hacer root en el dispositivo tampoco las vuelve estables, porque root y acceso a API ocultas son problemas no relacionados.

La ayuda de navegación soportada es Settings.ACTION_VPN_SETTINGS, cuyo valor es android.net.vpn.SETTINGS. Resuélvela antes de lanzarla, porque algunas compilaciones OEM no incluyen esa actividad, y recurre a pasos escritos cuando la resolución falla. Lleva al usuario a la pantalla y no configura nada.

Los caminos de propietario del dispositivo y MDM son la excepción que la gente suele querer decir. DevicePolicyManager puede designar un paquete de VPN siempre activa, y las configuraciones gestionadas pueden precargar ajustes para un cliente que los admita, pero eso sigue sin ser el SDK público redactando un perfil PPTP.

Recorre la decisión desde el lado del usuario

Si tu producto tiene que transportar tráfico, planifica VpnService más una pila de protocolos real, y presupuesta tiempo para el flujo de consentimiento y la regla de una sola VPN. Si el objetivo es conectarse a un perfil corporativo existente, tu trabajo es guiar: enlace profundo a la pantalla de ajustes, documenta los campos y deja que el cliente de la plataforma haga el túnel. Si la aplicación solo necesita llegar a un punto final privado, no necesita ningún túnel propio.

Escribe esa decisión antes de escribir código, porque los tres caminos no tienen casi nada en común después del primer sprint.

Una última comprobación antes de empezar: ¿el requisito dice que se conecta nuestra aplicación o que se conecta el dispositivo? Lo primero es VpnService, lo segundo es un perfil que no puedes crear. Acertar esa frase es más barato que cualquier refactorización.

Artículos relacionados