Jy kan nie vir Android vra of 'n VPN gekoppel is nie. VpnService bied geen gekoppelde-aanduider nie, en die sleutelikoon in die statusbalk word deur die stelsel geteken, nie deur iets wat jou app kan lees nie. Wat jy wel kan doen, is die konnektiwiteitstapel 'n smaller vraag vra: watter netwerk gebruik hierdie app se verkeer, en dra daardie netwerk die VPN-vervoer? Hierdie handleiding volg die kontroles in die volgorde wat vals positiewes vermy, van 'n shell-bevel op die toestel tot die callback wat jy in die app laat loop.

Kontroleer die toestel vanuit 'n shell voordat jy app-kode aanraak

Kry eers 'n basislyn. adb shell dumpsys connectivity druk elke netwerk uit wat die stelsel ken, en elke blok lys sy vervoersoorte, so 'n VPN-netwerk verskyn met VPN in daardie lys. Lees die versteknetwerkblok voor enigiets anders en kyk dan na ander netwerke wat dieselfde vervoer dra.

Twee uitsette beantwoord verskillende vrae. Of 'n VPN-netwerk bestaan is nie dieselfde as of jou app dit gebruik nie, en op 'n toestel met 'n werkprofiel of 'n tweede gebruiker kan albei gelyk waar wees terwyl jou proses direk met die internet praat. Die aktiewe netwerk-lyn is die een wat besluit wat jou sokkels doen.

Vra vir die netwerk wat die app gebruik

In kode is die vermoe-toets vier reels. Vra ACCESS_NETWORK_STATE in die manifes aan en vergelyk dan die aktiewe netwerk se vermoeens met die VPN-vervoer:

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);

Die antwoord is doelbewus smal: is die app se versteknetwerk nou 'n VPN. Dit se niks oor watter VPN, of dit aan jou behoort, of die tonnel sy verre punt bereik nie. Behandel 'n true as “verkeer verlaat deur een of ander tonnel” en hou jou eie boekhouding apart. 'n Boolse waarde wat stilweg drie dinge gelyk beteken, is hoe 'n instellingsskerm uiteindelik die VPN as af rapporteer terwyl die gebruiker daardeur blaai.

Wanneer jy eerder wil weet of enige VPN-netwerk teenwoordig is, itereer cm.getAllNetworks() en toets elke vermoe-stel. Die twee antwoorde verskil op 'n toestel wat 'n per-app VPN gebruik wat ander toepassings dek maar nie jou s'n nie, en daardie verskil is die bron van die meeste foutverslae wat se die app kan nie 'n VPN sien wat duidelik aan is nie.

Dophou veranderinge in plaas van om te peil

Peil op 'n tydhouer is die verkeerde vorm vir hierdie vraag, want toestandsveranderinge kom as gebeurtenisse. Registreer 'n versoek wat by die VPN-vervoer pas en laat die raamwerk jou vertel wanneer 'n passende netwerk verskyn, verdwyn of verander:

NetworkRequest request = new NetworkRequest.Builder()
    .addTransportType(NetworkCapabilities.TRANSPORT_VPN)
    .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
    .build();
cm.registerNetworkCallback(request, callback);

'n VPN-netwerk dra nooit NET_CAPABILITY_NOT_VPN nie, so die eksplisiete verwydering dokumenteer die bedoeling. Sonder dit pas die versoek steeds, maar die volgende persoon wat die kode lees, moet dit self uitwerk.

Registrasie hoort by die omvang wat die waarneming nodig het, gewoonlik 'n skerm of 'n voorgronddiens. Deregistreer in onStop of onDestroy, en moenie 'n callback aan 'n aktiwiteit laat hang wat reeds weg is nie. 'n App sonder sigbare komponent is 'n swak gasheer vir 'n permanente waarnemer, en die callbacks wat jy vergeet, is die wat na 'n konfigurasieverandering ineenstort.

Hou drie vrae apart

Die meeste verwarring op hierdie gebied kom daarvan dat drie verskillende kontroles as een behandel word. Hulle gebruik verskillende API's, en elkeen kan waar wees terwyl die ander onwaar is.

QuestionHow you answer itWhat a yes means
Did the user grant VPN consent to my app?VpnService.prepare() returns nullConsent exists; the tunnel may still be down
Is the device sending default traffic through a VPN?TRANSPORT_VPN on the active networkSomething is tunneling, not necessarily your app
Did this request arrive through the VPN?Source address seen by the serverProof for that connection, nothing wider

Die derde ry is die een wat mense op die kliënt probeer beantwoord, en dit kan nie daar beantwoord word nie. Gee VPN-kliënte hul eie adrespoel en lees die bronadres op die bediener; dit is die enigste bewys wat 'n gebruiker oorleef wat midde-in 'n sessie van tonnel verander.

Verifikasievolgorde wat vals positiewes uitskakel

Ouer voorbeeldkode wat nog in omloop is, roep getNetworkInfo(ConnectivityManager.TYPE_VPN). Daardie oproep is verouderd, en op verskeie weergawes het dit null teruggegee selfs terwyl 'n VPN gekoppel was, en daarom lyk so baie gekopieerde brokkies stukkend op 'n toestel wat werk. Vermoe-kontroles vermy die lokval en gedra hulle dieselfde vanaf Android 5.0. As jy 'n kodebasis onderhou wat dit nog roep, vervang die oproep eerder as om dit in 'n terugval te draai, want die terugval is wat die verkeerde antwoord oorspronklik veroorsaak het.

Een kortpad verdien 'n waarskuwing. Om die publieke adres wat 'n eksterne diens rapporteer met die VPN-uitgangadres te vergelyk, bewys wel iets oor die pad, maar dit voeg 'n derdepartyversoek by elke kontrole, hang daarvan af dat daardie diens aanbly, en kan gekas of geblokkeer word. Hou dit as 'n handmatige diagnostiek, nooit as die toestandskontrole binne die app nie.

Voer die kontroles in hierdie volgorde uit en stop by die eerste een wat nie met die gebruiker se verslag ooreenstem nie: shell-vervoerlys, aktiewe netwerkvermoeens, callback-gebeurtenisse terwyl jy die tonnel aan- en afskakel, dan die bronadres aan die bedienerkant. As al vier ooreenstem en die app nog steeds verkeerd optree, is die fout in jou eie toestandmasjien eerder as in Android se siening van die netwerk.

Verwante artikels