Jūsu lietotne izsauc VpnService.prepare, saņem null, izveido tuneli, un deskriptors izskatās derīgs, tomēr nekas nesasniedz serveri. Vai arī prepare atgriež Intent, lietotājs to apstiprina, un establish joprojām neizdodas. Abi rezultāti parasti nozīmē vienu un to pašu: cita lietotne jau pārvalda šī lietotāja VPN saskarni, un jūsu protect izsaukumi atzīmē ligzdas, kuras jūsu tunelis nevar izmantot. Pārskatiet zemāk esošās pārbaudes secīgi un apstājieties pie pirmās, kas neizdodas, jo vēlāks solis nevar salabot iepriekšējo.

Pārbaudiet VPN vietu, pirms aiztiecat protect

Android piešķir katram lietotājam tieši vienu aktīvu VPN saskarni. Tas ir platformas noteikums, nevis atļauja, ko jūsu lietotne var pieprasīt, tāpēc divi klienti, kas abi grib būt tunelis, nevar pastāvēt kopā.

Citas lietotnes iestatīts vienmēr ieslēgts VPN ir grūtākais gadījums, jo sistēma uztur šo lietotni savienotu un atsakās no pārņemšanas. Trafika filtrs, piemēram, AdGuard, uzņēmuma klients vai patērētāju VPN, var aizņemt vietu, kamēr lietotājs ir aizmirsis, ka tas ir instalēts. Lūdziet lietotājam atvērt Iestatījumus un nolasīt ierakstu, kas norādīts sadaļā VPN; tur esošais nosaukums ir īpašnieks, ar kuru jūs konkurējat. Kamēr šis ieraksts nav atvienots vai vienmēr ieslēgts iestatījums nav notīrīts, jūsu VpnService nevar kļūt par saskarni.

1. solis: nolasiet, ko atgriež prepare

VpnService.prepare atbild uz vienu jautājumu: vai šī lietotne drīkst kļūt par VPN? Tas atgriež null, ja piekrišana jau ir, un Intent, ja lietotājam tā vēl jāapstiprina, kas jāpalaiž ar startActivityForResult. Uztveriet null atgriešanu kā atļauju turpināt, nevis kā pierādījumu, ka establish izdosies.

Intent intent = VpnService.prepare(context);
if (intent != null) {
    startActivityForResult(intent, REQUEST_VPN);
}

Ja Intent ceļš atgriežas un lietotājs ir atteicies, prepare turpinās atgriezt Intent nākamajā mēģinājumā. Reģistrējiet rezultāta kodu, nevis mēģiniet vēlreiz cilpā, jo atteikta piekrišana ir lietotāja lēmums, nevis īslaicīga kļūda.

2. solis: apstipriniet, ka saskarne pieder jūsu lietotnei

Pēc establish saņemtais ParcelFileDescriptor ir jūsu īpašumtiesību pierādījums, un to ir vērts pārbaudīt pirms jebkura darba ar ligzdām. Deskriptors, kas ir null vai jau aizvērts, nozīmē, ka saskarne nekad netika izveidota, pat ja izņēmums neparādījās. Salīdziniet saskarnes nosaukumu no builder ar to, ko sistēma norāda aktīvajam VPN, izmantojot dumpsys testa ierīcē. Ja tie atšķiras, jūsu izveidotais tunelis nav tunelis, kas pārvadā trafiku.

adb shell dumpsys connectivity

Tā pati neatbilstība izskaidro savienotu ikonu ar mirušu trafiku. Sistēma rāda otras lietotnes tuneli, kamēr jūsu kods tur deskriptoru saskarnei, kas tam nepieder.

3. solis: izsauciet protect pirms connect

Kad saskarne pastāv, ligzdas, ko atver jūsu lietotne, pēc noklusējuma tiek maršrutētas tunelī. Ārējais transports nevar ievērot šo noteikumu, citādi iekapsulētā pakete atgrieztos saskarnē, tāpēc VpnService protect atzīmē ligzdu, lai apietu VPN un izmantotu pamata tīklu. Izsaukums atgriež boolean, un tā ignorēšana ir ceļš, kā nonākt pie ligzdas, kas izskatās vesela un neko nepārvadā.

Izsauciet protect pirms connect vai bind, nekad pēc. Aizsardzībai jābūt vietā, pirms ligzda tiek savienota vai saistīta, jo savienota ligzda jau ir izvēlējusies maršrutu, un vēlāks protect to droši nepārvieto. Ja protect atgriež false, apstājieties un vēlreiz pārbaudiet īpašumtiesības: tas neizdodas, ja saskarne nepieder jūsu lietotnei, un tieši tāds ir stāvoklis, ko atstāj cits VPN. false atgriešana ir signāls atgriezties pie 1. soļa, nevis atkārtot to pašu ligzdu.

DatagramSocket socket = new DatagramSocket();
if (!vpnService.protect(socket)) {
    return;
}
socket.connect(serverAddress, serverPort);

4. solis: saistiet procesu, kad ligzda ir neērta

Daži transporti nav viena ligzda: bibliotēka var atvērt vairākas, vai arī jūs varat vēlēties, lai katrs savienojums palīgprocesā izmantotu to pašu izeju. ConnectivityManager.bindProcessToNetwork saista procesu ar izvēlētu tīklu, un vecākais setProcessDefaultNetwork darīja to pašu, pirms tika atzīts par novecojušu. Pieprasiet pamata savienojumu ar NET_CAPABILITY_NOT_VPN, lai saistīšana izvēlētos tīklu zem jūsu tuneļa, nevis pašu tuneli.

NetworkRequest request = new NetworkRequest.Builder()
    .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
    .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
    .build();

Procesa saistīšana nav otrs VPN. Tā izvēlas izeju šim procesam, kas ir noderīgi jūsu transportam un bezjēdzīgi divu tuneļu vienlaicīgai darbināšanai.

Labojiet lietotāja ierīci, nevis koda ceļu

Nav API, kas ļautu divām lietotnēm dalīt VPN vietu, tāpēc labojums attiecas uz ierīces stāvokli. Piedāvājiet lietotājam divus konkrētus ceļus: atvienojiet vai notīriet vienmēr ieslēgts otrai lietotnei, lai jūsu prepare varētu pārņemt, vai atveriet tās lietotnes iestatījumus pa lietotnēm un izslēdziet savu lietotni no tās tuneļa. Izslēgšana uztur filtru darbojamies visam pārējam un ļauj jūsu lietotnei izmantot parasto savienojumu, kas bieži ir rezultāts, ko lietotājs patiešām vēlas.

Ierakstiet abus ceļus savā atbalsta dokumentācijā, jo lietotāji reti zina, kura lietotne pārvalda VPN. Lūdziet viņiem atsūtīt aktīvā VPN nosaukumu no Iestatījumiem un prepare, establish un protect rezultātus no jūsu žurnāliem, un minūtes laikā varat pateikt, kurš solis neizdevās. Pēc tam pārbaudiet ar reālu trafiku: nosaukuma vaicājumu, TCP savienojumu un vienu pieprasījumu caur tuneli, nevis tikai savienotu ikonu. Derīgs deskriptors un zaļš indikators labākajā gadījumā pierāda īpašumtiesības, bet nekad to, ka transports pārdzīvoja maršrutēšanas noteikumus.

Ja visas četras pārbaudes iztur un trafiks joprojām mirst, īpašumtiesības vairs nav jūsu problēma. Pārejiet pie maršrutēšanas un servera sasniedzamības, un pārbaudiet tos pašus akreditācijas datus ierīcē, kurā nav instalēta VPN lietotne.

Saistītie raksti