Dwa kody błędu wyjaśniają większość pierwszych prób z VPN Network Extension w iOS: NEVPNErrorDomain Code=4 i Code=5. Żaden nie jest skargą serwera. Jeden pojawia się, gdy aplikacja zapisuje ustawienia do obiektu, którego nigdy nie odczytano z dysku, a drugi, gdy sam zapis się nie udaje, najczęściej dlatego, że profil jest zapisywany, gdy jest jeszcze wyłączony. Oba naprawia się, zmieniając kolejność czterech wywołań, a nie dotykając parametrów IKEv2.

Najpierw wczytaj, inaczej zapis nie ma z czym porównać

Menedżer trzyma kopię zapisanego profilu, a obiekt, który edytujesz, nie jest tą kopią, dopóki jej nie odczytasz. Najpierw wywołaj loadFromPreferences, edytuj w jego procedurze ukończenia, a potem zapisz. Jeśli pominiesz odczyt, framework zobaczy rozbieżność między tym, co ma, a tym, co zapisujesz. W Swift kształt jest taki sam na każdym kroku, a każdy krok należy do własnego 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
    }
}

Uruchamianie tunelu z wnętrza closure zapisu to ten sam błąd w innym miejscu. Działa, zanim profil zostanie ponownie odczytany, więc wywołanie startu widzi stan, który zbudowałeś, a nie stan, który został zapisany. Closure zapisu kończy się drugim loadFromPreferences i tylko ta procedura ukończenia wywołuje startVPNTunnel.

Flaga włączenia jest częścią zapisu

Zapisany profil jest bezużyteczny, dopóki nie zostanie włączony. Ustaw isEnabled = true w tym samym zapisie, inaczej profil trafi na dysk wyłączony i startVPNTunnel odmówi, nawet gdy Ustawienia pokazują konfigurację, która wygląda na kompletną.

Zewnętrzne zmiany to druga połowa. Jeśli użytkownik zmieni coś w Ustawieniach albo urządzenie przejdzie między sieciami, odczytaj ponownie, zanim zaufasz wartościom, które wciąż trzymasz w pamięci. Obiekt nie obserwuje tych zmian za ciebie. Nieaktualna kopia to sposób, w jaki aplikacja zapisuje profil, który po cichu cofa zmianę użytkownika. Dwa sąsiednie pola powodują cichy problem w tej samej chwili: reguły on-demand muszą być tablicą obiektów reguł, a nie pustym zastępnikiem, a disconnectOnSleep powinien odzwierciedlać wybrane zachowanie, a nie skopiowaną wartość domyślną.

Tylko dwa protokoły są dostępne dla aplikacji innych firm

Network Extension daje aplikacjom IPsec i IKEv2. L2TP i PPTP zostają w systemie, więc aplikacja, która ich potrzebuje, nie może ich mieć, a realistyczne odpowiedzi to brama obsługująca IKEv2 albo zarządzany profil konfiguracji.

Dane logowania podlegają temu samemu wzorcowi. Umieść hasło w Keychain i przekaż trwałe odwołanie zamiast łańcucha. Puste odwołanie przy zapisie zwykle oznacza, że wyszukiwanie odbyło się przed zapisaniem elementu, a nie że menedżer jest zepsuty.

Oba są decyzjami projektowymi, a nie obejściami. Aplikacja, która trzyma hasło we własnych preferencjach, wybiera ścieżkę, której framework nie zaleca, a błąd, który produkuje, czyta się jak błąd zapisu.

Wyklucz uprawnienie, zanim przepiszesz kod

Gdy loadFromPreferences w ogóle nie wywołuje odpowiedzi, prawdopodobną przyczyną jest brakująca możliwość Network Extension albo profil provisioningu, który jej nie zawiera. Ten błąd wisi zamiast zwracać błąd, i dlatego działający kod jest przepisywany godzinami. Sprawdź uprawnienie w podpisanej kompilacji, którą zamierzasz wydać, bo uruchomienie w symulatorze i na urządzeniu mogą się różnić, a celem, który się liczy, jest urządzenie. Otwórz ustawienia podpisywania celu i potwierdź, że możliwość Network Extension jest obecna dla dokładnie tej kompilacji.

Profil provisioningu bez uprawnienia zawodzi tak samo na sprzęcie, podczas gdy ta sama kompilacja może wczytać się normalnie w symulatorze. Przetestuj podpisane archiwum na prawdziwym urządzeniu, zanim przepiszesz kolejność wywołań.

Obserwuj zmiany stanu, a nie założenia

Obserwuj NEVPNStatusDidChangeNotification i zapisuj manager.connection.status po każdym kroku. Stan, który nigdy nie opuszcza invalid, oznacza, że profil nie został zapisany albo brakuje uprawnienia. Połączenie, które osiąga connecting i nigdy się nie łączy, wskazuje na propozycję albo dane logowania, a to jest inne śledztwo z innymi dowodami.

Potwierdź, że profil pojawia się w Ustawienia, Ogólne, VPN, i zanotuj błąd z każdego closure. Te dwa fakty oddzielają błąd kolejności od błędu uprawnień bez zgadywania.

Powiązane artykuły