Flutter地理位置获取插件x_location的使用

Flutter地理位置获取插件x_location的使用

前述

  1. 高德定位Flutter插件。
  2. 登录高德开放平台官网分别申请Android端iOS端的key。
  3. 如需了解高德定位SDK的相关功能,请参阅Android定位SDK开发指南iOS定位SDK开发指南

使用高德定位Flutter插件

  1. 请参考在Flutter里使用Packages,引入amap_flutter_location插件。
  2. 引入高德定位SDK,Android平台请参考Android Studio配置工程,iOS平台请参考ios安装定位SDK

常见问题:

  1. 在iOS设备上运行或者运行iOS工程遇到:Invalid Podfile file: cannot load such file - /flutter/packages/flutter_tools/bin/podhelper
    $ rm ios/Podfile
    $ flutter build ios
    

在需要的定位功能的页面中引入定位Flutter插件的dart类

import 'package:amap_flutter_location/amap_flutter_location.dart';
import 'package:amap_flutter_location/amap_location_option.dart';

接口说明

设置定位参数
/// 设置定位参数
void setLocationOption(AMapLocationOption locationOption)

将您设置的参数传递到原生端对外接口,目前支持以下定位参数:

//// 是否需要地址信息,默认true
bool needAddress = true;

///逆地理信息语言类型<br>
///默认[GeoLanguage.DEFAULT] 自动适配<br>
///可选值:
///<li>[GeoLanguage.DEFAULT] 自动适配</li>
///<li>[GeoLanguage.EN] 英文</li>
///<li>[GeoLanguage.ZH] 中文</li>
GeoLanguage geoLanguage;

///是否单次定位
///默认值:false
bool onceLocation = false;

///Android端定位模式, 只在Android系统上有效<br>
///默认值:[AMapLocationMode.Hight_Accuracy]<br>
///可选值:
///<li>[AMapLocationMode.Battery_Saving]</li>
///<li>[AMapLocationMode.Device_Sensors]</li>
///<li>[AMapLocationMode.Hight_Accuracy]</li>
AMapLocationMode locationMode;

///Android端定位间隔<br>
///单位:毫秒<br>
///默认:2000毫秒<br>
int locationInterval = 2000;

///iOS端是否允许系统暂停定位<br>
///默认:false
bool pausesLocationUpdatesAutomatically = false;

/// iOS端期望的定位精度, 只在iOS端有效<br>
/// 默认值:最高精度<br>
/// 可选值:
/// <li>[DesiredAccuracy.Best] 最高精度</li>
/// <li>[DesiredAccuracy.BestForNavigation] 适用于导航场景的高精度 </li>
/// <li>[DesiredAccuracy.NearestTenMeters] 10米 </li>
/// <li>[DesiredAccuracy.Kilometer] 1000米</li>
/// <li>[DesiredAccuracy.ThreeKilometers] 3000米</li>
DesiredAccuracy desiredAccuracy = DesiredAccuracy.Best;

/// iOS端定位最小更新距离<br>
/// 单位:米<br>
/// 默认值:-1,不做限制<br>
double distanceFilter = -1;

///iOS 14中设置期望的定位精度权限
AMapLocationAccuracyAuthorizationMode desiredLocationAccuracyAuthorizationMode = AMapLocationAccuracyAuthorizationMode.FullAccuracy;

/// iOS 14中定位精度权限由模糊定位升级到精确定位时,需要用到的场景key fullAccuracyPurposeKey 这个key要和plist中的配置一样
String fullAccuracyPurposeKey = "";

开始定位
void startLocation()

停止定位
void stopLocation()

销毁定位
/// 高德定位Flutter插件,支持多实例,请在dispose执行时调用当前定位插件的销毁方法
void destroy()

定位结果获取
Stream<Map<String, Object>> onLocationChanged()

注册定位结果监听:

_locationPlugin
    .onLocationChanged()
    .listen((Map<String, Object> result) {
      /// result即为定位结果
});

