睿诚科技协会

Android网络IP如何获取与配置?

核心概念

在开始之前,先明确几个关键概念:

Android网络IP如何获取与配置?-图1
(图片来源网络,侵删)
  1. IP 地址:设备在网络中的唯一标识,分为 IPv4(如 168.1.101)和 IPv6`(如 2001:0db8:85a3:0000:0000:8a2e:0370:7334),Android 开发中需要同时兼容两者。
  2. Wi-Fi 和移动数据:Android 设备可以通过多种方式连接网络,最常见的是 Wi-Fi 和移动蜂窝网络(如 4G/5G),获取 IP 地址时需要考虑当前活动的网络类型。
  3. 网络接口:设备上的每个网络连接(如 Wi-Fi、以太网)都是一个网络接口,每个接口都有自己的 IP 地址。
  4. 权限:从 Android 6.0 (API 23) 开始,部分网络相关权限需要动态请求,但获取本机 IP 地址不需要任何特殊权限。

如何获取本机设备的 IP 地址

获取本机 IP 地址是最常见的需求,通常用于网络调试、设备发现等场景。

获取 Wi-Fi IP 地址

这是最常用的场景,我们可以通过 WifiManager 来获取。

步骤:

  1. 添加权限:在 AndroidManifest.xml 中声明 ACCESS_WIFI_STATE 权限。

    Android网络IP如何获取与配置?-图2
    (图片来源网络,侵删)
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
  2. 获取 WifiManager 并查询 IP 地址

    import android.content.Context;
    import android.net.wifi.WifiManager;
    import android.text.format.Formatter;
    // ...
    public String getWifiIpAddress(Context context) {
        WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
        if (wifiManager != null && wifiManager.isWifiEnabled()) {
            // 获取 WifiInfo 对象
            android.net.wifi.WifiInfo wifiInfo = wifiManager.getConnectionInfo();
            // 获取 IP 地址的整数表示
            int ipAddress = wifiInfo.getIpAddress();
            // 将整数 IP 地址格式化为字符串 (IPv4)
            return Formatter.formatIpAddress(ipAddress);
        }
        return "Wi-Fi is disabled or not available";
    }

注意

  • getIpAddress() 返回的是一个 int168.1.101 会被表示为整数 3232235781Formatter.formatIpAddress() 会帮我们把它转换回点分十进制的字符串。
  • 这种方法只支持 IPv4,对于现代设备,如果连接的是 IPv6 网络,此方法将无法工作。
  • 从 Android 10 (API 29) 开始,对非前台应用访问 Wi-Fi 信息有了更多限制,确保你的应用在前台时调用此方法或处理可能的 SecurityException

获取移动数据 (蜂窝网络) IP 地址

获取移动网络的 IP 地址没有直接的 API,因为它通常由运营商动态分配,我们可以通过查询网络接口来实现。

使用 ConnectivityManagerNetwork API (推荐 - Android 7.0+)

Android网络IP如何获取与配置?-图3
(图片来源网络,侵删)

这是现代 Android 开发推荐的方式,可以同时处理 IPv4 和 IPv6。

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.os.Build;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.List;
// ...
public String getMobileIpAddress(Context context) {
    ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    if (connectivityManager == null) {
        return "ConnectivityManager is null";
    }
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        // 获取当前活动的网络
        Network network = connectivityManager.getActiveNetwork();
        if (network == null) {
            return "No active network";
        }
        // 获取网络能力
        NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(network);
        if (capabilities == null || !capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
            return "Not on a mobile network";
        }
        try {
            // 从网络获取所有 IP 地址列表
            List<InetAddress> addresses = Collections.list(network.getSocketFactory().getInetAddress());
            for (InetAddress address : addresses) {
                // 排回环地址 (127.0.0.1)
                if (!address.isLoopbackAddress()) {
                    String hostAddress = address.getHostAddress();
                    // 确保返回的是 IPv4 或 IPv6 地址,而不是 % 后缀的接口名
                    if (hostAddress != null && (hostAddress.indexOf(':') < 0)) {
                        return hostAddress;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    return "Unable to get mobile IP";
}

通用方法:获取当前活动网络的 IP 地址

我们可以将上述方法结合,写一个通用的方法来获取当前活动网络(无论是 Wi-Fi 还是移动数据)的 IP 地址。

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.os.Build;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.List;
// ...
public String getActiveNetworkIpAddress(Context context) {
    ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    if (connectivityManager == null) {
        return "ConnectivityManager is null";
    }
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        Network network = connectivityManager.getActiveNetwork();
        if (network == null) {
            return "No active network";
        }
        try {
            List<InetAddress> addresses = Collections.list(network.getSocketFactory().getInetAddress());
            for (InetAddress address : addresses) {
                if (!address.isLoopbackAddress()) {
                    String hostAddress = address.getHostAddress();
                    // 返回第一个非回环的 IP 地址
                    if (hostAddress != null) {
                        return hostAddress;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    } else {
        // 对于旧版本,可以尝试分别查询 Wi-Fi 和移动网络
        // ... (略)
    }
    return "Unable to get IP";
}

如何获取远程服务器的 IP 地址

获取远程服务器的 IP 地址非常简单,就是标准的 Java 网络编程。

使用 InetAddress

import java.net.InetAddress;
import java.net.UnknownHostException;
// ...
public String getServerIpAddress(String domainName) {
    try {
        // 通过域名获取 IP 地址
        InetAddress inetAddress = InetAddress.getByName(domainName);
        // 获取主机地址 (IPv4 或 IPv6)
        return inetAddress.getHostAddress();
    } catch (UnknownHostException e) {
        e.printStackTrace();
        return "Unable to resolve host: " + domainName;
    }
}
// 使用示例
String serverIp = getServerIpAddress("www.google.com");
Log.d("ServerIP", serverIp); // 输出类似: 142.250.199.100 或 2a00:1450:4001:80a::2004

高级主题:获取本机所有 IP 地址和 MAC 地址

有时候你可能需要获取设备所有网络接口的详细信息。

获取所有网络接口信息 (使用 NetworkInterface)

import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Collections;
import java.util.List;
// ...
public void getAllNetworkInterfacesInfo() {
    try {
        List<NetworkInterface> networkInterfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
        for (NetworkInterface ni : networkInterfaces) {
            // 排除虚拟接口
            if (ni.isUp() && !ni.isLoopback()) {
                byte[] macBytes = ni.getHardwareAddress();
                if (macBytes != null) {
                    StringBuilder macString = new StringBuilder();
                    for (byte b : macBytes) {
                        macString.append(String.format("%02X:", b));
                    }
                    if (macString.length() > 0) {
                        macString.deleteCharAt(macString.length() - 1);
                    }
                    Log.d("NetworkInfo", "Name: " + ni.getName() + ", Display Name: " + ni.getDisplayName() + ", MAC: " + macString.toString());
                }
                List<InetAddress> inetAddresses = Collections.list(ni.getInetAddresses());
                for (InetAddress inetAddress : inetAddresses) {
                    if (!inetAddress.isLoopbackAddress()) {
                        String ipHostAddress = inetAddress.getHostAddress();
                        // 筛选出 IPv4 或 IPv6
                        if (ipHostAddress.indexOf(':') < 0) { // IPv4
                            Log.d("NetworkInfo", "IPv4: " + ipHostAddress);
                        } else { // IPv6
                            Log.d("NetworkInfo", "IPv6: " + ipHostAddress);
                        }
                    }
                }
            }
        }
    } catch (SocketException e) {
        e.printStackTrace();
    }
}

获取 Wi-Fi MAC 地址

import android.content.Context;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
// ...
public String getWifiMacAddress(Context context) {
    WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
    if (wifiManager != null) {
        WifiInfo info = wifiManager.getConnectionInfo();
        if (info != null) {
            return info.getMacAddress();
        }
    }
    return "02:00:00:00:00:00"; // 如果获取失败,返回一个默认的 MAC 地址
}

⚠️ 重要提醒 (Android 10+): 从 Android 10 开始,为了增强用户隐私,系统会为所有应用随机化设备的 MAC 地址,除非你的应用被授予 ACCESS_FINE_LOCATION 权限并且位置服务已开启,在 Android 10 及以上版本,即使不请求位置权限,getMacAddress() 返回的也可能是随机地址或 02:00:00:00:00:00 这样的空地址,获取 MAC 地址的正确方式是请求位置权限。


常见问题与最佳实践

  1. 主线程网络操作:永远不要在主线程(UI 线程)上执行网络请求或 IP 查询等耗时操作,否则会抛出 NetworkOnMainThreadException,应使用 AsyncTaskThreadExecutorService 或现代的 Coroutines/RxJava

  2. 网络权限

    • INTERNET:允许应用程序打开网络套接字,几乎所有网络应用都需要。
    • ACCESS_NETWORK_STATE:允许应用程序查看网络状态,推荐用于检测网络连接变化。
    • ACCESS_WIFI_STATE:允许应用程序访问 Wi-Fi 网络状态信息,如需获取 Wi-Fi 的 IP 或 MAC 地址,需要此权限。
    • ACCESS_FINE_LOCATION:在 Android 10+ 上,获取真实的 Wi-Fi MAC 地址需要此权限和用户授权。
  3. IPv6 的普及:新项目应默认支持 IPv6,使用 ConnectivityManagerNetwork API 可以很好地处理双栈网络,而旧的 WifiManager 方法仅支持 IPv4。

  4. 处理无网络情况:在获取 IP 之前,务必检查网络是否可用。

    ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    Network activeNetwork = cm.getActiveNetwork();
    NetworkCapabilities caps = cm.getNetworkCapabilities(activeNetwork);
    boolean isConnected = caps != null && (caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) || caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR));
    if (!isConnected) {
        // 处理无网络逻辑
    }
需求 推荐方法 关键 API/类 备注
获取 Wi-Fi IPv4 WifiManager WifiManager, WifiInfo, Formatter 仅限 IPv4,旧方法。
获取活动网络 IP ConnectivityManager + Network ConnectivityManager, Network, InetAddress 现代推荐方法,支持 IPv4/IPv6。
获取服务器 IP InetAddress InetAddress.getByName() 标准 Java 网络编程。
获取 MAC 地址 WifiManager (旧) 或 NetworkInterface (新) WifiInfo.getMacAddress(), NetworkInterface Android 10+ 需位置权限才能获取真实 MAC。
获取所有接口信息 NetworkInterface NetworkInterface 可用于调试,获取所有 IP 和 MAC。

希望这份详细的指南能帮助你更好地处理 Android 中的网络 IP 相关问题!

分享:
扫描分享到社交APP
上一篇
下一篇