如何从代码中获取设备的IP地址?

459

有没有可能使用一些代码获取设备的IP地址?


6
请记住,这是一个大小为N的集合,您不能假设N ==(0 || 1)。换句话说,不要假设设备只有一种与网络通信的方式,也不要假定它根本没有与网络通信的方式。 - James Moore
相关:https://dev59.com/IGkx5IYBdhLWcg3wCP-Y - AlikElzin-kilaka
2
如何查看我的Android手机的IP地址? - Ciro Santilli OurBigBook.com
你应该从外部服务获取它,http://ipof.in/txt 就是这样的一个服务。 - vivekv
在Android中,是否可以通过编程方式获取它? - Tanmay Sahoo
请查看我的答案:https://dev59.com/ymQn5IYBdhLWcg3wkH3U#50871614 - Yong
32个回答

6

你可以使用LinkProperties。它适用于新的Android版本。

此功能可同时检索WiFi和移动数据的本地IP地址。它需要Manifest.permission.ACCESS_NETWORK_STATE权限。

@Nullable
public static String getDeviceIpAddress(@NonNull ConnectivityManager connectivityManager) {
    LinkProperties linkProperties = connectivityManager.getLinkProperties(connectivityManager.getActiveNetwork());
    InetAddress inetAddress;
    for(LinkAddress linkAddress : linkProperties.getLinkAddresses()) {
        inetAddress = linkAddress.getAddress();
        if (inetAddress instanceof Inet4Address
                && !inetAddress.isLoopbackAddress()
                && inetAddress.isSiteLocalAddress()) {
            return inetAddress.getHostAddress();
        }
    }
    return null;
}

1
“新的Android版本”指的是>= api 21(Android 5,https://developer.android.com/reference/android/net/ConnectivityManager#getLinkProperties(android.net.Network))。如果您想要接收特定网络的IP地址(只需将其作为参数传递给getLinkProperties),这也是首选方法。 - Maxdestroyer

6

在您的活动中,以下函数getIpAddress(context)返回手机的IP地址:

public static String getIpAddress(Context context) {
    WifiManager wifiManager = (WifiManager) context.getApplicationContext()
                .getSystemService(WIFI_SERVICE);

    String ipAddress = intToInetAddress(wifiManager.getDhcpInfo().ipAddress).toString();

    ipAddress = ipAddress.substring(1);

    return ipAddress;
}

public static InetAddress intToInetAddress(int hostAddress) {
    byte[] addressBytes = { (byte)(0xff & hostAddress),
                (byte)(0xff & (hostAddress >> 8)),
                (byte)(0xff & (hostAddress >> 16)),
                (byte)(0xff & (hostAddress >> 24)) };

    try {
        return InetAddress.getByAddress(addressBytes);
    } catch (UnknownHostException e) {
        throw new AssertionError();
    }
}

我得到了0.0.0.0 - natsumiyu
你的手机连接到了WiFi网络吗?如果你调用wifiManager.getConnectionInfo().getSSID(),会返回什么值? - matdev
1
它能在连接移动数据而非WiFi的设备上工作吗? - Sergio
不,只有当设备连接到WiFi时,此方法才会起作用。 - matdev

5
这是对这个答案的再次改进,它剔除了无关的信息,添加了有益的注释,更清晰地命名变量,并改善了逻辑。
不要忘记包括以下权限:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

InternetHelper.java:

public class InternetHelper {

    /**
     * Get IP address from first non-localhost interface
     *
     * @param useIPv4 true=return ipv4, false=return ipv6
     * @return address or empty string
     */
    public static String getIPAddress(boolean useIPv4) {
        try {
            List<NetworkInterface> interfaces =
                    Collections.list(NetworkInterface.getNetworkInterfaces());

            for (NetworkInterface interface_ : interfaces) {

                for (InetAddress inetAddress :
                        Collections.list(interface_.getInetAddresses())) {

                    /* a loopback address would be something like 127.0.0.1 (the device
                       itself). we want to return the first non-loopback address. */
                    if (!inetAddress.isLoopbackAddress()) {
                        String ipAddr = inetAddress.getHostAddress();
                        boolean isIPv4 = ipAddr.indexOf(':') < 0;

                        if (isIPv4 && !useIPv4) {
                            continue;
                        }
                        if (useIPv4 && !isIPv4) {
                            int delim = ipAddr.indexOf('%'); // drop ip6 zone suffix
                            ipAddr = delim < 0 ? ipAddr.toUpperCase() :
                                    ipAddr.substring(0, delim).toUpperCase();
                        }
                        return ipAddr;
                    }
                }

            }
        } catch (Exception ignored) { } // if we can't connect, just return empty string
        return "";
    }

    /**
     * Get IPv4 address from first non-localhost interface
     *
     * @return address or empty string
     */
    public static String getIPAddress() {
        return getIPAddress(true);
    }

}

4
public static String getdeviceIpAddress() {
    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 instanceof Inet4Address) {
                    return inetAddress.getHostAddress();
                }
            }
        }
    } catch (SocketException ex) {
        ex.printStackTrace();
    }
    return null;
}

1
这段代码帮助我获取了Hotspot的本地IP地址,对我来说是192.168.55.66。谢谢! - mihai71

