簡體   English   中英

檢查 Android 中的 VPN 連接是否處於活動狀態?

[英]Check if a VPN connection is active in Android?

我的無根 Android 4.4 設備上有一個第三方 VPN 應用程序,我想編寫一個后台服務來監視 VPN 連接並在 VPN 連接斷開時提醒用戶。

有沒有辦法做到這一點? 我找不到任何使用 VPNService API 的方法。

感謝:D

使用NetworkCapabilities對我NetworkCapabilities 您必須遍歷所有現有網絡並檢查哪個具有VPN_TRANSPORT

ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
Network[] networks = cm.getAllNetworks();

Log.i(TAG, "Network count: " + networks.length);
for(int i = 0; i < networks.length; i++) {

  NetworkCapabilities caps = cm.getNetworkCapabilities(networks[i]);

  Log.i(TAG, "Network " + i + ": " + networks[i].toString());
  Log.i(TAG, "VPN transport is: " + caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN));
  Log.i(TAG, "NOT_VPN capability is: " + caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN));

}

這對我有用:從 API 16 到 23 測試:

List<String> networkList = new ArrayList<>();
try {
    for (NetworkInterface networkInterface : Collections.list(NetworkInterface.getNetworkInterfaces())) {
        if (networkInterface.isUp())
            networkList.add(networkInterface.getName());
    }
} catch (Exception ex) {
    Timber.d("isVpnUsing Network List didn't received");
}

return networkList.contains("tun0");

PS它也可以是另一個名為“ppp0”的網絡接口,但在我對不同VPN應用程序的測試中,它總是“tun0”

遲到的答案,在 Android 16 <-> 29上測試:

public boolean vpn() {
    String iface = "";
    try {
        for (NetworkInterface networkInterface : Collections.list(NetworkInterface.getNetworkInterfaces())) {
            if (networkInterface.isUp())
                iface = networkInterface.getName();
                Log.d("DEBUG", "IFACE NAME: " + iface);
            if ( iface.contains("tun") || iface.contains("ppp") || iface.contains("pptp")) {
                return true;
            }
        }
    } catch (SocketException e1) {
        e1.printStackTrace();
    }

    return false;
}

以上不適用於wireguard,因為接口名稱可以是任何內容(通常是連接名稱)。

檢查活動網絡是否正在使用 VPN 的替代方法:

Network activeNetwork = connectivityManager.getActiveNetwork();
NetworkCapabilities caps = connectivityManager.getNetworkCapabilities(activeNetwork);
boolean vpnInUse = caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN);

這里是kotlin coroutines flow解決方案

val isVpnActiveFlow = callbackFlow {
        val connectivityManager =
            context.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
        if (connectivityManager == null) {
            channel.close(IllegalStateException("connectivity manager is null"))
            return@callbackFlow
        } else {
            val callback = object : ConnectivityManager.NetworkCallback() {
                override fun onAvailable(network: Network) {
                    channel.trySend(true)
                }

                override fun onLost(network: Network) {
                    channel.trySend(false)
                }
            }
            connectivityManager.registerNetworkCallback(
                //I have to investigate on this builder!
                NetworkRequest.Builder()
                    .addTransportType(NetworkCapabilities.TRANSPORT_VPN)
                    .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
                    .build(),
                callback
            )
            awaitClose {
                connectivityManager.unregisterNetworkCallback(callback)
            }
        }
    }

編寫一個點擊內部頁面或 ping 內部站點的小應用程序...

HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(internal_url);
HttpResponse response = client.execute(request);

String html = "";
InputStream in = response.getEntity().getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
StringBuilder str = new StringBuilder();
String line = null;
while((line = reader.readLine()) != null)
{
    str.append(line);
}
in.close();
html = str.toString();

或者

String str = "";
try 
{
    Process process = Runtime.getRuntime().exec(
            "/system/bin/ping -c 8 " + internal_url);
    BufferedReader reader = new BufferedReader(new InputStreamReader(
            process.getInputStream()));
    int i;
    char[] buffer = new char[4096];
    StringBuffer output = new StringBuffer();
    while ((i = reader.read(buffer)) > 0)
        output.append(buffer, 0, i);
    reader.close();


    str = output.toString();

} 
catch (IOException e)
{

    e.printStackTrace();
}
return str;

檢查網絡信息如何? 如果一個人有一種 VPN,我會假設有一個 VPN 連接。

需要 ACCESS_NETWORK_STATE 權限。

            List<NetworkInfo> connectedNetworks    = new ArrayList<>();

        if (Build.VERSION.SDK_INT >= 21)
            {
            Network[] networks = m_ConnectivityManager.getAllNetworks();

            for (Network n : networks)
                {
                NetworkInfo ni = m_ConnectivityManager.getNetworkInfo(n);

                if (ni.isConnectedOrConnecting())
                    {
                    connectedNetworks.add(ni);
                    }
                }
            }
        else
            {
            NetworkInfo[] nis = m_ConnectivityManager.getAllNetworkInfo();

            for (NetworkInfo ni : nis)
                {
                if (ni.isConnectedOrConnecting())
                    {
                    connectedNetworks.add(ni);
                    }
                }
            }

        boolean bHasVPN = false;

        if (Build.VERSION.SDK_INT >= 21)
            {
            for (NetworkInfo ni : connectedNetworks)
                {
                bHasVPN |= (ni.getType() == ConnectivityManager.TYPE_VPN);
                }
            }

這也適用於 API < 21:

ConnectivityManager manager = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
        NetworkInfo[] infos=manager.getAllNetworkInfo();
        boolean VPNConnected = false;
        for (NetworkInfo info : infos){
            if ("VPN".equalsIgnoreCase(info.getTypeName()){
                if (info.getState() == NetworkInfo.State.CONNECTED){
                    VPNConnected = true;
                    break;
                }
            }
        }

我為自己編寫了一個適用於 API 21 及更高版本的輔助函數。

public static boolean vpnActive(Context context){

        //this method doesn't work below API 21
        if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
            return false;

        boolean vpnInUse = false;

        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);


        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {

            Network activeNetwork = connectivityManager.getActiveNetwork();
            NetworkCapabilities caps = connectivityManager.getNetworkCapabilities(activeNetwork);

            return caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
        }

        Network[] networks = connectivityManager.getAllNetworks();

        for(int i = 0; i < networks.length; i++) {

            NetworkCapabilities caps = connectivityManager.getNetworkCapabilities(networks[i]);
        if(caps.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) {
            vpnInUse = true;
            break;
        }
    }

    return vpnInUse;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM