Korleis sjekke i kode om ein VPN er tilkopla på Android
Android har ingen getter for VPN-tilkopling. Spør om nettverksfunksjonane, følg med på transportendringar, og hald samtykket til appen, tilstanden til eininga og serverbeviset frå kvarandre.
Du kan ikkje spørje Android om ein VPN er tilkopla. VpnService eksponerer ingen getter for tilkoplingstilstand, og nøkkelikonet i statuslinja blir teikna av systemet, ikkje av noko appen din kan lese. Det du kan gjere, er å stille tilkoplingstakka eit smalare spørsmål: kva nettverk brukar trafikken til denne appen, og ber det nettverket VPN-transporten. Denne rettleiinga går gjennom kontrollane i den rekkjefølgja som unngår falske positive, frå ein shell-kommando på eininga til callbacken du lèt gå i appen.
Sjekk eininga frå ein shell før du rører appkoden
Skaff ei basislinje først. adb shell dumpsys connectivity skriv ut kvart nettverk systemet kjenner, og kvar blokk listar opp transportane sine, så eit VPN-nettverk viser seg med VPN i den lista. Les blokka for standardnettverket før noko anna, og sjå deretter etter andre nettverk som ber same transport.
To utdata svarar på ulike spørsmål. Om eit VPN-nettverk finst er ikkje det same som om appen din brukar det, og på ei eining med arbeidsprofil eller ein annan brukar kan begge vere sanne samstundes medan prosessen din snakkar direkte med internett. Linja for aktivt nettverk er den som avgjer kva soklane dine gjer.
Spør etter nettverket appen brukar
I kode er funksjonstesten fire linjer. Be om ACCESS_NETWORK_STATE i manifestet, og samanlikn deretter funksjonane til det aktive nettverket med VPN-transporten:
ConnectivityManager cm = (ConnectivityManager)
context.getSystemService(Context.CONNECTIVITY_SERVICE);
Network active = cm.getActiveNetwork();
NetworkCapabilities caps = cm.getNetworkCapabilities(active);
boolean vpnInUse = caps != null
&& caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
Svaret er med vilje smalt: er standardnettverket til appen ein VPN akkurat no. Det seier ingenting om kva VPN, om det er ditt, eller om tunnelen når den andre enden. Handsame ein true som «trafikk går ut gjennom ein eller annan tunnel» og hald di eiga bokføring åtskild. Ein boolsk verdi som stille tyder tre ting samstundes, er grunnen til at ein innstillingsskjerm rapporterer VPN som av medan brukaren surfar gjennom den.
Når du i staden treng å vite om noko VPN-nettverk er til stades, iterer cm.getAllNetworks() og test kvart funksjonssett. Dei to svara sprikjer på ei eining som køyrer ein appspesifikk VPN som dekkjer andre appa men ikkje din, og den sprikjen er kjelda til dei fleste feilrapportane som seier at appen ikkje ser ein VPN som tydeleg er på.
Følg med på endringar i staden for å polle
Polling på ein timer er feil form for dette spørsmålet, fordi tilstandsendringar kjem som hendingar. Registrer ein førespurnad som samsvarar med VPN-transporten, og la rammeverket fortelje deg når eit samsvarande nettverk dukkar opp, forsvinn eller endrar seg:
NetworkRequest request = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_VPN)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
.build();
cm.registerNetworkCallback(request, callback);
Eit VPN-nettverk ber aldri NET_CAPABILITY_NOT_VPN, så den eksplisitte fjerninga dokumenterer hensikta. Utan ho samsvarar førespurnaden framleis, men neste person som les koden må finne det ut sjølv.
Registreringa høyrer til omfanget som treng observasjonen, vanlegvis ein skjerm eller ei forgrunnsteneste. Avregistrer i onStop eller onDestroy, og ikkje la ein callback henge på ein aktivitet som alt er borte. Ein app utan synlege komponentar er ein dårleg vert for ein permanent observatør, og callbackane du gløymer er dei som krasjar etter ei konfigurasjonsendring.
Hald tre spørsmål frå kvarandre
Det meste av forvirringa på dette området kjem av å handsame tre ulike kontrollar som éin. Dei brukar ulike API, og kvar av dei kan vere sann medan dei andre er falske.
| Question | How you answer it | What a yes means |
|---|---|---|
| Did the user grant VPN consent to my app? | VpnService.prepare() returns null | Consent exists; the tunnel may still be down |
| Is the device sending default traffic through a VPN? | TRANSPORT_VPN on the active network | Something is tunneling, not necessarily your app |
| Did this request arrive through the VPN? | Source address seen by the server | Proof for that connection, nothing wider |
Den tredje rada er den folk prøver å svare på i klienten, og den kan ikkje svarast der. Gi VPN-klientar sin eigen adressepool og les kjeldeadressa på serveren; det er det einaste beviset som overlever at ein brukar byter tunnel midt i ei økt.
Verifiseringsrekkjefølgje som utelukkar falske positive
Eldre eksempelkode som framleis sirkulerer kallar getNetworkInfo(ConnectivityManager.TYPE_VPN). Det kallet er utdatert, og på fleire versjonar returnerte det null sjølv medan ein VPN var tilkopla, og det er grunnen til at så mange kopierte bitar ser øydelagde ut på ei eining som fungerer. Funksjonskontrollar unngår fella og oppfører seg likt frå Android 5.0 og utover. Viss du vedlikeheld ein kodebase som framleis kallar det, erstatt kallet i staden for å pakke det inn i ein reserve, fordi reserven er det som produserte det gale svaret i utgangspunktet.
Ein snarveg fortener ei åtvaring. Å samanlikne den offentlege adressa som ei ekstern teneste rapporterer med utgangsadressa til VPN-en beviser noko om vegen, men det legg til ein tredjepartsførespurnad i kvar kontroll, er avhengig av at tenesta held seg oppe, og kan bli buftra eller blokkert. Hald det som ein manuell diagnose, aldri som tilstandskontrollen inne i appen.
Køyr kontrollane i denne rekkjefølgja og stopp ved den første som ikkje stemmer med rapporten til brukaren: transportliste frå shell, funksjonane til aktivt nettverk, callback-hendingar medan du slår tunnelen av og på, deretter kjeldeadresse på serversida. Viss alle fire stemmer og appen framleis oppfører seg feil, er feilen i din eigen tilstandsmaskin og ikkje i Androids syn på nettverket.