3
WifiManager wm = (WifiManager) getSystemService(WIFI_SERVICE);
String ipAddress = BigInteger.valueOf(wm.getDhcpInfo().netmask).toString();

2

只需使用Volley从网站获取IP即可。

RequestQueue queue = Volley.newRequestQueue(this);    
String urlip = "http://checkip.amazonaws.com/";

    StringRequest stringRequest = new StringRequest(Request.Method.GET, urlip, new Response.Listener<String>() {
        @Override
        public void onResponse(String response) {
            txtIP.setText(response);

        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            txtIP.setText("didnt work");
        }
    });

    queue.add(stringRequest);

这是获取公共IP的程序,依赖于亚马逊AWS检查IP服务,该服务可能会在某一天更改或消失,并且仅在设备可以访问互联网时才能工作。在本地网络或离线时,它将无法工作。此外,请注意,checkip服务不安全,因此可能会被中间人伪造。要获取设备的IP地址列表,我们需要查询设备的网络接口列表(蜂窝数据、WiFi等),并获取非本地地址。 - Raphael C

2

最近,即使从网络断开(没有服务指示器),getLocalIpAddress()仍然返回一个IP地址。这意味着在“设置”>“关于手机”>“状态”中显示的IP地址与应用程序所认为的不同。

我已经通过添加以下代码来实现解决方法:

ConnectivityManager cm = getConnectivityManager();
NetworkInfo net = cm.getActiveNetworkInfo();
if ((null == net) || !net.isConnectedOrConnecting()) {
    return null;
}

这个问题有人记得吗?

2

在 Kotlin 中,可以不使用 Formatter

private fun getIPAddress(useIPv4 : Boolean): String {
    try {
        var interfaces = Collections.list(NetworkInterface.getNetworkInterfaces())
        for (intf in interfaces) {
            var addrs = Collections.list(intf.getInetAddresses());
            for (addr in addrs) {
                if (!addr.isLoopbackAddress()) {
                    var sAddr = addr.getHostAddress();
                    var isIPv4: Boolean
                    isIPv4 = sAddr.indexOf(':')<0
                    if (useIPv4) {
                        if (isIPv4)
                            return sAddr;
                    } else {
                        if (!isIPv4) {
                            var delim = sAddr.indexOf('%') // drop ip6 zone suffix
                            if (delim < 0) {
                                return sAddr.toUpperCase()
                            }
                            else {
                                return sAddr.substring(0, delim).toUpperCase()
                            }
                        }
                    }
                }
            }
        }
    } catch (e: java.lang.Exception) { }
    return ""
}

2
一个设备可能有多个IP地址,而在特定应用程序中使用的IP地址可能不是接收请求的服务器将看到的IP地址。实际上,一些用户使用VPN或代理,例如Cloudflare Warp
如果您的目的是获取从您的设备发送请求的服务器所显示的IP地址,则最好查询IP地理位置服务,例如Ipregistry(免责声明:我为该公司工作),并使用其Java客户端:

https://github.com/ipregistry/ipregistry-java

IpregistryClient client = new IpregistryClient("tryout");
RequesterIpInfo requesterIpInfo = client.lookup();
requesterIpInfo.getIp();

除了非常简单易用之外,您还可以获得其他信息,例如国家、语言、货币以及设备IP的时区,并且您可以确定用户是否使用代理。

2
这是互联网上存在的最简单和简单的方法... 首先,将此权限添加到您的清单文件中...
  1. "INTERNET"

  2. "ACCESS_NETWORK_STATE"

在Activity的onCreate文件中添加以下内容...
    getPublicIP();
现在将此函数添加到您的MainActivity.class中。

    private void getPublicIP() {
ArrayList<String> urls=new ArrayList<String>(); //to read each line

        new Thread(new Runnable(){
            public void run(){
                //TextView t; //to show the result, please declare and find it inside onCreate()

                try {
                    // Create a URL for the desired page
                    URL url = new URL("https://api.ipify.org/"); //My text file location
                    //First open the connection
                    HttpURLConnection conn=(HttpURLConnection) url.openConnection();
                    conn.setConnectTimeout(60000); // timing out in a minute

                    BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));

                    //t=(TextView)findViewById(R.id.TextView1); // ideally do this in onCreate()
                    String str;
                    while ((str = in.readLine()) != null) {
                        urls.add(str);
                    }
                    in.close();
                } catch (Exception e) {
                    Log.d("MyTag",e.toString());
                }

                //since we are in background thread, to post results we have to go back to ui thread. do the following for that

                PermissionsActivity.this.runOnUiThread(new Runnable(){
                    public void run(){
                        try {
                            Toast.makeText(PermissionsActivity.this, "Public IP:"+urls.get(0), Toast.LENGTH_SHORT).show();
                        }
                        catch (Exception e){
                            Toast.makeText(PermissionsActivity.this, "TurnOn wiffi to get public ip", Toast.LENGTH_SHORT).show();
                        }
                    }
                });

            }
        }).start();

    }


urls.get(0) 包含了你的公共 IP 地址。 - Zia
你必须在你的活动文件中这样声明: ArrayList<String> urls=new ArrayList<String>(); // 用于读取每一行。 - Zia
连接手机网络时无法工作。在这种情况下如何获取公共IP? - Bhaskar Jha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接