loadNetworkGeoInfo method

Future<NetworkGeoInfo?> loadNetworkGeoInfo()

获取网络位置信息

Implementation

Future<NetworkGeoInfo?> loadNetworkGeoInfo() async {
  // 如果已经有信息,直接返回
  if (geoInfo != null) {
    publicIP = geoInfo!.ip;
    return geoInfo!;
  }

  // 定义多个服务商的 url 和解析方法
  final List<_ProviderDefinition> providers = [
    //开源免费
    _ProviderDefinition(
      url:
          'http://ip-api.com/json/?lang=zh-CN&fields=status,message,country,countryCode,region,regionName,city,lat,lon,timezone,query,mobile',
      parser: (data) {
        try {
          if (data is Map && data['status'] == 'success') {
            return NetworkGeoInfo()
              ..ip = data['query'] ?? ''
              ..country = data['country'] ?? ''
              ..countryCode = data['countryCode'] ?? ''
              ..region = data['region'] ?? ''
              ..regionName = data['regionName'] ?? ''
              ..city = data['city'] ?? ''
              ..lat = (data['lat'] ?? 0.0).toDouble()
              ..lon = (data['lon'] ?? 0.0).toDouble()
              ..timezone = data['timezone'] ?? '';
          }
          return null;
        } catch (_) {
          return null;
        }
      },
    ),
    // 免费:每分钟60次
    _ProviderDefinition(
      url: 'https://free.freeipapi.com/api/json/',
      parser: (data) {
        try {
          if (data is Map) {
            var timeZones = data['timeZones'] ?? [];
            var timezone = timeZones.isNotEmpty ? timeZones.first : '';
            return NetworkGeoInfo()
              ..ip = data['ipAddress'] ?? ''
              ..country = data['countryName'] ?? ''
              ..countryCode = data['countryCode'] ?? ''
              ..region = data['regionName'] ?? ''
              ..regionName = data['regionName'] ?? ''
              ..city = data['cityName'] ?? ''
              ..lat = (data['latitude'] ?? 0.0).toDouble()
              ..lon = (data['longitude'] ?? 0.0).toDouble()
              ..timezone = timezone;
          }
          return null;
        } catch (_) {
          return null;
        }
      },
    ),
    //https://ipinfo.io/developers使用最新API,KEY方式无限制https://api.ipinfo.io/lite/me?token=2bbec5864d5271
    _ProviderDefinition(
      url: 'https://ipinfo.io/json',
      parser: (data) {
        try {
          if (data is Map) {
            return NetworkGeoInfo()
              ..ip = data['ip'] ?? ''
              ..country = data['country'] ?? ''
              ..countryCode = data['country'] ?? ''
              ..region = data['region'] ?? ''
              ..regionName = data['region'] ?? ''
              ..city = data['city'] ?? ''
              ..lat = 0.0
              ..lon = 0.0
              ..timezone = data['timezone'] ?? '';
          }
        } catch (_) {
          return null;
        }
        return null;
      },
    ),
    // 免费
    _ProviderDefinition(
      url: 'https://ipv4-check-perf.radar.cloudflare.com/api/info',
      parser: (data) {
        try {
          if (data is Map) {
            return NetworkGeoInfo()
              ..ip = data['ip_address'] ?? ''
              ..country = data['country'] ?? ''
              ..countryCode = data['country'] ?? ''
              ..region = data['region'] ?? ''
              ..regionName = data['region'] ?? ''
              ..city = data['city'] ?? ''
              ..lat = 0.0
              ..lon = 0.0
              ..timezone = '';
          }
        } catch (_) {
          return null;
        }
        return null;
      },
    ),
    // 每天免费30000次
    _ProviderDefinition(
      url: 'https://ipapi.co/json/',
      parser: (data) {
        try {
          if (data is Map) {
            return NetworkGeoInfo()
              ..ip = data['ip'] ?? ''
              ..country = data['country'] ?? ''
              ..countryCode = data['country_code'] ?? ''
              ..region = data['region'] ?? ''
              ..regionName = data['region_code'] ?? ''
              ..city = data['city'] ?? ''
              ..lat = 0.0
              ..lon = 0.0
              ..timezone = data['timezone'] ?? '';
          }
        } catch (_) {
          return null;
        }
        return null;
      },
    ),
    //每天1500次
    _ProviderDefinition(
      url:
          'https://api.ipdata.co?api-key=8d79f088ef95545378ef877ef2ecdff9ed4909d5e213e5a8a9a71b97&fields=ip,is_eu,city,region,region_code,country_name,country_code,continent_name,continent_code,latitude,longitude',
      parser: (data) {
        try {
          if (data is Map) {
            return NetworkGeoInfo()
              ..ip = data['ip'] ?? ''
              ..country = data['country_name'] ?? ''
              ..countryCode = data['country_code'] ?? ''
              ..region = data['region'] ?? ''
              ..regionName = data['region_code'] ?? ''
              ..city = data['city'] ?? ''
              ..lat = 0.0
              ..lon = 0.0
              ..timezone = data['timezone'] ?? '';
          }
        } catch (_) {
          return null;
        }
        return null;
      },
    ),
    //每月30000次
    _ProviderDefinition(
      url:
          'https://api.ipgeolocation.io/v2/ipgeo?apiKey=50c00e5864934ed7869d22ce078bcfb9',
      parser: (data) {
        try {
          if (data is Map &&
              data['ip'] != null &&
              data['ip'].toString().isNotEmpty) {
            var lat = 0.0;
            var lon = 0.0;
            if (data['location'] is Map) {
              var locationMap = data['location'] as Map;
              return NetworkGeoInfo()
                ..ip = data['ip'] ?? ''
                ..country = locationMap['country_name'] ?? ''
                ..countryCode = locationMap['country_code2'] ?? ''
                ..region = data['state_prov'] ?? ''
                ..regionName = data['state_code'] ?? ''
                ..city = data['city'] ?? ''
                ..lat = lat
                ..lon = lon
                ..timezone = data['timezone'] ?? '';
            }
          }
        } catch (_) {
          return null;
        }
        return null;
      },
    ),
  ];

  // 串行请求各服务商
  for (final provider in providers) {
    try {
      final response = await Dio().get(provider.url);
      final data = response.data;
      final info = provider.parser(data);
      if (info != null) {
        publicIP = info.ip;
        geoInfo = info;
        break;
      }
    } catch (e) {
      // ignore, 尝试下一个
      Logger.log('IP定位服务失败: ${provider.url} 错误: $e');
    }
  }

  return geoInfo;
}