定位结果是以map的形式返回的,具体内容为:

/// `callbackTime`: 回调时间,格式为"yyyy-MM-dd HH:mm:ss"
///
/// `locationTime`: 定位时间, 格式为"yyyy-MM-dd HH:mm:ss"
///
/// `locationType`: 定位类型, 具体类型可以参考https://lbs.amap.com/api/android-location-sdk/guide/utilities/location-type
///
/// `latitude`: 纬度
///
/// `longitude`: 经度
///
/// `accuracy`: 精确度
///
/// `altitude`: 海拔, android上只有locationType==1时才会有值
///
/// `bearing`: 角度,android上只有locationType==1时才会有值
///
/// `speed`: 速度, android上只有locationType==1时才会有值
///
/// `country`: 国家,android上只有通过[AMapLocationOption.needAddress]为true时才有可能返回值
///
/// `province`: 省,android上只有通过[AMapLocationOption.needAddress]为true时才有可能返回值
///
/// `city`: 城市,android上只有通过[AMapLocationOption.needAddress]为true时才有可能返回值
///
/// `district`: 城镇(区),android上只有通过[AMapLocationOption.needAddress]为true时才有可能返回值
///
/// `street`: 街道,android上只有通过[AMapLocationOption.needAddress]为true时才有可能返回值
///
/// `streetNumber`: 门牌号,android上只有通过[AMapLocationOption.needAddress]为true时才有可能返回值
///
/// `cityCode`: 城市编码,android上只有通过[AMapLocationOption.needAddress]为true时才有可能返回值
///
/// `adCode`: 区域编码, android上只有通过[AMapLocationOption.needAddress]为true时才有可能返回值
///
/// `address`: 地址信息, android上只有通过[AMapLocationOption.needAddress]为true时才有可能返回值
///
/// `description`: 位置语义, android上只有通过[AMapLocationOption.needAddress]为true时才有可能返回值
///
/// `errorCode`: 错误码,当定位失败时才会返回对应的错误码, 具体错误请参考:https://lbs.amap.com/api/android-location-sdk/guide/utilities/errorcode
///
/// `errorInfo`: 错误信息, 当定位失败时才会返回

示例代码

import 'dart:async';
import 'dart:io';
import 'package:amap_flutter_location/x_location.dart';
import 'package:amap_flutter_location/x_location_option.dart';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';

void main() {
  runApp(new MyApp());
}

class MyApp extends StatefulWidget {
  [@override](/user/override)
  _MyAppState createState() => new _MyAppState();
}

class _MyAppState extends State<MyApp> {
  Map<String, Object>? _locationResult;

  StreamSubscription<Map<String, Object>>? _locationListener;

  AMapFlutterLocation _locationPlugin = new AMapFlutterLocation();

  [@override](/user/override)
  void initState() {
    super.initState();

    /// 设置是否已经包含高德隐私政策并弹窗展示显示用户查看,如果未包含或者没有弹窗展示,高德定位SDK将不会工作
    ///
    /// 高德SDK合规使用方案请参考官网地址:https://lbs.amap.com/news/sdkhgsy
    /// <b>必须保证在调用定位功能之前调用, 建议首次启动App时弹出《隐私政策》并取得用户同意</b>
    ///
    /// 高德SDK合规使用方案请参考官网地址:https://lbs.amap.com/news/sdkhgsy
    ///
    /// [hasContains] 隐私声明中是否包含高德隐私政策说明
    ///
    /// [hasShow] 隐私权政策是否弹窗展示告知用户
    AMapFlutterLocation.updatePrivacyShow(true, true);

    /// 设置是否已经取得用户同意,如果未取得用户同意,高德定位SDK将不会工作
    ///
    /// 高德SDK合规使用方案请参考官网地址:https://lbs.amap.com/news/sdkhgsy
    ///
    /// <b>必须保证在调用定位功能之前调用, 建议首次启动App时弹出《隐私政策》并取得用户同意</b>
    ///
    /// [hasAgree] 隐私权政策是否已经取得用户同意
    AMapFlutterLocation.updatePrivacyAgree(true);

    /// 动态申请定位权限
    requestPermission();

    /// 设置Android和iOS的apiKey<br>
    /// key的申请请参考高德开放平台官网说明<br>
    /// Android: https://lbs.amap.com/api/android-location-sdk/guide/create-project/get-key
    /// iOS: https://lbs.amap.com/api/ios-location-sdk/guide/create-project/get-key
    AMapFlutterLocation.setApiKey(
        "1dbf56e2e8a4d0e4cdc2df9efd36bc71", "dfb64c0463cb53927914364b5c09aba0");

    /// iOS 获取native精度类型
    if (Platform.isIOS) {
      requestAccuracyAuthorization();
    }

    /// 注册定位结果监听
    _locationListener = _locationPlugin
        .onLocationChanged()
        .listen((Map<String, Object> result) {
      setState(() {
        _locationResult = result;
      });
    });
  }

