Android中获取WiFi已连接设备IP地址的方法求助(附尝试代码)
Android 获取同WiFi网络下已连接设备IP的解决方案
原代码存在的问题
- 废弃API使用:
Formatter.formatIpAddress已被官方废弃,高版本Android系统中可能无法正常工作 - 主线程阻塞:在UI线程中执行
isReachable扫描操作,会直接导致ANR(应用无响应) - 扫描逻辑缺陷:未排除自身IP,且
isReachable依赖ICMP请求,部分设备可能禁用ICMP但实际在线 - 权限缺失:未声明必要的网络/位置权限,导致无法获取WiFi信息或执行网络扫描
- 用户体验差:频繁弹出Toast会严重干扰正常操作
实现步骤及修正代码
1. 声明必要权限
在AndroidManifest.xml中添加权限配置:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <!-- Android 6+ 需动态申请位置权限 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
注:Android 10及以上版本,扫描WiFi设备必须获取位置权限,需动态申请
2. 修正IP地址转换方法
替换废弃的Formatter.formatIpAddress,用InetAddress实现标准IP转换:
private String getLocalIpAddress(WifiManager wifiManager) { WifiInfo wifiInfo = wifiManager.getConnectionInfo(); int ipInt = wifiInfo.getIpAddress(); byte[] ipBytes = new byte[]{ (byte) (ipInt & 0xff), (byte) ((ipInt >> 8) & 0xff), (byte) ((ipInt >> 16) & 0xff), (byte) ((ipInt >> 24) & 0xff) }; try { return InetAddress.getByAddress(ipBytes).getHostAddress(); } catch (UnknownHostException e) { e.printStackTrace(); return null; } }
3. 异步执行扫描任务
使用线程池执行扫描逻辑,避免阻塞主线程:
private void scanConnectedDevices() { WifiManager wifiManager = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE); String localIp = getLocalIpAddress(wifiManager); if (localIp == null) { Toast.makeText(this, "无法获取本地IP", Toast.LENGTH_SHORT).show(); return; } String ipPrefix = localIp.substring(0, localIp.lastIndexOf(".") + 1); String selfIp = localIp; // 用线程池并行扫描,提高效率 ExecutorService executor = Executors.newFixedThreadPool(10); List<Future<?>> futures = new ArrayList<>(); for (int i = 1; i <= 254; i++) { final String testIp = ipPrefix + i; // 跳过自身IP if (testIp.equals(selfIp)) continue; futures.add(executor.submit(() -> { try { InetAddress address = InetAddress.getByName(testIp); // 优先用TCP连接检测(端口80),再回退到ICMP,提高准确性 boolean isReachable = isHostReachable(testIp, 80, 1000) || address.isReachable(1000); if (isReachable) { String hostName = address.getCanonicalHostName(); // 回到UI线程更新数据 runOnUiThread(() -> { ipAddressArray.add(testIp); Log.i("wifi => ", "在线设备: " + hostName + "(" + testIp + ")"); Toast.makeText(MainActivity.this, "发现在线设备: " + testIp, Toast.LENGTH_SHORT).show(); }); } } catch (Exception e) { e.printStackTrace(); } })); } // 扫描完成后关闭线程池 executor.shutdown(); } // TCP连接检测方法,解决部分设备不响应ICMP的问题 private boolean isHostReachable(String ip, int port, int timeout) { Socket socket = null; try { socket = new Socket(); socket.connect(new InetSocketAddress(ip, port), timeout); return true; } catch (IOException e) { return false; } finally { if (socket != null) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } }
4. 动态申请权限(Android 6+)
调用扫描前检查并申请必要权限:
private static final int PERMISSION_REQUEST_CODE = 100; private void checkPermissionsAndScan() { String[] permissions = { Manifest.permission.ACCESS_WIFI_STATE, Manifest.permission.INTERNET, Manifest.permission.ACCESS_FINE_LOCATION }; List<String> needPermissions = new ArrayList<>(); for (String perm : permissions) { if (ContextCompat.checkSelfPermission(this, perm) != PackageManager.PERMISSION_GRANTED) { needPermissions.add(perm); } } if (!needPermissions.isEmpty()) { ActivityCompat.requestPermissions(this, needPermissions.toArray(new String[0]), PERMISSION_REQUEST_CODE); } else { scanConnectedDevices(); } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == PERMISSION_REQUEST_CODE) { boolean allGranted = true; for (int result : grantResults) { if (result != PackageManager.PERMISSION_GRANTED) { allGranted = false; break; } } if (allGranted) { scanConnectedDevices(); } else { Toast.makeText(this, "权限不足,无法扫描设备", Toast.LENGTH_SHORT).show(); } } }
实现效果
- 兼容高版本Android系统,能正确获取本地WiFi IP地址
- 异步扫描避免UI阻塞,彻底解决ANR问题
- 结合TCP+ICMP检测,大幅提高在线设备识别准确率
- 自动排除自身IP,避免无效数据
- 权限流程合规,符合Android系统权限要求
内容的提问来源于stack exchange,提问作者Sniper Dev
相关产品推荐
相关产品推荐

