En Android-app kan inte lösa ett internt namn medan webbläsaren i själva VPN-klienten når det, och samma bygge fungerar på en annan telefon. URL:en är inte variabeln. Variabeln är vilket nätverk appens process får använda för uppslagning, och Android garanterar inte att den aktiva VPN:en är det nätverk dina sockets använder. Gör dessa kontroller i ordning och stanna när resolver-ögonblicksbilden inte stämmer med ditt antagande.

Steg 1: bevisa vilket nätverk appen ligger på

Läs appens egen vy i stället för statusfältet. Hämta det aktiva nätverket från ConnectivityManager, dess LinkProperties, listan över DNS-servrar och inställningen för privat DNS. Om listan innehåller VPN:ens resolver har appen en väg dit; om den innehåller Wi-Fi:ns resolver är tunneln inte standardnätverket för den processen.

Et VPN-ikon säger bara att en tunnel finns. Den säger inte att appens process var bunden till den, och Android dirigerar inte alltid namnuppslagning via nätverket som verkar aktivt. Lokala VPN-appar som vidarebefordrar till en annan enhet, Wi-Fi-nätverk utan internet och leverantörernas byggen kan alla lämna appen frågande efter standardresolvern i stället för tunnelns servrar.

Steg 2: begär VPN-transporten och bind processen

När appen måste använda tunnelns resolver, begär ett nätverk med VPN-transport och bind processen i callbacken, så att koden inte gissar när nätverket dyker upp:

val request = NetworkRequest.Builder()
    .addTransportType(NetworkCapabilities.TRANSPORT_VPN)
    .build()

connectivityManager.requestNetwork(request, object : NetworkCallback() {
    override fun onAvailable(network: Network) {
        val bound = connectivityManager.bindProcessToNetwork(network)
        Log.i(TAG, "bound to VPN network: " + bound)
    }
})

Anropet ändrar standardnätverket för hela processen, så varje socket som skapas efteråt använder det. Sockets som redan finns behåller nätverket de skapades på, och därför kan en anslutningspool som öppnades före bindningen fortsätta lösa via den gamla vägen. Returvärdet är en boolean, och ett resultat på false betyder att bindningen inte skedde; försök igen med en kort fördröjning och logga båda försöken.

Steg 3: begränsa bindningen till det som behöver den

Bindning för hela processen är grov. Telemetri, uppdateringskontroller och SDK:er från tredje part flyttar också över till tunneln, och om tunneln saknar internet börjar de misslyckas. För en enda begäran använder du nätverkets socketfabrik och låter enhetens standard gälla för allt annat. Välj medvetet en modell: smal bindning per anslutning, eller processbindning med tydlig avbindning när VPN:en försvinner.

Två resolverfunktioner kan besegra bindningen utan något fel. Privat DNS i strikt läge skickar frågor till en namngiven DoT-server i stället för nätverkets resolver, och en app som levererar en egen DNS-over-HTTPS-klient kringgår systemets resolver helt. Kontrollera båda innan du drar slutsatsen att bindningen misslyckades. En fråga som aldrig når VPN:ens DNS-server kommer inte att synas i någon logg på tunnelsidan.

Steg 4: lita inte på ett CONNECTED-villkor

NetworkType.CONNECTED i WorkManager betyder att ett nätverk är anslutet, och VPN-transporten uppfyller det även när den underliggande Wi-Fi- eller mobillänken är borta. Jobbet körs, varje begäran misslyckas, och återförsökspolicyn förvandlar det till en storm som ser ut som en schemaläggningsbugg. Tunneln är ett nätverk; villkoret var aldrig en internetkontroll.

Kontrollera den förmåga som arbetet faktiskt behöver, till exempel verifierad internetåtkomst, och håll en begränsad återförsökspolicy med backoff. Om jobbet behöver ett privat namn, lös det namnet i det valda nätverket innan arbetet utförs, och misslyckas snabbt med ett tydligt fel i stället för att upprepa en begäran som inte kan lyckas.

Steg 5: registrera bevisen och testa intervallet igen

Logga transporttyperna för det valda nätverket, DNS-servrarna från LinkProperties, om bindningen returnerade true, och det exakta felet för den första begäran. Kör sedan ett privat namn och ett offentligt namn under samma bindning. Det paret visar om appen använde tunnelns resolver eller tyst föll tillbaka på enhetens standard, och det är skillnaden användaren upplever.

Upprepa på den äldsta Android-version du stöder och på en aktuell utgåva. Resolverns beteende som får standardvägen att se korrekt ut är precis där enheter och versioner skiljer sig, och ett bygge som bara passerar på den nyaste testenheten är inte verifierat för det intervall du levererar. adb shell dumpsys connectivity är ett snabbt sätt att bekräfta vilka nätverk och förmågor enheten rapporterar medan du återskapar felet.

Relaterade artiklar