Vaše aplikace hlásí odpojeno, panel nabídek hlásí připojeno a provoz zjevně teče. Ten rozdíl není race condition, kterou opravíte opakováním: aplikace a tunel jsou samostatné procesy a objekt, který váš kód čte, je uložený pohled na konfiguraci, kterou spravuje systém. Personal VPN rozhraní od Applu je řídicí API, ne datová cesta, a většina jeho podivného chování z tohoto jediného faktu vyplývá. Tady je, co se při každém volání skutečně děje.

Objekt správce je uložený pohled, ne tunel

NETunnelProviderManager se plní z úložiště předvoleb, které vlastní systém, takže jeho vlastnosti nic neznamenají, dokud se loadFromPreferences nedokončí. Přečtete-li connection.status dřív, dostanete výchozí hodnotu, a proto první obnovení stavu po restartu hlásí odpojeno, zatímco tunel běží. Nejprve načtěte a potom čtěte stav i konfiguraci protokolu ze stejného dokončovacího handleru. Pozdější změny sledujte přes NEVPNStatusDidChange místo dotazování a všimněte si, že oznámení přichází i pro spojení spuštěná přes On Demand, kde neexistuje žádné volání aplikace, které by něco vrátilo. Totéž platí pro nastavení protokolu: čtou se z načtené konfigurace, ne z toho, co aplikace předala.

Tunel sám žije v procesu poskytovatele Network Extension, takže aplikace může ztratit vlastní stav, aniž by ztratila spojení. Vše, co rozhraní zobrazuje, se musí znovu sestavit ze správce, ne pamatovat z poslední relace.

Pořadí spuštění: uložit, načíst, potom spustit

Spojení založené na poskytovateli vyžaduje tři kroky v pořadí. Zapište konfiguraci poskytovatele a zavolejte saveToPreferences, načtěte správce, aby uložená konfigurace byla ta, kterou držíte, a potom spusťte přes NETunnelProviderSession.startVPNTunnel(). Když uložení přeskočíte, spuštění nemá co spustit; když načtete před uložením, správce stále odráží starou konfiguraci.

Logická hodnota vrácená z startVPNTunnel říká jen to, že požadavek byl přijat. Selhání na úrovni poskytovatele přicházejí později jako změna stavu na odpojeno, kterou pozorujete přes oznámení NEVPNStatusDidChange, a obsluha oznámení musí znovu přečíst connection.status po loadFromPreferences, protože uložená hodnota může být stále stará. Selhání na úrovni požadavku se vracejí okamžitě z podoby volání, která vyhazuje výjimky, nebo přes výstupní parametr chyby u startVPNTunnelAndReturnError:. Kód, který vrácenou hodnotu považuje za výsledek, hlásí spojení, které se nikdy nenavázalo. Další tichá porucha je identifikátor balíčku poskytovatele, který neodpovídá nainstalovanému rozšíření: požadavek je odmítnut a nic ve zprávě na identifikátor neukazuje. Je-li identifikátor špatný, požadavek obvykle selže hned, dřív než se objeví řádek v logu poskytovatele.

Opětovné načtení předvoleb po spuštění je to, co dělá obrazovky stavu správnými. Správce vám neposílá novou konfiguraci, když ji systém změní.

Materiál důvěry přichází profilem, nikdy z kódu aplikace

Aplikace nemá podporovaný způsob, jak přidat kořenový certifikát do úložiště důvěry iOS, takže konfigurace Personal VPN může odkazovat jen na materiál, kterému zařízení už důvěřuje: řetězec vytvořený nainstalovaným profilem, správou zařízení nebo CA, které systém důvěřuje z jiných důvodů. Aplikace, která si při prvním spuštění vytvoří vlastní CA a čeká, že ji systém uzná, selže při validaci uvnitř poskytovatele, kde rozhraní aplikace důvod nevidí.

Berte tuto hranici jako návrhové omezení, kterým je, a doručujte kotvu důvěry spolu s profilem pro zápis. Držte VPN autentizaci oddělenou od rozhodnutí o důvěře, protože selhávají na různých místech a ladí je různí lidé.

Čítače přicházejí z rozhraní, ne z VPN API

Správce vystavuje stav a konfiguraci a nic, co by počítalo bajty na tunel. Potřebujete-li čísla o využití, zavolejte getifaddrs() a přečtěte if_data příslušného rozhraní: en0 pro Wi-Fi, rozhraní pdp_ip pro mobilní síť a zařízení utun pro samotný tunel. Čítače utun popisují vnitřní provoz a zahrnují režii protokolu.

Tato čísla jsou odhady, ne účtování po aplikacích a resetují se, když se rozhraní znovu vytvoří. Označte je tak v rozhraní, jinak je někdo použije k fakturaci zákazníka. Potřebujete-li čísla po aplikacích, potřebujete úplně jiný mechanismus, ne lepší čtení těchto polí.

Úklid patří do stopVPNTunnel, ne do ukončení

applicationWillTerminate vám dá několik sekund, než systém může proces zabít, což není spolehlivé místo pro rozpojení spojení. Pošlete zastavení na stopVPNTunnel() nebo je obslužte ve zpětném volání zastavení poskytovatele a ponechte si identifikátor správce nebo konfigurace, se kterým jste začali, aby zastavení mířilo na toto spojení, a ne na každou konfiguraci v zařízení.

Uložte tento identifikátor vedle profilu, ke kterému patří, protože objekt správce nezaznamenává, kterou konfiguraci uživatel vybral. A pamatujte, že spojení vyvolané On Demand nemá za sebou žádné volání aplikace, takže obrazovka stavu stejně musí načíst předvolby, než cokoli vykreslí.

Související články