Flutter geolocator包无法返回经纬度、返回null值问题求助
Flutter geolocator 获取经纬度返回null问题排查
问题表现
- 集成geolocator包获取设备当前位置时,经度、纬度字段均返回null值
- 已完成Android、iOS端清单/配置文件中的位置访问权限声明
现有实现代码
loading_screen.dart
import 'package:flutter/material.dart'; import 'package:clima/services/location.dart'; class LoadingScreen extends StatefulWidget { @override _LoadingScreenState createState() => _LoadingScreenState(); } class _LoadingScreenState extends State<LoadingScreen> { @override void initState() { super.initState(); print('init state called'); getLocation(); } double? lat; double? long; void getLocation() async { Location location = Location(); await location.getCurrentLocation(); print(location.longitude); print(location.latitude); lat = location.latitude; long = location.longitude; } @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Text('$lat & $long'), ), ); } }
location.dart
import 'package:geolocator/geolocator.dart'; class Location { double? longitude; double? latitude; Future<void> getCurrentLocation() async { try { Position position = await Geolocator.getCurrentPosition( desiredAccuracy: LocationAccuracy.lowest); longitude = position.longitude; latitude = position.latitude; } catch (e) { print(e); } } }
控制台运行日志
Running Gradle task 'assembleDebug'... √ Built build\app\outputs\flutter-apk\app-debug.apk. D/FlutterGeolocator( 9601): Attaching Geolocator to activity D/FlutterGeolocator( 9601): Creating service. D/FlutterGeolocator( 9601): Binding to location service. D/FlutterGeolocator( 9601): Geolocator foreground service connected D/FlutterGeolocator( 9601): Initializing Geolocator services Debug service listening on ws://127.0.0.1:52220/Dm4z5g8IYT4=/ws Syncing files to device SM A528B... I/flutter ( 9601): init state called I/BufferQueueProducer( 9601): [SurfaceView - com.kanuthakor.clima/com.kanuthakor.clima.MainActivity@e98a93d@0#1(BLAST Consumer)1](id:258100000001,api:1,p:9601,c:9601) queueBuffer: queued for the first time. D/ViewRootImpl@797d88a[MainActivity]( 9601): Creating frameDrawingCallback nextDrawUseBlastSync=false reportNextDraw=true hasBlurUpdates=false D/ViewRootImpl@797d88a[MainActivity]( 9601): Creating frameCompleteCallback I/SurfaceView@e98a93d( 9601): uSP: rtp = Rect(0, 0 - 1080, 2265) rtsw = 1080 rtsh = 2265 I/SurfaceView@e98a93d( 9601): onSSPAndSRT: pl = 0 pt = 0 sx = 1.0 sy = 1.0 I/SurfaceView@e98a93d( 9601): aOrMT: uB = true t = android.view.SurfaceControl$Transaction@10aa451 fN = 1 android.view.SurfaceView.access$500:124 android.view.SurfaceView$SurfaceViewPositionUpdateListener.positionChanged:1728 android.graphics.RenderNode$CompositePositionUpdateListener.positionChanged:319 I/SurfaceView@e98a93d( 9601): aOrMT: vR.mWNT, vR = ViewRootImpl@797d88a[MainActivity] I/ViewRootImpl@797d88a[MainActivity]( 9601): mWNT: t = android.view.SurfaceControl$Transaction@10aa451 fN = 1 android.view.SurfaceView.applyOrMergeTransaction:1628 android.view.SurfaceView.access$500:124 android.view.SurfaceView$SurfaceViewPositionUpdateListener.positionChanged:1728 I/ViewRootImpl@797d88a[MainActivity]( 9601): mWNT: merge t to BBQ D/ViewRootImpl@797d88a[MainActivity]( 9601): Received frameDrawingCallback frameNum=1. Creating transactionCompleteCallback=false I/BufferQueueProducer( 9601): [ViewRootImpl@797d88a[MainActivity]#0(BLAST Consumer)0](id:258100000000,api:1,p:9601,c:9601) queueBuffer: queued for the first time. D/OpenGLRenderer( 9601): GPIS:: SetUp Pid : 9601 Tid : 9632 D/ViewRootImpl@797d88a[MainActivity]( 9601): Received frameCompleteCallback lastAcquiredFrameNum=1 lastAttemptedDrawFrameNum=1 I/ViewRootImpl@797d88a[MainActivity]( 9601): [DP] pdf(0) 1 android.view.ViewRootImpl.lambda$addFrameCompleteCallbackIfNeeded$3$ViewRootImpl:4987 android.view.ViewRootImpl$$ExternalSyntheticLambda16.run:6 android.os.Handler.handleCallback:938 I/ViewRootImpl@797d88a[MainActivity]( 9601): [DP] rdf() D/ViewRootImpl@797d88a[MainActivity]( 9601): reportDrawFinished (fn: -1) I/ViewRootImpl@797d88a[MainActivity]( 9601): MSG_WINDOW_FOCUS_CHANGED 1 1 D/InputMethodManager( 9601): startInputInner - Id : 0 I/InputMethodManager( 9601): startInputInner - mService.startInputOrWindowGainedFocus D/InputMethodManager( 9601): startInputInner - Id : 0
排查步骤与解决方案
- 补全定位前置校验逻辑
清单文件配置权限不代表运行时权限已授予、位置服务已开启,直接调用定位接口大概率拿不到结果。在调用getCurrentPosition前必须加两层校验:- 检查系统位置开关是否开启:执行
bool serviceEnabled = await Geolocator.isLocationServiceEnabled();,返回false时直接引导用户打开系统位置服务,终止后续定位流程 - 检查运行时权限状态:执行
LocationPermission permission = await Geolocator.checkPermission();,权限为denied时调用requestPermission()主动申请权限,权限为deniedForever时引导用户跳转系统设置页手动授权
- 检查系统位置开关是否开启:执行
- 修复页面不刷新问题
定位结果返回后给lat、long赋值时没有调用setState(),Flutter不会重新触发build渲染,就算拿到有效值页面也会一直显示null。修改getLocation方法的赋值逻辑:void getLocation() async { Location location = Location(); await location.getCurrentLocation(); setState(() { lat = location.latitude; long = location.longitude; }); } - 调整定位参数配置
当前设置的desiredAccuracy: LocationAccuracy.lowest在多数安卓机型上需要依赖网络定位,信号差时会直接返回null,同时缺少超时配置会导致定位请求无限挂起。修改定位调用参数:Position position = await Geolocator.getCurrentPosition( desiredAccuracy: LocationAccuracy.high, timeLimit: const Duration(seconds: 10), ); - 排查测试环境问题
- 优先用真机测试,安卓模拟器默认未开启位置模拟时无法返回有效定位结果
- 确认测试设备系统设置中位置信息总开关为开启状态,且已给测试应用授予位置访问权限
- 首次测试尽量在室外GPS信号良好的区域进行,室内遮挡环境下低精度定位很容易返回null
- 补全异常日志
当前catch块仅打印异常对象,很多定位失败的错误堆栈被吞无法定位根因,修改异常打印逻辑输出完整堆栈:catch (e, stack) { print('定位失败: $e'); print(stack); }
内容的提问来源于stack exchange,提问作者Kanu Thakor
相关产品推荐
相关产品推荐

