Flutter地理位置获取插件geolocation的使用
Flutter地理位置获取插件geolocation的使用
geolocation
Flutter geolocation 插件 适用于 Android API 16+ 和 iOS 9+。
特性:
- 手动和自动位置权限管理
- 获取当前位置(单次)
- 带有前台和后台选项的连续位置更新
该插件正在积极开发中,以下功能计划尽快推出:
- 地理编码
- 地理围栏
- 地点建议
- 活动识别
- 暴露 iOS/Android 特定的 API(如 iOS 上的重要位置更新)
Android | iOS |
---|---|
![]() |
![]() |
安装
按照以下说明进行安装: https://pub.dev/packages/geolocation#-installing-tab-
iOS
Objective-C 兼容性
对于使用 Objective-C 模板创建的 Flutter 项目,可能需要在 ios/Podfile
文件顶部添加 use_frameworks!
。
更多细节可以查看以下问题:https://github.com/flutter/flutter/issues/16049#issuecomment-552060349
Android
AndroidX
geolocation 依赖于 AndroidX。确保在 android/gradle.properties
中包含以下设置:
android.useAndroidX=true
android.enableJetifier=true
R8/Proguard 代码混淆
如果启用了 R8 或 ProGuard 的代码混淆,请添加以下规则。
在 android/app/build.gradle
文件中:
buildTypes {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
在 android/app/proguard-rules.pro
文件中:
# Geolocation - start
-keep class app.loup.geolocation.** { *; }
# Moshi - start
# https://github.com/square/moshi/blob/master/moshi/src/main/resources/META-INF/proguard/moshi.pro
# JSR 305 annotations are for embedding nullability information.
-dontwarn javax.annotation.**
-keepclasseswithmembers class * {
@com.squareup.moshi.* <methods>;
}
-keep @com.squareup.moshi.JsonQualifier interface *
# Enum field names are used by the integrated EnumJsonAdapter.
# values() is synthesized by the Kotlin compiler and is used by EnumJsonAdapter indirectly
# Annotate enums with @JsonClass(generateAdapter = false) to use them with Moshi.
-keepclassmembers @com.squareup.moshi.JsonClass class * extends java.lang.Enum {
<fields>;
**[] values();
}
# Moshi - end
# Geolocation - end
权限
Android 和 iOS 都需要在配置文件中声明位置权限。
对于 iOS
iOS 提供了两种位置权限:“当应用使用时” 和 “始终”。
如果你不确定哪种权限适合你的用途,请查看以下链接: https://developer.apple.com/documentation/corelocation/choosing_the_authorization_level_for_location_services
你需要在 ios/Runner/Info.plist
文件中声明所需的权限描述:
<dict>
<!-- for iOS 11 + -->
<key>NSLocationWhenInUseUsageDescription</key>
<string>Reason why app needs location</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Reason why app needs location</string>
<!-- additionally for iOS 9/10, if you need always permission -->
<key>NSLocationAlwaysUsageDescription</key>
<string>Reason why app needs location</string>
...
</dict>
对于 Android
Android 提供了两种位置权限:“粗略” 和 “精确”。 粗略位置将允许基于 Wi-Fi 等传感器获取近似位置,而精确位置会使用 GPS 返回最准确的位置(包括粗略)。
你可以在 android/app/src/main/AndroidManifest.xml
文件中声明其中一个权限:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- or -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
</manifest>
注意,ACCESS_FINE_LOCATION
权限包含了 ACCESS_COARSE_LOCATION
。
API
有关所有用法的更完整文档,请参阅 API 文档: https://pub.dartlang.org/documentation/geolocation/latest/geolocation/geolocation-library.html
你还可以检查示例项目,它展示了 Geolocation 插件的全面使用。
检查位置服务是否可用
final GeolocationResult result = await Geolocation.isLocationOperational();
if(result.isSuccessful) {
// 位置服务已启用,并且权限已授予
} else {
// 位置服务未启用、受限或权限被拒绝
}
请求位置权限
在 Android (API 23+) 和 iOS 上,应用程序需要在运行时请求位置权限。
注意:你不需要手动请求权限。Geolocation 插件会在必要时自动请求权限,当你进行位置请求时。
final GeolocationResult result = await Geolocation.requestLocationPermission(
const LocationPermission(
android: LocationPermissionAndroid.fine,
ios: LocationPermissionIOS.always,
),
openSettingsIfDenied: true,
);
if(result.isSuccessful) {
// 权限已授予(或之前已经授予)
} else {
// 权限未授予
// 用户可能已经拒绝,但也可能是位置服务未启用、受限,用户从未看到权限请求对话框。检查 result.error.type 以获取详细信息。
}
获取当前单次位置
Geolocation 提供了三种方法:
- 最后已知位置(在 Android 上最佳): https://pub.dartlang.org/documentation/geolocation/latest/geolocation/Geolocation/lastKnownLocation.html
- 单次位置更新(在 iOS 上最佳): https://pub.dartlang.org/documentation/geolocation/latest/geolocation/Geolocation/singleLocationUpdate.html
- 当前位置(最佳选择,尝试在 Android 上获取最后已知位置,否则请求单次位置更新): https://pub.dartlang.org/documentation/geolocation/latest/geolocation/Geolocation/currentLocation.html
// 获取最后已知位置,这是一个 Future 而不是 Stream(在 Android 上最佳)
LocationResult result = await Geolocation.lastKnownLocation();
// 强制进行单次位置更新(在 iOS 上最佳)
StreamSubscription<LocationResult> subscription = Geolocation.currentLocation(accuracy: LocationAccuracy.best).listen((result) {
// 处理结果
});
// 对大多数情况来说这是最佳选择
StreamSubscription<LocationResult> subscription = Geolocation.currentLocation(accuracy: LocationAccuracy.best).listen((result) {
if(result.isSuccessful) {
double latitude = result.location.latitude;
// 处理结果
}
});
连续位置更新
StreamSubscription<LocationResult> subscription = Geolocation.locationUpdates(
accuracy: LocationAccuracy.best,
displacementFilter: 10.0, // 以米为单位
inBackground: true, // 默认情况下,位置更新将在应用处于非活动状态(后台)时暂停。设置为 `true` 以继续后台更新。
)
.listen((result) {
if(result.isSuccessful) {
// 处理结果
}
});
// 取消订阅也会停止正在进行的位置请求
subscription.cancel();
处理位置结果
位置请求返回一个 LocationResult
Future 或 LocationResult
流。
API 文档:https://pub.dartlang.org/documentation/geolocation/latest/geolocation/LocationResult-class.html
LocationResult result = await Geolocation.lastKnownLocation();
if (result.isSuccessful) {
// 位置请求成功,保证位置不为空
double lat = result.location.latitude;
double lng = result.location.longitude;
} else {
switch (result.error.type) {
case GeolocationResultErrorType.runtime:
// 运行时错误,检查 result.error.message
break;
case GeolocationResultErrorType.locationNotFound:
// 位置请求未返回任何结果
break;
case GeolocationResultErrorType.serviceDisabled:
// 设备上的位置服务禁用
// 可能是 GPS 关闭,或者家长控制(Android)
break;
case GeolocationResultErrorType.permissionNotGranted:
// 尚未请求位置权限
// 应用必须请求权限才能访问位置
break;
case GeolocationResultErrorType.permissionDenied:
// 用户拒绝了应用程序的位置权限
// 拒绝在 iOS 上是最终决定,如果用户勾选了“不再询问”,则在 Android 上也是如此
// 用户需要手动从设置中允许应用程序,参见 requestLocationPermission(openSettingsIfDenied: true)
break;
case GeolocationResultErrorType.playServicesUnavailable:
// 仅适用于 Android
// result.error.additionalInfo 包含更多关于 Play Services 错误的详细信息
switch(result.error.additionalInfo as GeolocationAndroidPlayServices) {
// 做一些事情,比如弹出对话框邀请用户安装/更新 Play Services
case GeolocationAndroidPlayServices.missing:
case GeolocationAndroidPlayServices.updating:
case GeolocationAndroidPlayServices.versionUpdateRequired:
case GeolocationAndroidPlayServices.disabled:
case GeolocationAndroidPlayServices.invalid:
}
break;
}
}
示例代码
以下是一个完整的示例代码,展示了如何使用 geolocation 插件获取当前位置并处理结果。
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:geolocation/geolocation.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
[@override](/user/override)
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
String _latitude = "Unknown";
String _longitude = "Unknown";
Future<void> _getLocation() async {
try {
final GeolocationResult result = await Geolocation.currentLocation(accuracy: LocationAccuracy.high);
if (result.isSuccessful) {
setState(() {
_latitude = result.location.latitude.toString();
_longitude = result.location.longitude.toString();
});
} else {
setState(() {
_latitude = "Location Not Found";
_longitude = "Location Not Found";
});
}
} catch (e) {
setState(() {
_latitude = "Error: $e";
_longitude = "Error: $e";
});
}
}
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Geolocation Example"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: _getLocation,
child: Text("Get Location"),
),
SizedBox(height: 20),
Text("Latitude: $_latitude"),
Text("Longitude: $_longitude"),
],
),
),
);
}
}
更多关于Flutter地理位置获取插件geolocation的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter地理位置获取插件geolocation的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter中,获取设备的地理位置信息通常使用geolocator
插件。geolocator
是一个功能强大的插件,允许你获取设备的当前位置、监听位置变化、获取位置权限等。
以下是如何使用geolocator
插件获取设备地理位置的步骤:
1. 添加依赖
首先,在pubspec.yaml
文件中添加geolocator
插件的依赖:
dependencies:
flutter:
sdk: flutter
geolocator: ^9.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. 获取当前位置
以下是一个简单的示例,展示如何使用geolocator
插件获取设备的当前位置:
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
Position? _currentPosition;
Future<void> _getCurrentLocation() async {
// 检查位置服务是否启用
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();
if (!serviceEnabled) {
// 位置服务未启用,提示用户启用
return;
}
// 检查位置权限
LocationPermission permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied) {
// 权限被拒绝,提示用户
return;
}
}
if (permission == LocationPermission.deniedForever) {
// 权限被永久拒绝,提示用户
return;
}
// 获取当前位置
Position position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high,
);
setState(() {
_currentPosition = position;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('获取地理位置'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
if (_currentPosition != null)
Text(
'纬度: ${_currentPosition!.latitude}, 经度: ${_currentPosition!.longitude}',
),
ElevatedButton(
onPressed: _getCurrentLocation,
child: Text('获取当前位置'),
),
],
),
),
);
}
}
4. 监听位置变化
你还可以使用geolocator
插件来监听设备位置的变化:
StreamSubscription<Position>? positionStream;
void startListening() {
positionStream = Geolocator.getPositionStream(
desiredAccuracy: LocationAccuracy.high,
distanceFilter: 10, // 位置变化超过10米时触发
).listen((Position position) {
print('位置变化: ${position.latitude}, ${position.longitude}');
});
}
void stopListening() {
positionStream?.cancel();
}