Android-də VPN-in qoşulduğunu kodla necə yoxlamaq olar
Android-də VPN bağlantısı üçün getter yoxdur. Şəbəkə imkanlarını sorğulayın, nəqliyyat dəyişikliklərini izləyin və tətbiq razılığını, cihaz vəziyyətini və server sübutunu ayrı saxlayın.
Android-dən VPN-in qoşulub-qoşulmadığını soruşa bilməzsiniz. VpnService heç bir bağlantı getteri təqdim etmir və status panelindəki açar ikonunu sistem çəkir, tətbiqinizin oxuya biləcəyi heç nə deyil. Edə biləcəyiniz şey əlaqə yığınına daha dar bir sual verməkdir: bu tətbiqin trafiki hansı şəbəkədən istifadə edir və həmin şəbəkə VPN nəqliyyatını daşıyırmı. Bu təlimat yoxlamaları yanlış müsbət nəticələrdən qaçan ardıcıllıqla keçir, cihazdakı shell əmrindən tutmuş tətbiqdə işlək saxladığınız callback-ə qədər.
Tətbiq koduna toxunmadan əvvəl cihazı shell-dən yoxlayın
Əvvəlcə baza xətti götürün. adb shell dumpsys connectivity sistemin bildiyi hər şəbəkəni çap edir və hər blok öz nəqliyyat növlərini sadalayır, ona görə VPN şəbəkəsi həmin siyahıda VPN ilə görünür. Hər şeydən əvvəl default şəbəkə blokunu oxuyun, sonra eyni nəqliyyatı daşıyan digər şəbəkələrə baxın.
İki çıxış fərqli suallara cavab verir. VPN şəbəkəsinin mövcudluğu tətbiqinizin ondan istifadə etməsi ilə eyni şey deyil və iş profili və ya ikinci istifadəçi olan cihazda prosesiniz birbaşa internetlə danışarkən hər ikisi eyni vaxtda doğru ola bilər. Aktiv şəbəkə sətri soketlərinizin nə edəcəyini müəyyən edən sətdir.
Tətbiqin istifadə etdiyi şəbəkəni soruşun
Kodda imkan testi dörd sətirdir. Manifestdə ACCESS_NETWORK_STATE istəyin, sonra aktiv şəbəkənin imkanlarını VPN nəqliyyatı ilə müqayisə edin:
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);
Cavab qəsdən dardır: tətbiqin default şəbəkəsi hazırda VPN-dirmi. Bu, hansı VPN olduğu, sizə aid olub-olmadığı və ya tunelin uzaq ucuna çatıb-çatmadığı barədə heç nə demir. true dəyərini “trafik hansısa tuneldən çıxır” kimi qəbul edin və öz uçotunuzu ayrı saxlayın. Eyni vaxtda üç şeyi səssizcə ifadə edən boolean, ayarlar ekranının istifadəçi ondan keçərkən VPN-i söndürülmüş kimi göstərməsinin yoludur.
Əvəzində hər hansı VPN şəbəkəsinin mövcud olub-olmadığını bilmək lazım olduqda, cm.getAllNetworks() üzərində iterasiya edin və hər imkan dəstini yoxlayın. İki cavab digər tətbiqləri əhatə edən, amma sizinkini əhatə etməyən hər-tətbiq VPN işlədən cihazda ayrılır və bu ayrılıq tətbiqin açıq-aydın yandırılmış VPN-i görmədiyini deyən xəta hesabatlarının çoxunun mənbəyidir.
Sorğu göndərmək əvəzinə dəyişiklikləri izləyin
Taymerlə sorğu göndərmək bu sual üçün yanlış formadır, çünki vəziyyət dəyişiklikləri hadisə kimi gəlir. VPN nəqliyyatına uyğun bir sorğu qeydiyyatdan keçirin və uyğun şəbəkə görünəndə, yoxa çıxanda və ya dəyişəndə framework sizə desin:
NetworkRequest request = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_VPN)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
.build();
cm.registerNetworkCallback(request, callback);
VPN şəbəkəsi heç vaxt NET_CAPABILITY_NOT_VPN daşımır, ona görə açıq şəkildə çıxarılması niyyəti sənədləşdirir. Olmadan da sorğu uyğun gəlir, amma kodu oxuyan növbəti şəxs bunu özü anlamalı olur.
Qeydiyyat müşahidəni ehtiyac duyan əhatəyə aiddir, adətən bir ekran və ya ön plan xidməti. onStop və ya onDestroy daxilində qeydiyyatdan çıxarın və artıq getmiş activity-yə callback bağlı qoymayın. Görünən komponenti olmayan tətbiq daimi müşahidəçi üçün zəif ev sahibidir və unutduğunuz callback-lər konfiqurasiya dəyişikliyindən sonra çökənlərdir.
Üç sualı ayrı saxlayın
Bu sahədəki qarışıqlığın çoxu üç fərqli yoxlamanı bir kimi qəbul etməkdən gəlir. Onlar fərqli API-lər istifadə edir və hər biri digərləri yalan ikən doğru ola bilər.
| 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 |
Üçüncü sətir insanların client-də cavablandırmağa çalışdığı sətirdir və orada cavablandırıla bilməz. VPN client-lərinə öz ünvan hovuzunu verin və mənbə ünvanını serverdə oxuyun; istifadəçinin sessiya ortasında tunel dəyişməsinə tab gətirən yeganə sübut budur.
Yanlış müsbətləri istisna edən yoxlama sırası
Hələ də dövriyyədə olan köhnə nümunə kodu getNetworkInfo(ConnectivityManager.TYPE_VPN) çağırır. Bu çağırış köhnəlmişdir və bir neçə buraxılışda VPN qoşulmuş olsa belə null qaytardı, buna görə də çox sayda köçürülmüş kod parçası işləyən cihazda sınıq görünür. İmkan yoxlamaları bu tələdən qaçır və Android 5.0-dan bəri eyni cür davranır. Hələ də onu çağıran kod bazası saxlayırsınızsa, çağırışı fallback ilə əhatə etmək əvəzinə əvəz edin, çünki yanlış cavabı ilk növbədə fallback yaratmışdı.
Bir qısa yol xəbərdarlığa layiqdir. Xarici xidmətin bildirdiyi ictimai ünvanı VPN çıxış ünvanı ilə müqayisə etmək yol haqqında nəsə sübut edir, amma hər yoxlamaya üçüncü tərəf sorğusu əlavə edir, həmin xidmətin işlək qalmasından asılıdır və keşlənə və ya bloklana bilər. Onu əl ilə diaqnostika kimi saxlayın, heç vaxt tətbiqin içində vəziyyət yoxlaması kimi yox.
Yoxlamaları bu sıra ilə aparın və istifadəçinin hesabatı ilə uyğun gəlməyən ilk yoxlamada dayanın: shell nəqliyyat siyahısı, aktiv şəbəkə imkanları, tuneli açıb-bağlayarkən callback hadisələri, sonra server tərəfində mənbə ünvanı. Əgər dördü də uyğun gəlirsə və tətbiq hələ də səhv davranırsa, xəta Android-in şəbəkəyə baxışında deyil, sizin öz vəziyyət maşınınızdadır.