Vaša aplikacija kaže prekinuto, traka izbornika kaže povezano, a promet očito teče. Ta razlika nije uvjet utrke koji popravljate ponovnim pokušajem: aplikacija i tunel su odvojeni procesi, a objekt koji vaš kod čita predmemorirani je prikaz konfiguracije koju sustav čuva. Appleovo Personal VPN sučelje je kontrolni API, a ne put podataka, i većina njegovog neobičnog ponašanja proizlazi iz te jedne činjenice. Evo što se zapravo događa pri svakom pozivu.

Objekt upravitelja je predmemorirani prikaz, a ne tunel

NETunnelProviderManager se popunjava iz spremišta postavki koje posjeduje sustav, pa njegova svojstva ništa ne znače dok loadFromPreferences ne završi. Pročitate li connection.status prije toga, dobivate zadanu vrijednost, zbog čega prvo osvježavanje statusa nakon ponovnog pokretanja javlja prekinuto dok je tunel aktivan. Prvo učitajte, pa pročitajte status i konfiguraciju protokola iz istog rukovatelja dovršetka. Kasnije promjene pratite kroz NEVPNStatusDidChange umjesto periodičnog provjeravanja i imajte na umu da se obavijest javlja i za veze koje pokreće On Demand, gdje ne postoji nikakav poziv aplikacije koji bi nešto vratio. Isto vrijedi i za postavke protokola: čitaju se iz učitane konfiguracije, a ne iz onoga što je aplikacija poslala.

Sam tunel živi u procesu pružatelja Network Extension, pa aplikacija može izgubiti vlastito stanje bez gubitka veze. Sve što sučelje prikazuje mora se ponovno izgraditi iz upravitelja, a ne pamtiti iz posljednje sesije.

Redoslijed pokretanja: spremi, učitaj, pa pokreni

Veza koja se temelji na pružatelju zahtijeva tri koraka po redu. Zapišite konfiguraciju pružatelja i pozovite saveToPreferences, učitajte upravitelja da spremljena konfiguracija bude ona koju držite, pa pokrenite kroz NETunnelProviderSession.startVPNTunnel(). Preskočite li spremanje, pokretanje nema što pokrenuti; učitate li prije spremanja, upravitelj i dalje odražava staru konfiguraciju.

Booleova vrijednost koju vraća startVPNTunnel samo kaže da je zahtjev prihvaćen. Pogreške na razini pružatelja dolaze kasnije kao promjena statusa u prekinuto, što pratite kroz obavijest NEVPNStatusDidChange, a rukovatelj obavijesti mora ponovno pročitati connection.status nakon loadFromPreferences jer predmemorirana vrijednost može još biti stara. Pogreške na razini zahtjeva vraćaju se odmah iz oblika poziva koji baca iznimku ili kroz izlazni parametar pogreške od startVPNTunnelAndReturnError:. Kod koji vraćenu vrijednost tretira kao ishod javlja vezu koja nikada nije uspostavljena. Drugi tihi kvar je identifikator paketa pružatelja koji se ne podudara s instaliranim proširenjem: zahtjev se odbija i ništa u poruci ne upućuje na identifikator. Ako je identifikator pogrešan, zahtjev obično odmah propada, prije nego se pojavi ijedan redak u dnevniku pružatelja.

Ponovno učitavanje postavki nakon pokretanja jest ono što čini zaslone statusa ispravnima. Upravitelj vam ne šalje novu konfiguraciju kad je sustav promijeni.

Materijal povjerenja dolazi putem profila, nikada iz koda aplikacije

Aplikacija nema podržan način da doda korijenski certifikat u iOS spremište povjerenja, pa Personal VPN konfiguracija može referencirati samo materijal kojem uređaj već vjeruje: lanac uspostavljen instaliranim profilom, upravljanjem uređajem ili CA kojem sustav vjeruje iz drugih razloga. Aplikacija koja stvori vlastiti CA pri prvom pokretanju i očekuje da ga sustav prihvati propast će na validaciji unutar pružatelja, gdje korisničko sučelje aplikacije ne može vidjeti razlog.

Tretirajte tu granicu kao dizajnersko ograničenje kakvo jest i isporučite sidro povjerenja uz profil za upis. Držite VPN autentifikaciju odvojeno od odluke o povjerenju, jer one propadaju na različitim mjestima i otklanjaju ih različiti ljudi.

Brojači dolaze sa sučelja, ne iz VPN API-ja

Upravitelj izlaže status i konfiguraciju i ništa što broji bajtove po tunelu. Ako su vam potrebni brojevi potrošnje, pozovite getifaddrs() i pročitajte if_data za odgovarajuće sučelje: en0 za Wi-Fi, sučelja pdp_ip za mobilnu mrežu i utun uređaj za sam tunel. Brojači utun opisuju unutarnji promet i uključuju protokolni trošak.

Te brojke su procjene, a ne obračun po aplikaciji, i resetiraju se kad se sučelje ponovno stvori. Označite ih tako u sučelju, ili će ih netko iskoristiti da naplati kupcu. Ako su vam potrebni brojevi po aplikaciji, potreban vam je posve drugačiji mehanizam, a ne bolje čitanje ovih polja.

Čišćenje pripada stopVPNTunnel, a ne terminaciji

applicationWillTerminate vam daje nekoliko sekundi prije nego sustav može ubiti proces, što nije pouzdano mjesto za rušenje veze. Pošaljite zaustavljanje na stopVPNTunnel() ili ga obradite u povratnom pozivu zaustavljanja pružatelja, i zadržite identifikator upravitelja ili konfiguracije s kojim ste pokrenuli da zaustavljanje cilja tu vezu umjesto svake konfiguracije na uređaju.

Spremite taj identifikator uz profil kojem pripada, jer objekt upravitelja ne bilježi koju je konfiguraciju korisnik odabrao. I zapamtite da veza koju podigne On Demand nema nikakav poziv aplikacije iza sebe, pa zaslon statusa i dalje mora učitati postavke prije nego išta nacrta.

Povezani članci