  [@override](/user/override)
  void dispose() {
    super.dispose();

    /// 移除定位监听
    if (null != _locationListener) {
      _locationListener?.cancel();
    }

    /// 销毁定位
    _locationPlugin.destroy();
  }

  /// 设置定位参数
  void _setLocationOption() {
    AMapLocationOption locationOption = new AMapLocationOption();

    /// 是否单次定位
    locationOption.onceLocation = false;

    /// 是否需要返回逆地理信息
    locationOption.needAddress = true;

    /// 逆地理信息的语言类型
    locationOption.geoLanguage = GeoLanguage.DEFAULT;

    locationOption.desiredLocationAccuracyAuthorizationMode =
        AMapLocationAccuracyAuthorizationMode.ReduceAccuracy;

    locationOption.fullAccuracyPurposeKey = "AMapLocationScene";

    /// 设置Android端连续定位的定位间隔
    locationOption.locationInterval = 2000;

    /// 设置Android端的定位模式<br>
    /// 可选值:
    /// <li>[AMapLocationMode.Battery_Saving]</li>
    /// <li>[AMapLocationMode.Device_Sensors]</li>
    /// <li>[AMapLocationMode.Hight_Accuracy]</li>
    locationOption.locationMode = AMapLocationMode.Hight_Accuracy;

    /// 设置iOS端的定位最小更新距离<br>
    locationOption.distanceFilter = -1;

    /// 设置iOS端期望的定位精度
    /// 可选值:
    /// <li>[DesiredAccuracy.Best] 最高精度</li>
    /// <li>[DesiredAccuracy.BestForNavigation] 适用于导航场景的高精度 </li>
    /// <li>[DesiredAccuracy.NearestTenMeters] 10米 </li>
    /// <li>[DesiredAccuracy.Kilometer] 1000米</li>
    /// <li>[DesiredAccuracy.ThreeKilometers] 3000米</li>
    locationOption.desiredAccuracy = DesiredAccuracy.Best;

    /// 设置iOS端是否允许系统暂停定位
    locationOption.pausesLocationUpdatesAutomatically = false;

    /// 将定位参数设置给定位插件
    _locationPlugin.setLocationOption(locationOption);
  }

  /// 开始定位
  void _startLocation() {
    /// 开始定位之前设置定位参数
    _setLocationOption();
    _locationPlugin.startLocation();
  }

  /// 停止定位
  void _stopLocation() {
    _locationPlugin.stopLocation();
  }

