Cara menyemak dalam kod sama ada VPN disambungkan pada Android
Android tiada getter status sambungan VPN. Tanya keupayaan rangkaian, perhati perubahan pengangkutan, dan asingkan persetujuan apl, keadaan peranti dan bukti pelayan.
Anda tidak boleh bertanya kepada Android sama ada VPN disambungkan. VpnService tidak mendedahkan getter status sambungan, dan ikon kunci dalam bar status dilukis oleh sistem, bukan sesuatu yang apl anda boleh baca. Apa yang boleh anda lakukan ialah bertanya kepada tindanan kesambungan soalan yang lebih sempit: rangkaian mana yang digunakan trafik apl ini, dan adakah rangkaian itu membawa pengangkutan VPN. Buku panduan ini menelusuri semakan mengikut urutan yang mengelakkan positif palsu, daripada arahan shell pada peranti sehingga callback yang anda biarkan berjalan dalam apl.
Semak peranti dari shell sebelum menyentuh kod apl
Dapatkan keadaan asas dahulu. adb shell dumpsys connectivity mencetak setiap rangkaian yang diketahui sistem, dan setiap blok menyenaraikan pengangkutannya, jadi rangkaian VPN muncul dengan VPN dalam senarai itu. Baca blok rangkaian lalai sebelum apa-apa lagi, kemudian cari rangkaian lain yang membawa pengangkutan yang sama.
Dua output menjawab soalan berbeza. Sama ada rangkaian VPN wujud bukanlah sama dengan sama ada apl anda menggunakannya, dan pada peranti dengan profil kerja atau pengguna kedua, kedua-duanya boleh benar serentak semasa proses anda bercakap terus dengan internet. Baris rangkaian aktif yang menentukan apa yang dibuat oleh soket anda.
Tanya rangkaian yang digunakan oleh apl
Dalam kod, ujian keupayaan ialah empat baris. Minta ACCESS_NETWORK_STATE dalam manifes, kemudian bandingkan keupayaan rangkaian aktif dengan pengangkutan 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);
Jawapannya sengaja sempit: adakah rangkaian lalai apl ialah VPN sekarang. Ia tidak berkata apa-apa tentang VPN mana, sama ada ia milik anda, atau sama ada terowong itu sampai ke hujung jauhnya. Anggap true sebagai “trafik keluar melalui sesuatu terowong” dan simpan kiraan anda sendiri secara berasingan. Boolean yang secara senyap bermaksud tiga perkara serentak ialah sebab skrin tetapan melaporkan VPN sebagai mati semasa pengguna melayari melaluinya.
Apabila sebaliknya anda perlu tahu sama ada mana-mana rangkaian VPN hadir, lelaran cm.getAllNetworks() dan uji setiap set keupayaan. Kedua-dua jawapan menyimpang pada peranti yang menjalankan VPN khusus apl yang meliputi aplikasi lain tetapi bukan apl anda, dan penyimpangan itulah punca kebanyakan laporan pepijat yang mengatakan apl tidak nampak VPN yang jelas menyala.
Perhati perubahan dan bukan meninjau berulang
Tinjauan berkala dengan pemasa ialah bentuk yang salah untuk soalan ini, kerana perubahan keadaan datang sebagai peristiwa. Daftarkan permintaan yang sepadan dengan pengangkutan VPN dan biarkan rangka kerja memberitahu anda apabila rangkaian yang sepadan muncul, hilang atau berubah:
NetworkRequest request = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_VPN)
.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
.build();
cm.registerNetworkCallback(request, callback);
Rangkaian VPN tidak pernah membawa NET_CAPABILITY_NOT_VPN, jadi penyingkiran eksplisit itu mendokumenkan niat. Tanpanya permintaan masih sepadan, tetapi orang seterusnya yang membaca kod perlu memikirkannya sendiri.
Pendaftaran tergolong dalam skop yang memerlukan pemerhatian, biasanya skrin atau perkhidmatan latar hadapan. Nyahdaftar dalam onStop atau onDestroy, dan jangan tinggalkan callback terlekat pada aktiviti yang sudah tiada. Apl tanpa komponen yang kelihatan ialah perumah yang buruk untuk pemerhati kekal, dan callback yang anda lupa itulah yang ranap selepas perubahan konfigurasi.
Asingkan tiga soalan
Kebanyakan kekeliruan dalam bidang ini datang daripada menganggap tiga semakan berbeza sebagai satu. Ia menggunakan API berbeza, dan setiap satu boleh benar semasa yang lain palsu.
| 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 |
Baris ketiga ialah yang orang cuba jawab pada klien, dan ia tidak boleh dijawab di situ. Beri klien VPN kolam alamat sendiri dan baca alamat sumber pada pelayan; itulah satu-satunya bukti yang bertahan apabila pengguna menukar terowong di tengah sesi.
Urutan pengesahan yang menolak positif palsu
Kod contoh lama yang masih tersebar memanggil getNetworkInfo(ConnectivityManager.TYPE_VPN). Panggilan itu sudah usang, dan pada beberapa keluaran ia memulangkan null walaupun VPN disambungkan, sebab itulah banyak coretan yang disalin kelihatan rosak pada peranti yang berfungsi. Semakan keupayaan mengelakkan perangkap itu dan berkelakuan sama sejak Android 5.0. Jika anda menyelenggara pangkalan kod yang masih memanggilnya, ganti panggilan itu dan bukan membungkusnya dalam sandaran, kerana sandaran itulah yang menghasilkan jawapan salah pada mulanya.
Satu jalan pintas patut diberi amaran. Membandingkan alamat awam yang dilaporkan oleh perkhidmatan luaran dengan alamat keluar VPN memang membuktikan sesuatu tentang laluan, tetapi ia menambah permintaan pihak ketiga pada setiap semakan, bergantung pada perkhidmatan itu kekal hidup, dan boleh dicache atau disekat. Simpan ia sebagai diagnostik manual, jangan sekali-kali sebagai semakan keadaan di dalam apl.
Jalankan semakan mengikut urutan ini dan berhenti pada yang pertama yang tidak bersetuju dengan laporan pengguna: senarai pengangkutan shell, keupayaan rangkaian aktif, peristiwa callback semasa anda menghidupkan dan mematikan terowong, kemudian alamat sumber di sebelah pelayan. Jika keempat-empatnya selaras dan apl masih salah laku, pepijat itu ada dalam mesin keadaan anda sendiri, bukan dalam pandangan Android tentang rangkaian.