Aplikacja Android nie potrafi rozwiązać nazwy wewnętrznej, choć przeglądarka samego klienta VPN ją osiąga, a ten sam build działa na innym telefonie. URL nie jest zmienną. Zmienną jest to, której sieci proces aplikacji może używać do rozwiązywania, a Android nie gwarantuje, że aktywny VPN to sieć, której używają twoje gniazda. Wykonaj te kontrole po kolei i zatrzymaj się, gdy obraz resolvera nie zgadza się z twoim założeniem.

Krok 1: udowodnij, w której sieci jest aplikacja

Czytaj własny widok aplikacji, a nie pasek stanu. Z ConnectivityManager pobierz aktywną sieć, jej LinkProperties, listę serwerów DNS i ustawienie prywatnego DNS. Jeśli lista zawiera resolver VPN, aplikacja ma do niego ścieżkę; jeśli zawiera resolver Wi-Fi, tunel nie jest siecią domyślną dla tego procesu.

Ikona VPN mówi tylko, że tunel istnieje. Nie mówi, że proces aplikacji był do niego przypisany, a Android nie zawsze kieruje rozwiązywanie nazw przez sieć, która wygląda na aktywną. Lokalne aplikacje VPN przekazujące ruch do innego urządzenia, sieci Wi-Fi bez internetu i buildy producentów mogą zostawić aplikację pytającą domyślny resolver zamiast serwerów tunelu.

Krok 2: zażądaj transportu VPN i powiąż proces

Gdy aplikacja musi używać resolvera tunelu, zażądaj sieci z transportem VPN i powiąż proces w wywołaniu zwrotnym, aby kod nie zgadywał, kiedy pojawi się sieć:

val request = NetworkRequest.Builder()
    .addTransportType(NetworkCapabilities.TRANSPORT_VPN)
    .build()

connectivityManager.requestNetwork(request, object : NetworkCallback() {
    override fun onAvailable(network: Network) {
        val bound = connectivityManager.bindProcessToNetwork(network)
        Log.i(TAG, "bound to VPN network: " + bound)
    }
})

Wywołanie zmienia domyślną sieć całego procesu, więc każde gniazdo utworzone później jej używa. Gniazda, które już istnieją, zachowują sieć, w której powstały, dlatego pula połączeń otwarta przed powiązaniem może nadal rozwiązywać starą ścieżką. Zwracana wartość jest typu boolean, a wynik false oznacza, że powiązanie nie nastąpiło; spróbuj ponownie z krótkim opóźnieniem i zapisz obie próby.

Krok 3: ogranicz powiązanie do tego, co go potrzebuje

Powiązanie całego procesu jest grubiańskie. Telemetria, sprawdzanie aktualizacji i SDK firm trzecich też przechodzą na tunel, a jeśli tunel nie ma internetu, zaczynają zawodzić. Dla jednego żądania użyj fabryki gniazd sieci, a wszystko inne zostaw na domyślnym ustawieniu urządzenia. Wybierz świadomie jeden model: wąskie powiązanie na połączenie albo powiązanie procesu z jawnym odwiązaniem, gdy VPN zniknie.

Dwie funkcje resolvera mogą pokonać powiązanie bez żadnego błędu. Prywatny DNS w trybie ścisłym wysyła zapytania do nazwanego serwera DoT zamiast do resolvera sieci, a aplikacja z własnym klientem DNS-over-HTTPS całkowicie omija resolver systemowy. Sprawdź oba, zanim uznasz, że powiązanie zawiodło. Zapytanie, które nigdy nie dotrze do serwera DNS VPN, nie pojawi się w żadnym logu po stronie tunelu.

Krok 4: nie ufaj ograniczeniu CONNECTED

NetworkType.CONNECTED w WorkManager oznacza, że sieć jest połączona, a transport VPN spełnia to nawet wtedy, gdy leżące pod spodem łącze Wi-Fi lub komórkowe zniknęło. Zadanie działa, każde żądanie zawodzi, a polityka ponowień zamienia to w burzę, która wygląda jak błąd planowania. Tunel to sieć; to ograniczenie nigdy nie było kontrolą internetu.

Sprawdź możliwość, której praca naprawdę potrzebuje, na przykład potwierdzony dostęp do internetu, i utrzymuj ograniczoną politykę ponowień z wycofywaniem. Jeśli zadanie potrzebuje prywatnej nazwy, rozwiąż tę nazwę w wybranej sieci przed wykonaniem pracy i zawiedź szybko z jasnym błędem, zamiast powtarzać żądanie, które nie może się udać.

Krok 5: zapisz dowody i ponownie przetestuj zakres

Zapisz typy transportu wybranej sieci, serwery DNS z LinkProperties, czy powiązanie zwróciło true, oraz dokładny błąd pierwszego żądania. Następnie uruchom prywatną nazwę i nazwę publiczną pod tym samym powiązaniem. Ta para pokazuje, czy aplikacja użyła resolvera tunelu, czy po cichu wróciła do domyślnego ustawienia urządzenia, i to jest różnica, której doświadcza użytkownik.

Powtórz to na najstarszej obsługiwanej wersji Androida i na jednym bieżącym wydaniu. Zachowanie resolvera, które sprawia, że domyślna ścieżka wygląda poprawnie, jest dokładnie tym miejscem, w którym urządzenia i wersje się różnią, a build, który przechodzi tylko na najnowszym urządzeniu testowym, nie został zweryfikowany dla zakresu, który wysyłasz. adb shell dumpsys connectivity to szybki sposób potwierdzenia, jakie sieci i możliwości zgłasza urządzenie, gdy reprodukujesz awarię.

Powiązane artykuły