  Container _createButtonContainer() {
    return new Container(
        alignment: Alignment.center,
        child: new Row(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            new ElevatedButton(
              onPressed: _startLocation,
              child: new Text('开始定位'),
              style: ButtonStyle(
                backgroundColor: MaterialStateProperty.all(Colors.blue),
                foregroundColor: MaterialStateProperty.all(Colors.white),
              ),
            ),
            new Container(width: 20.0),
            new ElevatedButton(
              onPressed: _stopLocation,
              child: new Text('停止定位'),
              style: ButtonStyle(
                backgroundColor: MaterialStateProperty.all(Colors.blue),
                foregroundColor: MaterialStateProperty.all(Colors.white),
              ),
            )
          ],
        ));
  }

  Widget _resultWidget(key, value) {
    return new Container(
      child: new Row(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: <Widget>[
          new Container(
            alignment: Alignment.centerRight,
            width: 100.0,
            child: new Text('$key :'),
          ),
          new Container(width: 5.0),
          new Flexible(child: new Text('$value', softWrap: true)),
        ],
      ),
    );
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    List<Widget> widgets = <Widget>[];
    widgets.add(_createButtonContainer());

    if (_locationResult != null) {
      _locationResult?.forEach((key, value) {
        widgets.add(_resultWidget(key, value));
      });
    }

    return new MaterialApp(
        home: new Scaffold(
      appBar: new AppBar(
        title: new Text('AMap Location plugin example app'),
      ),
      body: new Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisSize: MainAxisSize.min,
        children: widgets,
      ),
    ));
  }

  /// 获取iOS native的accuracyAuthorization类型
  void requestAccuracyAuthorization() async {
    AMapAccuracyAuthorization currentAccuracyAuthorization =
        await _locationPlugin.getSystemAccuracyAuthorization();
    if (currentAccuracyAuthorization ==
        AMapAccuracyAuthorization.AMapAccuracyAuthorizationFullAccuracy) {
      print("精确定位类型");
    } else if (currentAccuracyAuthorization ==
        AMapAccuracyAuthorization.AMapAccuracyAuthorizationReducedAccuracy) {
      print("模糊定位类型");
    } else {
      print("未知定位类型");
    }
  }

  /// 动态申请定位权限
  void requestPermission() async {
    // 申请权限
    bool hasLocationPermission = await requestLocationPermission();
    if (hasLocationPermission) {
      print("定位权限申请通过");
    } else {
      print("定位权限申请不通过");
    }
  }

  /// 申请定位权限
  /// 授予定位权限返回true, 否则返回false
  Future<bool> requestLocationPermission() async {
    // 获取当前的权限
    var status = await Permission.location.status;
    if (status == PermissionStatus.granted) {
      // 已经授权
      return true;
    } else {
      // 未授权则发起一次申请
      status = await Permission.location.request();
      if (status == PermissionStatus.granted) {
        return true;
      } else {
        return false;
      }
    }
  }
}

更多关于Flutter地理位置获取插件x_location的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter地理位置获取插件x_location的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


x_location 是一个 Flutter 插件,用于在 Android 和 iOS 设备上获取设备的地理位置信息。它支持获取当前的位置、连续的位置更新以及监听位置的变化。下面是如何使用 x_location 插件的详细步骤。

1. 添加依赖

首先,在 pubspec.yaml 文件中添加 x_location 插件的依赖:

dependencies:
  flutter:
    sdk: flutter
  x_location: ^1.0.0  # 请使用最新的版本号

然后运行 flutter pub get 来安装依赖。

2. 配置权限

为了获取地理位置信息,你需要在 Android 和 iOS 项目中配置相应的权限。

Android

android/app/src/main/AndroidManifest.xml 文件中添加以下权限:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

iOS

ios/Runner/Info.plist 文件中添加以下权限:

<key>NSLocationWhenInUseUsageDescription</key>
<string>我们需要您的位置信息来提供更好的服务</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>我们需要您的位置信息来提供更好的服务</string>

3. 使用 x_location 插件

在你的 Dart 代码中,你可以使用 x_location 插件来获取地理位置信息。

获取当前位置

import 'package:x_location/x_location.dart';

void getCurrentLocation() async {
  try {
    // 获取当前位置
    LocationData locationData = await XLocation.getLocation();
    
    print("Latitude: ${locationData.latitude}");
    print("Longitude: ${locationData.longitude}");
    print("Accuracy: ${locationData.accuracy}");
    print("Altitude: ${locationData.altitude}");
    print("Speed: ${locationData.speed}");
    print("Speed Accuracy: ${locationData.speedAccuracy}");
    print("Heading: ${locationData.heading}");
    print("Time: ${locationData.time}");
  } catch (e) {
    print("Error: $e");
  }
}

