Flutter 多端天气预报APP第二弹 —— 城市定位以及城市代码的转换

2024-01-19 18:11:03 浏览数 (1)

前言

在前一篇博客中,我们介绍了如何使用Flutter创建一个简单的天气预报应用程序。在这篇博客中,我们将进一步完善我们的应用,添加城市定位功能以及将地理位置转换为城市代码的功能。

获取当前位置

在获取当前位置的过程中,我们使用了Flutter的Geolocator库。这个库不仅仅可以获取设备的经纬度,还能提供更多有关设备位置的信息。例如,我们可以获取设备的海拔高度、速度、方向等。在实际应用中,根据需求可以灵活运用这些功能,比如实现高度相关的气象应用或运动追踪应用等。下面是获取当前位置的代码:

代码语言:javascript复制
  Future<Position?> getCurrentLocation() async {
    try {
      return await Geolocator.getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
    } catch (e) {
      // 处理定位失败的情况
      print("Error getting location: $e");
      return null;
    }
  }

这个函数通过Geolocator.getCurrentPosition方法获取设备的当前位置,desiredAccuracy参数用于指定定位的精确度。我们通过try-catch块捕获异常,以确保在定位失败时能够 graceful 地处理。

完成之后,我们输出获取到的地理位置信息,来看一看自己是否函数是否能够正常使用;下面编写一个函数来查看我们的输出:

代码语言:javascript复制
Future<void> printCurrentLocation() async{

    try {

      Position? position = await Geolocator.getCurrentPosition();
      print(position);
    } catch (error) {
      print('Error fetching weather data: $error');
      // 处理异常,显示错误信息
    }
  }

可以看到,控制台可以正常输出我们的位置。

当前位置经纬度转 Location ID

获得当前位置的经纬度后,我们要将其转换为可用于和风天气API的城市代码,这样才能够填充之前请求天气的 location 参数。下面是我找到的和风天气的经纬度转城市代码的api,

https://geoapi.qweather.com/v2/city/lookup?location=116.41,39.92&key=$apiKeye

请求后的内容如下:

代码语言:javascript复制
{
    "code": "200",
    "location": [
        {
            "name": "东城",
            "id": "101011600",
            "lat": "39.91755",
            "lon": "116.41876",
            "adm2": "北京",
            "adm1": "北京市",
            "country": "中国",
            "tz": "Asia/Shanghai",
            "utcOffset": " 08:00",
            "isDst": "0",
            "type": "city",
            "rank": "35",
            "fxLink": "https://www.qweather.com/weather/dongcheng-101011600.html"
        }
    ],
    "refer": {
        "sources": [
            "QWeather"
        ],
        "license": [
            "QWeather Developers License"
        ]
    }
}

简要把各个字段列成表格,表格中 location 属性下的 id 就是我们想要的内容:

字段

描述

code

API响应的状态码。

location

包含有关位置的详细信息的数组。

- name

位置的名称(例如:“东城”)。

- id

位置的唯一标识符(例如:“101011600”)。

- lat

位置的纬度坐标(例如:“39.91755”)。

- lon

位置的经度坐标(例如:“116.41876”)。

- adm2

行政区划级别2(例如:“北京”)。

- adm1

行政区划级别1(例如:“北京市”)。

- country

位置所在国家(例如:中国)。

- tz

位置的时区(例如:“Asia/Shanghai”)。

- utcOffset

位置的UTC偏移量(例如:“ 08:00”)。

- isDst

夏令时指示符(例如:"0"表示无夏令时)。

- type

位置的类型(例如:“city”)。

- rank

位置的排名(例如:“35”)。

- fxLink

查看位置天气详情的链接。

refer

附加信息和参考资料。

- sources

数据来源数组(例如:[“QWeather”])。

- license

QWeather开发者许可证信息。

编写代码通过 api 将经纬度转换成 location id。提醒一下大家,和风天气的这个api最多只支持经纬度小数点后两位,所以在之前的定位过程中可以不用选择高精度。

代码语言:javascript复制
Future<String?> getCityCodeFromLocation() async{

    try {
      // 经纬度
      String latitude = "39.91";
      String longitude = "116.41";

      Position? position = await Geolocator.getCurrentPosition();
      latitude = position.latitude.toStringAsFixed(2);
      longitude = position.longitude.toStringAsFixed(2);

      // 构建 API 请求的 URL
      String apiUrl =
          'https://geoapi.qweather.com/v2/city/lookup?location=$longitude,$latitude&key=$apiKey';

      // 发送 HTTP GET 请求
      http.Response response = await http.get(Uri.parse(apiUrl));

      if (response.statusCode == 200) {
        // 解析 JSON 响应
        Map<String, dynamic> data = json.decode(response.body);

        // 获取 Location ID
        String locationId = data['location'][0]['id'].toString();
        print(locationId);	// 输出一下看看
        return locationId;
        
      } else {
        print("Error getting Location ID");
        return null;
      }
    } catch (e) {
      
      print("Error getting Location ID");
      return null;
      
    }
  }

通过http库发送HTTP GET请求到和风天气的城市查询API,获取对应经纬度的城市信息,并提取出城市代码。运行后可以看到输出的城市代码:

然后再传回到 getWeatherData() 中,

代码语言:javascript复制
Future<Map<String, dynamic>> getWeatherData() async {


    String? locationId = await getCityCodeFromLocation();
    String url = 'https://devapi.qweather.com/v7/weather/3d?location=$locationId&key=$apiKey';
    Uri uri = Uri.parse(url);
    var response = await http.get(uri);

    if (response.statusCode == 200) {
      return json.decode(response.body);
    } else {
      throw Exception('Failed to load weather data');
    }
  }

编译运行一下,和我所在位置的气候一模一样,Success

0 人点赞