热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Flutter中获取地理位置[Flutter专题61]

Flutter中获取地理位置[Flutter专题61]-大家好,我是坚果,公众号“坚果前端”Flutter中获取地理位置如今,发现用户位置是移动应用程序非常常见且功能强大的用例

大家好,我是坚果,公众号“坚果前端”

Flutter 中获取地理位置

如今,发现用户位置是移动应用程序非常常见且功能强大的用例。如果您曾经尝试过在 Android 中实现位置,您就会知道样例代码会变得多么复杂和混乱。

但这与 Flutter 不同——它有很多令人惊叹的包,可以为您抽象出样板代码,并使实现地理定位成为梦想。另一个好的方面是您可以在 Android 和 iOS 上获得这些功能。

让我们快速浏览一下我们今天正在构建的用于收集位置数据的内容:

本文将带您了解两个最流行且易于使用的 Flutter 地理定位包。

让我们从location开始,这是Flutter 最喜欢的包。这很简单。只需三个简单的步骤,您就可以获取当前用户位置以及处理位置权限。

先决条件

在继续前进之前,让我们快速检查一下我们需要的东西:

  • 该FlutterSDK
  • 编辑器;您可以使用 Visual Code 或 Android Studio
  • 至少对 Flutter 有初级的了解

差不多就是这样!

使用 Flutter 定位包

设置

将依赖项添加到您的文件中:pubspec.yaml

    location: ^4.3.0

由于 Android 和 iOS 处理权限的方式不同,因此我们必须在每个平台上分别添加它们。

安卓版

将以下位置权限添加到:AndroidManifest.xml

 

如果您还想在后台访问用户的位置,请在访问后台位置之前使用该API,并在清单文件中添加后台权限:enableBackgroundMode({bool enable})


对于 iOS

将以下位置权限添加到:Info.plist

NSLocationWhenInUseUsageDescription 
此应用需要访问您的位置

NSLocationWhenInUseUsageDescription是您需要的唯一许可。这也允许您访问后台位置,唯一需要注意的是,当应用程序在后台访问位置时,状态栏中会显示蓝色徽章。与 Android 不同,我们在其中添加了单独的权限以在后台访问用户的位置。

位置权限

我们需要在请求用户位置之前检查位置服务状态和权限状态,这可以使用以下几行代码轻松完成:

Location location = new Location();

bool _serviceEnabled;
PermissionStatus _permissionGranted;

_serviceEnabled = await location.serviceEnabled();
if (!_serviceEnabled) {
 _serviceEnabled = await location.requestService();
 if (!_serviceEnabled) {
   return null;
 }
}

_permissiOnGranted= await location.hasPermission();
if (_permissiOnGranted== PermissionStatus.denied) {
 _permissiOnGranted= await location.requestPermission();
 if (_permissionGranted != PermissionStatus.granted) {
   return null;
 }
}

首先,我们创建一个由Location()包提供的对象,location反过来为我们提供了两个有用的方法。检查设备位置是否已启用或用户是否已手动禁用它。``serviceEnabled()

对于后者,我们显示了一个原生提示,允许用户通过调用快速启用位置,然后我们再检查一次,如果他们从提示中启用了它。requestService()

一旦我们确定启用了位置服务,下一步就是通过调用它来检查我们的应用程序是否具有使用它的必要权限,这将返回.hasPermission()``PermissionStatus

PermissionStatus是可以具有以下三个值之一的枚举:

  • PermissionStatus.granted: 定位服务权限已被授予
  • PermissionStatus.denied: 定位服务权限被拒绝
  • PermissionStatus.deniedForever: 位置服务权限被用户永久拒绝。这仅适用于 iOS。在这种情况下不会显示对话框requestPermission()

如果状态为 ,我们可以通过调用显示请求位置权限的系统提示。对于 status ,我们可以立即访问 location ,因此我们返回一个.denied,``requestPermission()``granted``null

如果您还想在后台访问用户位置,请使用。location.enableBackgroundMode(enable: **true**)

获取当前位置

如果位置服务可用并且用户已授予位置权限,那么我们只需两行代码即可获取用户位置 - 不,我不是在开玩笑:

LocationData _locationData;
_locatiOnData= await location.getLocation();

LocationData类提供以下位置信息:

class LocationData {
  final double latitude; // Latitude, in degrees
  final double longitude; // Longitude, in degrees
  final double accuracy; // Estimated horizontal accuracy of this location, radial, in meters
  final double altitude; // In meters above the WGS 84 reference ellipsoid
  final double speed; // In meters/second
  final double speedAccuracy; // In meters/second, always 0 on iOS
  final double heading; // Heading is the horizontal direction of travel of this device, in degrees
  final double time; // timestamp of the LocationData
  final bool isMock; // Is the location currently mocked
}

