NEVPNManager 저장이 실패하나요? 순서는 불러오기, 활성화, 저장, 연결
코드 4와 코드 5는 보통 프로필이 로드되기 전에 편집되었거나 비활성 상태로 저장되었다는 뜻입니다. 호출 순서를 고친 뒤 entitlement를 확인하세요.
iOS에서 Network Extension VPN의 첫 시도 대부분을 설명하는 오류 코드는 NEVPNErrorDomain Code=4와 Code=5, 두 가지입니다. 둘 다 서버의 불평이 아닙니다. 하나는 앱이 디스크에서 한 번도 읽지 않은 객체에 설정을 쓸 때 나타나고, 다른 하나는 쓰기 자체가 실패할 때, 대개 프로필이 아직 비활성 상태에서 저장되기 때문에 나타납니다. 둘 다 네 번의 호출 순서를 바꾸면 해결되며, IKEv2 매개변수를 건드릴 필요는 없습니다.
먼저 불러오기, 그렇지 않으면 저장할 비교 대상이 없습니다
관리자는 저장된 프로필의 복사본을 보관하며, 편집하는 객체는 그것을 읽기 전까지 그 복사본이 아닙니다. 먼저 loadFromPreferences를 호출하고, 그 완료 핸들러 안에서 편집한 뒤 저장합니다. 읽기를 건너뛰면 프레임워크는 자기가 가진 것과 작성 중인 것 사이의 불일치를 봅니다. Swift에서는 모든 단계의 형태가 같고, 각 단계는 자기 클로저에 들어갑니다:
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
}
}
저장 클로저 안에서 터널을 시작하는 것은 다른 곳에서의 같은 실수입니다. 프로필이 다시 읽히기 전에 실행되므로 시작 호출은 저장된 상태가 아니라 직접 구성한 상태를 봅니다. 저장 클로저는 두 번째 loadFromPreferences로 끝나고, 그 완료 핸들러만이 startVPNTunnel을 호출합니다.
활성화 플래그는 저장의 일부입니다
저장된 프로필은 켜지기 전까지 비활성입니다. 같은 쓰기에서 isEnabled = true를 설정하지 않으면 프로필은 비활성 상태로 디스크에 남고, 설정에 완전해 보이는 구성이 표시되어도 startVPNTunnel는 거부합니다.
외부 편집이 나머지 절반입니다. 사용자가 설정에서 무언가를 바꾸거나 기기가 네트워크 사이를 이동하면, 메모리에 아직 들고 있는 값을 믿기 전에 다시 읽으세요. 객체는 그런 변경을 대신 관찰하지 않습니다. 오래된 복사본은 앱이 사용자의 편집을 조용히 되돌리는 프로필을 쓰는 경로입니다. 인접한 두 필드는 같은 순간에 조용한 문제를 일으킵니다: on-demand 규칙은 빈 자리표시자가 아니라 규칙 객체의 배열이어야 하고, disconnectOnSleep은 복사한 기본값이 아니라 선택한 동작을 반영해야 합니다.
서드파티 앱에 사용할 수 있는 프로토콜은 두 가지뿐입니다
Network Extension은 앱에 IPsec과 IKEv2를 제공합니다. L2TP와 PPTP는 시스템 내부에 남으므로 그것이 필요한 앱은 가질 수 없고, 현실적인 답은 IKEv2 지원 게이트웨이나 관리형 구성 프로필입니다.
자격 증명도 같은 패턴을 따릅니다. 암호를 Keychain에 넣고 문자열 대신 영구 참조를 전달합니다. 저장 시점의 nil 참조는 보통 항목이 쓰이기 전에 조회가 돌았다는 뜻이며, 관리자가 고장 났다는 뜻이 아닙니다.
둘 다 우회가 아니라 설계 결정입니다. 암호를 자체 설정에 보관하는 앱은 프레임워크가 권장하지 않는 길을 택하며, 그것이 만들어 내는 실패는 저장 오류처럼 읽힙니다.
코드를 다시 쓰기 전에 entitlement를 배제하세요
loadFromPreferences가 전혀 콜백하지 않으면, 가능한 원인은 Network Extension 기능이 없거나 그것을 담지 않은 프로비저닝 프로필입니다. 그 실패는 오류를 내지 않고 멈추므로, 동작하는 코드가 몇 시간씩 다시 작성됩니다. 시뮬레이터 실행과 기기 실행이 다를 수 있고 중요한 대상은 기기이므로, 배포할 서명된 빌드에서 entitlement를 확인하세요. 대상의 서명 설정을 열고 그 정확한 빌드에 Network Extension 기능이 있는지 확인합니다.
entitlement가 없는 프로비저닝 프로필은 하드웨어에서도 같은 방식으로 실패하는 반면, 같은 빌드는 시뮬레이터에서 정상적으로 로드될 수 있습니다. 호출 순서를 다시 쓰기 전에 서명된 아카이브를 실제 기기에서 테스트하세요.
가정이 아니라 상태 변화를 보세요
NEVPNStatusDidChangeNotification을 관찰하고 각 단계 후에 manager.connection.status를 기록합니다. invalid를 결코 벗어나지 않는 상태는 프로필이 저장되지 않았거나 entitlement가 없음을 뜻합니다. connecting에 도달하고 결코 연결되지 않는 연결은 제안이나 자격 증명을 가리키며, 그것은 다른 증거를 가진 다른 조사입니다.
프로필이 설정, 일반, VPN 아래에 표시되는지 확인하고 각 클로저의 오류를 기록합니다. 이 두 사실이 추측 없이 순서 버그와 권한 버그를 구분합니다.