Dous códigos de erro explican a maioría dos primeiros intentos cunha VPN Network Extension en iOS: NEVPNErrorDomain Code=4 e Code=5. Nin un é unha queixa do servidor. Un aparece cando a app escribe axustes nun obxecto que nunca se leu do disco, e o outro cando falla a propia escritura, case sempre porque o perfil se garda mentres segue desactivado. Ambos se corrixen cambiando a orde de catro chamadas, non tocando os parámetros de IKEv2.

Cargue primeiro, ou o gardado non ten con que comparar

O xestor garda unha copia do perfil almacenado, e o obxecto que edita non é esa copia ata que a le. Chame primeiro a loadFromPreferences, edite dentro do seu manexador de finalización e logo garde. Se se salta a lectura, o marco ve unha discrepancia entre o que ten e o que escribe. En Swift a forma é a mesma en cada paso, e cada paso pertence ao seu propio closure:

let mgr = NEVPNManager.shared()
mgr.loadFromPreferences { loadErr in
    guard loadErr == nil else { return }
    let proto = NEVPNProtocolIKEv2()
    proto.serverAddress = "vpn.example.net"
    proto.username = "alice"
    proto.useExtendedAuthentication = true
    mgr.protocolConfiguration = proto
    mgr.isEnabled = true
    mgr.saveToPreferences { saveErr in
        // do not start here; reload, then connect
    }
}

Iniciar o túnel desde dentro do closure de gardado é o mesmo erro noutro sitio. Execútase antes de que o perfil se volva ler, así que a chamada de inicio ve o estado que construíu e non o estado que se gardou. O closure de gardado remata cun segundo loadFromPreferences, e só ese manexador de finalización chama a startVPNTunnel.

O indicador de activación forma parte do gardado

Un perfil gardado é inerte ata que se acende. Defina isEnabled = true na mesma escritura, ou o perfil chega ao disco desactivado e startVPNTunnel négase aínda que Axustes mostre unha configuración que parece completa.

As edicións externas son a outra metade. Se o usuario cambia algo en Axustes, ou o dispositivo se move entre redes, volva ler antes de confiar nos valores que aínda mantén en memoria. O obxecto non observa eses cambios por vostede. Unha copia obsoleta é como unha app escribe un perfil que reverte en silencio a edición do usuario. Dous campos adxacentes causan problemas silenciosos ao mesmo tempo: as regras on-demand deben ser unha matriz de obxectos de regra e non un marcador baleiro, e disconnectOnSleep debe reflectir o comportamento que escolleu e non un valor predeterminado copiado.

Só dous protocolos están dispoñibles para apps de terceiros

Network Extension dá ás apps IPsec e IKEv2. L2TP e PPTP quedan dentro do sistema, así que unha app que os necesite non os pode ter, e as respostas realistas son unha pasarela compatible con IKEv2 ou un perfil de configuración xestionado.

As credenciais seguen o mesmo patrón. Pon o contrasinal no Keychain e pasa unha referencia persistente en lugar da cadea. Unha referencia nula ao gardar adoita significar que a busca se executou antes de escribir o elemento, non que o xestor estea roto.

Ambas son decisións de deseño e non solucións improvisadas. Unha app que garda o contrasinal nas súas propias preferencias escolle un camiño que o marco desaconsella, e o fallo que produce lese como un erro de gardado.

Descarte o entitlement antes de reescribir código

Cando loadFromPreferences non devolve nunca a chamada, a causa probable é unha capacidade Network Extension ausente ou un perfil de aprovisionamento que non a leva. Ese fallo colga en lugar de dar erro, e por iso se reescribe código que funciona durante horas. Revise o entitlement na compilación asinada que pensa entregar, porque unha execución no simulador e outra no dispositivo poden diferir e o obxectivo que importa é o dispositivo. Abra os axustes de sinatura do obxectivo e confirme que a capacidade Network Extension está presente para esa compilación exacta.

Un perfil de aprovisionamento sen o entitlement falla igual no hardware, mentres que a mesma compilación pode cargarse con normalidade no simulador. Probe o ficheiro asinado nun dispositivo real antes de reescribir a orde das chamadas.

Observe os cambios de estado, non as suposicións

Observe NEVPNStatusDidChangeNotification e rexistre manager.connection.status despois de cada paso. Un estado que nunca sae de invalid significa que o perfil non se gardou ou que falta o entitlement. Unha conexión que chega a connecting e nunca conecta apunta á proposta ou ás credenciais, que é outra investigación con outras probas.

Confirme que o perfil aparece en Axustes, Xeral, VPN, e rexistre o erro de cada closure. Esos dous feitos separan un erro de orde dun erro de permisos sen adiviñar.

Artigos relacionados