您还可以通过添加onLocationChanged侦听器在用户位置发生变化时监听位置更新来获得连续回调,这是出租车应用程序、司机/骑手应用程序等的一个很好的用例:

location.onLocationChanged.listen((LocationData currentLocation) {
  // current user location
});

注意,一旦您想停止收听更新,请不要忘记取消流订阅。

瞧!现在我们有了用户位置的当前纬度和经度值。

让我们利用这些纬度和经度值来获取用户的完整地址或反向地理编码。

为此,我们将使用另一个惊人的 Flutter 包:geocode。

使用 Flutter 地理编码包

设置

将依赖项添加到您的文件中:pubspec.yaml

dependencies:
    geocode: 1.0.1

获取地址

获取地址再简单不过了。就打电话吧。就是这样!带有空检查的完整函数如下所示:reverseGeocoding(latitude: lat, longitude: lang)

Future _getAddress(double? lat, double? lang) async {
 if (lat == null || lang == null) return "";
 GeoCode geoCode = GeoCode();
 Address address =
     await geoCode.reverseGeocoding(latitude: lat, longitude: lang);
 return "${address.streetAddress}, ${address.city}, ${address.countryName}, ${address.postal}";
}

没那么简单!

完整的代码如下所示:

class GetUserLocation extends StatefulWidget {
 GetUserLocation({Key? key, required this.title}) : super(key: key);
 final String title;

 @override
 _GetUserLocationState createState() => _GetUserLocationState();
}

class _GetUserLocationState extends State {
 LocationData? currentLocation;
 String address = "";

 @override
 Widget build(BuildContext context) {
   return Scaffold(
     appBar: AppBar(),
     body: Center(
       child: Padding(
         padding: EdgeInsets.all(16.0),
         child: Column(
           mainAxisAlignment: MainAxisAlignment.center,
           children: [
             if (currentLocation != null)
               Text(
                   "Location: ${currentLocation?.latitude}, ${currentLocation?.longitude}"),
             if (currentLocation != null) Text("Address: $address"),
             MaterialButton(
               onPressed: () {
                 _getLocation().then((value) {
                   LocationData? location = value;
                   _getAddress(location?.latitude, location?.longitude)
                       .then((value) {
                     setState(() {
                       currentLocation = location;
                       address = value;
                     });
                   });
                 });
               },
               color: Colors.purple,
               child: Text(
                 "Get Location",
                 style: TextStyle(color: Colors.white),
               ),
             ),
           ],
         ),
       ),
     ),
   );
 }

 Future _getLocation() async {
   Location location = new Location();
   LocationData _locationData;

   bool _serviceEnabled;
   PermissionStatus _permissionGranted;

   _serviceEnabled = await location.serviceEnabled();
   if (!_serviceEnabled) {
     _serviceEnabled = await location.requestService();
     if (!_serviceEnabled) {
       return null;
     }
   }

   _permissiOnGranted= await location.hasPermission();
   if (_permissiOnGranted== PermissionStatus.denied) {
     _permissiOnGranted= await location.requestPermission();
     if (_permissionGranted != PermissionStatus.granted) {
       return null;
     }
   }


   _locatiOnData= await location.getLocation();

   return _locationData;
 }

 Future _getAddress(double? lat, double? lang) async {
   if (lat == null || lang == null) return "";
   GeoCode geoCode = GeoCode();
   Address address =
       await geoCode.reverseGeocoding(latitude: lat, longitude: lang);
   return "${address.streetAddress}, ${address.city}, ${address.countryName}, ${address.postal}";
 }
}

常见的陷阱

尽管这些软件包让我们的生活变得更轻松,而且我们不必处理在 Android 和 iOS 中本地访问位置的复杂过程,但您可能会面临很多问题。让我们来看看它们以及可以帮助您修复这些问题的步骤:

  • 应用内存泄漏:如果您一直在收听位置更新,请确保取消流订阅,一旦您想停止收听更新
  • 用户必须接受位置权限才能始终允许使用后台位置。位置权限对话框提示中未显示始终允许的 Android 11 选项。用户必须从应用程序设置中手动启用它
  • 用户可能在 iOS 上永远拒绝定位,因此不会显示要求定位权限的本机提示。确保处理这种边缘情况requestPermisssions()
  • 用户可能随时从应用程序设置中撤销位置权限,因此在访问位置数据之前,请确保在应用程序恢复时检查它们

结论

由于 Flutter 简化了访问位置,因此我们作为开发人员可能会立即将其添加到我们的应用程序中。但同时,我们需要确保我们的应用程序真正适合请求用户位置并利用它为用户增加一些价值的用例,而不是仅仅将位置数据发送到服务器。

随着即将推出的 Android 和 iOS 操作系统版本中安全性和隐私性的提高,访问位置数据而不向用户提供价值可能会导致您的应用程序被商店拒绝。有很多很好的用例,您可以使用用户位置,例如,根据用户位置为食品/外卖应用程序个性化主屏幕,该应用程序显示按用户当前位置的接近程度订购的餐厅。取件/送货应用程序是最常见的用例。

