Како да проверите во кодот дали VPN е поврзан на Android
Android нема getter за поврзаност на VPN. Прашајте ги мрежните можности, набљудувајте промени на транспортот и одвојте ја согласноста на апликацијата, состојбата на уредот и доказот од серверот.
Не можете да го прашате Android дали VPN е поврзан. VpnService не изложува getter за состојбата на поврзаност, а иконата со клуч во статусната лента ја црта системот, а не нешто што вашата апликација може да го прочита. Она што можете да го направите е да му поставите на стекот за поврзување потесно прашање: која мрежа го користи сообраќајот на оваа апликација и дали таа мрежа го носи VPN транспортот. Овој прирачник ги поминува проверките по редослед што ги избегнува лажните позитивни резултати, од shell команда на уредот до callback што го оставате да работи во апликацијата.
Проверете го уредот од shell пред да го допрете кодот на апликацијата
Прво земете основна состојба. adb shell dumpsys connectivity печати секоја мрежа што системот ја знае, а секој блок ги наведува своите транспорти, така што VPN мрежата се појавува со VPN во тој список. Прочитајте го блокот на стандардната мрежа пред сè друго, потоа барајте други мрежи што го носат истиот транспорт.
Два излези одговараат на различни прашања. Тоа што постои VPN мрежа не е исто како тоа што вашата апликација ја користи, а на уред со работен профил или втор корисник двете можат да бидат вистинити истовремено додека вашиот процес разговара директно со интернетот. Редот на активната мрежа е тој што одлучува што прават вашите сокети.
Прашајте ја мрежата што ја користи апликацијата
Во кодот тестот на можности е четири реда. Побарајте ACCESS_NETWORK_STATE во манифестот, потоа споредете ги можностите на активната мрежа со VPN транспортот:
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);
Одговорот е намерно тесен: дали стандардната мрежа на апликацијата е VPN во моментов. Не кажува ништо за тоа кој VPN е, дали е ваш или дали тунелот стигнува до другиот крај. Третирајте го true како „сообраќајот излегува низ некој тунел“ и водете ја својата евиденција одделно. Булова вредност што тивко значи три работи истовремено е причината зошто екранот за поставки пријавува дека VPN е исклучен додека корисникот прелистува низ него.
Кога, пак, треба да знаете дали постои која било VPN мрежа, повторувајте cm.getAllNetworks() и проверете го секое множество можности. Двата одговора се разидуваат на уред што извршува VPN по апликација што опфаќа други апликации, но не и вашата, и тоа разидување е извор на повеќето пријави за грешки што велат дека апликацијата не гледа VPN што очигледно е вклучен.
Набљудувајте промени наместо да анкетирате
Анкетирањето со тајмер е погрешна форма за ова прашање, бидејќи промените на состојбата доаѓаат како настани. Регистрирајте барање што одговара на VPN транспортот и оставете рамката да ви каже кога соодветната мрежа се појавува, исчезнува или се менува:
NetworkRequest request = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_VPN)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
.build();
cm.registerNetworkCallback(request, callback);
VPN мрежата никогаш не носи NET_CAPABILITY_NOT_VPN, така што експлицитното отстранување ги документира намерите. Без него барањето сè уште одговара, но следниот човек што го чита кодот мора сам да го сфати тоа.
Регистрацијата припаѓа на опсегот на кој му е потребно набљудувањето, обично екран или услуга во преден план. Одрегистрирајте во onStop или onDestroy и не оставајте callback прикачен на активност што веќе ја нема. Апликација без видлива компонента е лош домаќин за постојан набљудувач, а заборавените callback се тие што паѓаат по промена на конфигурацијата.
Држете три прашања одделно
Повеќето конфузија во оваа област доаѓа од третирањето на три различни проверки како една. Тие користат различни API и секоја може да биде вистинита додека другите се лажни.
| 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 |
Третиот ред е тој што луѓето се обидуваат да го одговорат на клиентот и таму не може да се одговори. Дајте им на VPN клиентите свој базен од адреси и читајте ја изворната адреса на серверот; тоа е единствениот доказ што опстојува кога корисникот менува тунел во средина на сесија.
Редослед на проверка што ги исклучува лажните позитивни резултати
Постариот примерен код што сè уште циркулира го повикува getNetworkInfo(ConnectivityManager.TYPE_VPN). Тој повик е застарен и на неколку изданија враќаше null дури и кога VPN беше поврзан, поради што многу копирани фрагменти изгледаат расипани на уред што работи. Проверките на можности ја избегнуваат таа замка и се однесуваат исто од Android 5.0. Ако одржувате кодна база што сè уште го повикува, заменете го повикот наместо да го завиткате во резерва, бидејќи резервата го создаде погрешниот одговор во прв ред.
Еден кратен пат заслужува предупредување. Споредувањето на јавната адреса што ја пријавува надворешна услуга со излезната адреса на VPN докажува нешто за патеката, но додава барање од трета страна на секоја проверка, зависи од тоа услугата да остане достапна и може да биде кеширано или блокирано. Држете го како рачна дијагностика, никогаш како проверка на состојбата во апликацијата.
Извршете ги проверките по овој редослед и застанете на првата што не се совпаѓа со пријавеното од корисникот: список на транспорти од shell, можности на активната мрежа, callback настани додека го вклучувате и исклучувате тунелот, потоа изворна адреса од страната на серверот. Ако сите четири се совпаѓаат, а апликацијата сè уште работи погрешно, грешката е во вашата сопствена машина на состојби, а не во гледањето на мрежата од Android.