許多 Android 開發者在真機或模擬器上呼叫 NetworkInterface.getNetworkInterfaces() 遍歷 IP 時,發現取得的永遠是 10.0.2.15,但系統設定裡顯示的卻是 10.88.x.x 或 WiFi 下的 10.225.x.x。這到底發生了什麼事?
public String getLocalIpAddress() {
try {
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (!inetAddress.isLoopbackAddress() && !inetAddress.isLinkLocalAddress()) {
return inetAddress.getHostAddress();
}
}
}
} catch (SocketException ex) {
Log.e("WifiPreference IpAddress", ex.toString());
}
return null;
}
10.0.2.15 是 Android 模擬器預設給客體(Guest OS)的私有 IP。模擬器啟動時會建立一個虛擬網路:
10.0.2.210.0.2.15因此 NetworkInterface 枚舉到的第一張非回環、非 Link-Local 介面通常是 eth0(虛擬乙太網卡),其 IP 正是 10.0.2.15。
getNetworkInterfaces() 回傳順序由底層驅動決定,可能先拿到 rmnet_data0(行動數據)或 wlan0(WiFi),甚至 lo(回環)的下一個。public String getWifiIpv4() {
try {
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
NetworkInterface intf = en.nextElement();
if (!intf.getName().startsWith("wlan")) continue; // 只看 WiFi
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
InetAddress inetAddress = enumIpAddr.nextElement();
if (inetAddress instanceof Inet4Address && !inetAddress.isLoopbackAddress()) {
return inetAddress.getHostAddress();
}
}
}
} catch (SocketException e) {
e.printStackTrace();
}
return null;
}
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
Network activeNet = cm.getActiveNetwork();
if (activeNet != null) {
NetworkCapabilities caps = cm.getNetworkCapabilities(activeNet);
if (caps != null && caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
// 繫結到該 Network 再取 IP,確保拿到正確介面
}
}
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <!-- Android 10+ 需要 -->
10.0.2.15 不是 Bug,是模擬器 NAT 架構的必然產物。真機上則是介面遍歷順序導致。解決關鍵在於明確指定想要的介面類型(wlan/rmnet),而非盲目取第一個符合條件的 IP。