您还可以在您实际想要使用的特定屏幕上询问用户位置,而不是立即在主屏幕上询问。这使用户更清楚,并且他们不太可能拒绝位置权限。

感谢您的陪伴,坚果前端的粉丝们!您可以在GitHub 上访问本文中使用的示例应用程序。


推荐阅读
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • intellij idea的安装与使用(保姆级教程)
    intellijidea的安装与使用(保姆级教程)IntelliJ在业界被公认为最好的java开发工具,尤其在智能代码助手、代码自动提示、重构、JavaEE支持、各类版本工具(gi ... [详细]
  • 本文介绍了在Mac上安装Xamarin并使用Windows上的VS开发iOS app的方法,包括所需的安装环境和软件,以及使用Xamarin.iOS进行开发的步骤。通过这种方法,即使没有Mac或者安装苹果系统,程序员们也能轻松开发iOS app。 ... [详细]
  • 本文介绍了Android平台各个版本的API级别、版本号以及平台亮点,从Android 1.0到Android 10.0,共涵盖了多个版本的特点和发展历程。详细内容请参考https://developer.android.google.cn/guide/topics/manifest/uses-sdk-element.html。 ... [详细]
  • macOS命令行创建Android模拟器
    macOS下不安装AndroidStudio使用VSCode来开发Flutter应用使用命令行创建和管理Android模拟器设备avdmanageravdmanager 是一种命令 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 拥抱Android Design Support Library新变化(导航视图、悬浮ActionBar)
    转载请注明明桑AndroidAndroid5.0Loollipop作为Android最重要的版本之一,为我们带来了全新的界面风格和设计语言。看起来很受欢迎࿰ ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 利用Visual Basic开发SAP接口程序初探的方法与原理
    本文介绍了利用Visual Basic开发SAP接口程序的方法与原理,以及SAP R/3系统的特点和二次开发平台ABAP的使用。通过程序接口自动读取SAP R/3的数据表或视图,在外部进行处理和利用水晶报表等工具生成符合中国人习惯的报表样式。具体介绍了RFC调用的原理和模型,并强调本文主要不讨论SAP R/3函数的开发,而是针对使用SAP的公司的非ABAP开发人员提供了初步的接口程序开发指导。 ... [详细]
  • 本文介绍了一个免费的asp.net控件,该控件具备数据显示、录入、更新、删除等功能。它比datagrid更易用、更实用,同时具备多种功能,例如属性设置、数据排序、字段类型格式化显示、密码字段支持、图像字段上传和生成缩略图等。此外,它还提供了数据验证、日期选择器、数字选择器等功能,以及防止注入攻击、非本页提交和自动分页技术等安全性和性能优化功能。最后,该控件还支持字段值合计和数据导出功能。总之,该控件功能强大且免费,适用于asp.net开发。 ... [详细]
  • Android自定义控件绘图篇之Paint函数大汇总
    本文介绍了Android自定义控件绘图篇中的Paint函数大汇总,包括重置画笔、设置颜色、设置透明度、设置样式、设置宽度、设置抗锯齿等功能。通过学习这些函数,可以更好地掌握Paint的用法。 ... [详细]
  • 基于移动平台的会展导游系统APP设计与实现的技术介绍与需求分析
    本文介绍了基于移动平台的会展导游系统APP的设计与实现过程。首先,对会展经济和移动互联网的概念进行了简要介绍,并阐述了将会展引入移动互联网的意义。接着,对基础技术进行了介绍,包括百度云开发环境、安卓系统和近场通讯技术。然后,进行了用户需求分析和系统需求分析,并提出了系统界面运行流畅和第三方授权等需求。最后,对系统的概要设计进行了详细阐述,包括系统前端设计和交互与原型设计。本文对基于移动平台的会展导游系统APP的设计与实现提供了技术支持和需求分析。 ... [详细]
  • 本文介绍了在Ubuntu 11.10 x64环境下安装Android开发环境的步骤,并提供了解决常见问题的方法。其中包括安装Eclipse的ADT插件、解决缺少GEF插件的问题以及解决无法找到'userdata.img'文件的问题。此外,还提供了相关插件和系统镜像的下载链接。 ... [详细]
  • Android图形架构学习笔记(待修改)
    以下简单总结来自Android官网,稍作总结:https:source.android.google.cndevicesgraphics概览Andr ... [详细]
  • Flutter 布局(四) Baseline、FractionallySizedBox、IntrinsicHeight、IntrinsicWidth详解
    本文主要介绍Flutter布局中的Baseline、FractionallySizedBox、IntrinsicHeight、IntrinsicWidth四种控件,详细介绍了其布局 ... [详细]
author-avatar
coco2冰冰
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有