监听位置变化

import 'package:x_location/x_location.dart';

void listenLocation() async {
  // 设置位置更新间隔和最小距离变化
  XLocation.setLocationOption(interval: 10000, distance: 10);

  // 开始监听位置变化
  XLocation.onLocationChange().listen((LocationData locationData) {
    print("Latitude: ${locationData.latitude}");
    print("Longitude: ${locationData.longitude}");
    print("Accuracy: ${locationData.accuracy}");
    print("Altitude: ${locationData.altitude}");
    print("Speed: ${locationData.speed}");
    print("Speed Accuracy: ${locationData.speedAccuracy}");
    print("Heading: ${locationData.heading}");
    print("Time: ${locationData.time}");
  });
}

停止监听位置变化

void stopListenLocation() {
  XLocation.stopLocation();
}

4. 处理权限请求

在 iOS 和 Android 上,获取位置信息需要用户授权。你可以在首次请求位置信息时处理权限请求。

import 'package:x_location/x_location.dart';

void requestPermission() async {
  bool hasPermission = await XLocation.requestPermission();
  if (hasPermission) {
    print("Permission granted");
    getCurrentLocation();
  } else {
    print("Permission denied");
  }
}

5. 处理错误

在使用 x_location 插件时,可能会遇到一些错误,例如权限被拒绝或位置服务不可用。你可以使用 try-catch 块来捕获并处理这些错误。

void getCurrentLocation() async {
  try {
    LocationData locationData = await XLocation.getLocation();
    print("Latitude: ${locationData.latitude}");
  } catch (e) {
    print("Error: $e");
  }
}

6. 其他功能

x_location 插件还提供了其他一些功能,例如获取最后一次已知的位置、检查位置服务是否启用等。

void getLastKnownLocation() async {
  LocationData? lastKnownLocation = await XLocation.getLastKnownLocation();
  if (lastKnownLocation != null) {
    print("Last Known Latitude: ${lastKnownLocation.latitude}");
  }
}

void checkServiceEnabled() async {
  bool isServiceEnabled = await XLocation.isLocationServiceEnabled();
  print("Location Service Enabled: $isServiceEnabled");
}

7. 注意事项

  • 在 Android 10 及以上版本,后台访问位置信息需要额外的权限和配置。
  • 在 iOS 上,用户可以在设置中随时更改位置权限,因此你需要处理权限被撤销的情况。

8. 示例代码

以下是一个完整的示例代码,展示了如何使用 x_location 插件获取当前位置并监听位置变化:

import 'package:flutter/material.dart';
import 'package:x_location/x_location.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  [@override](/user/override)
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  String _locationInfo = "No location data";

  [@override](/user/override)
  void initState() {
    super.initState();
    requestPermission();
  }

  void requestPermission() async {
    bool hasPermission = await XLocation.requestPermission();
    if (hasPermission) {
      getCurrentLocation();
      listenLocation();
    } else {
      setState(() {
        _locationInfo = "Permission denied";
      });
    }
  }

  void getCurrentLocation() async {
    try {
      LocationData locationData = await XLocation.getLocation();
      setState(() {
        _locationInfo = "Latitude: ${locationData.latitude}, Longitude: ${locationData.longitude}";
      });
    } catch (e) {
      setState(() {
        _locationInfo = "Error: $e";
      });
    }
  }

  void listenLocation() async {
    XLocation.setLocationOption(interval: 10000, distance: 10);
    XLocation.onLocationChange().listen((LocationData locationData) {
      setState(() {
        _locationInfo = "Latitude: ${locationData.latitude}, Longitude: ${locationData.longitude}";
      });
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('XLocation Example'),
      ),
      body: Center(
        child: Text(_locationInfo),
      ),
    );
  }
}
回到顶部