You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter(Dart)环境下获取手机IPv4与IPv6地址的可行方案及权限问题咨询

我来帮你解决这几个困扰你的问题,都是基于实际开发中的经验总结:

在Flutter/Dart中无第三方依赖获取本机IP地址

如果你不想依赖第三方服务器,有两种可靠的原生方案:

1. 枚举所有网络接口获取地址

Dart的dart:io库自带NetworkInterface类,可以直接枚举设备上的所有活跃网络接口,从中筛选出非回环的IPv4/IPv6地址:

import 'dart:io';

Future<List<String>> getLocalIps() async {
  final List<String> ips = [];
  final interfaces = await NetworkInterface.list(
    includeLoopback: false,
    includeLinkLocal: true,
    type: InternetAddressType.any,
  );
  
  for (var interface in interfaces) {
    for (var addr in interface.addresses) {
      // 排除链路本地地址(可选,根据需求调整)
      if (!addr.isLinkLocal) {
        ips.add(addr.address);
      }
    }
  }
  return ips;
}

这个方法能获取到设备上所有可用的网络IP,但需要注意:如果设备同时连接了Wi-Fi和移动数据,会返回多个地址,你可能需要根据当前活跃网络进一步筛选。

2. 模拟Kotlin的DatagramSocket方式获取路由IP

虽然RawDatagramSocket没有connect方法,但可以用Socket发起一个到公共地址的连接(不需要成功建立,只要本地网络栈分配了出口IP),从而拿到当前用于对外通信的IP:

import 'dart:io';

Future<String?> getActiveIp() async {
  try {
    // 连接到公共DNS服务器(53端口是DNS服务端口)
    final socket = await Socket.connect(
      '8.8.8.8', 
      53, 
      timeout: const Duration(seconds: 3)
    );
    final activeIp = socket.address.address;
    socket.close();
    return activeIp;
  } catch (e) {
    // 连接失败时,可以尝试IPv6地址
    try {
      final socket = await Socket.connect(
        '2001:4860:4860::8888', 
        53, 
        timeout: const Duration(seconds: 3)
      );
      final activeIp = socket.address.address;
      socket.close();
      return activeIp;
    } catch (ipv6Error) {
      print('Failed to get active IP: $ipv6Error');
      return null;
    }
  }
}

这个方法的优势是能直接拿到当前路由使用的出口IP,适合需要知道“设备对外访问时使用的IP”的场景,而且完全不需要第三方服务器返回数据,只是利用本地网络栈的连接逻辑。

解决ip route get命令权限被拒的问题

你遇到的权限问题是因为Android 10+对系统命令的执行权限做了严格限制,ip route属于netlink操作,普通APP即使声明了INTERNET、ACCESS_NETWORK_STATE等权限,也无法直接执行该命令。而ConnectBot能做到,大概率是因为它使用了Android原生网络API而非直接执行shell命令,或者在某些特殊场景下(比如root设备)获取了额外权限。

推荐的解决方案是:

通过Android原生API获取路由信息

在Flutter中通过MethodChannel调用Android原生代码,利用系统提供的ConnectivityManager获取当前网络的链路属性,从而拿到对应的IP地址,不需要执行任何shell命令,也不需要额外的危险权限。

第一步:Android原生端代码(Kotlin)

class MainActivity : FlutterActivity() {
    private val CHANNEL = "com.example.ip_channel"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result ->
            if (call.method == "getCurrentRouteIp") {
                val ip = getCurrentRouteIp()
                if (ip != null) {
                    result.success(ip)
                } else {
                    result.error("NO_IP", "No active network IP found", null)
                }
            } else {
                result.notImplemented()
            }
        }
    }

    private fun getCurrentRouteIp(): String? {
        val connectivityManager = getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
        val activeNetwork = connectivityManager.activeNetwork ?: return null
        val linkProperties = connectivityManager.getLinkProperties(activeNetwork) ?: return null
        
        // 遍历所有链路地址,返回第一个非回环的IP
        linkProperties.linkAddresses.forEach { address ->
            val ipAddress = address.address
            if (!ipAddress.isLoopbackAddress) {
                return ipAddress.hostAddress
            }
        }
        return null
    }
}

第二步:Flutter端调用代码

import 'package:flutter/services.dart';

class IpUtils {
  static const MethodChannel _channel = MethodChannel('com.example.ip_channel');

  static Future<String?> getCurrentRouteIp() async {
    try {
      final String? ip = await _channel.invokeMethod('getCurrentRouteIp');
      return ip;
    } on PlatformException catch (e) {
      print('Error getting route IP: ${e.message}');
      return null;
    }
  }
}

这种方案完全符合Android的权限规范,只需要在AndroidManifest.xml中保留ACCESS_NETWORK_STATE权限即可,不需要额外申请危险权限,也能在私有网络环境下正常工作。

内容的提问来源于stack exchange,提问作者Vsevolod

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 17:47:29