Flutter iOS - 在加载 Google Maps 小部件之前无法获取 initialCameraPosition 的当前位置
Posted
技术标签:
【中文标题】Flutter iOS - 在加载 Google Maps 小部件之前无法获取 initialCameraPosition 的当前位置【英文标题】:Flutter iOS - cannot get current location for initialCameraPosition before loading Google Maps widget 【发布时间】:2020-08-02 09:15:34 【问题描述】:我正在尝试在我的 Flutter ios 应用程序中实现一个简单的地图功能。我遵循了从Flutter location package readme 到Medium "Implement Real-time Location Updates on Google Maps in your Flutter Apps" article 的指南,最后解决了许多关于类似问题的堆栈问题。
问题是我在加载地图之前无法获取当前位置,因此在 initialCameraPosition
中获取其 LatLng 会导致 NPE。我可以做的是加载带有硬编码initialCameraPosition
的地图,然后正确加载当前位置,我可以通过拖动或单击右下角的浮动位置按钮将相机移动到它。
这是我的代码示例:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:location/location.dart';
const double CAMERA_ZOOM = 16;
const LatLng SOURCE_LOCATION = LatLng(37.3317, -122.0325086);
class MapPage extends StatefulWidget
@override
_MapPageState createState() => _MapPageState();
class _MapPageState extends State<MapPage>
GoogleMapController mapController;
LocationData currentLocation;
Location location;
bool _serviceEnabled;
PermissionStatus _permissionGranted;
@override
void initState()
super.initState();
location = new Location();
location.onLocationChanged.listen((event)
currentLocation = event;
);
setInitialLocation();
void setInitialLocation() async
_serviceEnabled = await location.serviceEnabled();
if (!_serviceEnabled)
_serviceEnabled = await location.requestService();
if (!_serviceEnabled)
return;
_permissionGranted = await location.hasPermission();
if (_permissionGranted == PermissionStatus.denied)
_permissionGranted = await location.requestPermission();
if (_permissionGranted != PermissionStatus.granted)
return;
currentLocation = await location.getLocation();
void _onMapCreated(GoogleMapController controller)
mapController = controller;
CameraPosition initialCameraPosition()
LatLng target;
if (currentLocation != null)
target = LatLng(currentLocation.latitude, currentLocation.longitude);
else
target = SOURCE_LOCATION;
return CameraPosition(target: target, zoom: CAMERA_ZOOM);
@override
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.orangeAccent,
title: Text('Map'),
centerTitle: true,
),
body:
GoogleMap(
onMapCreated: _onMapCreated,
initialCameraPosition: initialCameraPosition(),
myLocationEnabled: true,
),
);
我知道获取当前位置是一个异步过程,所以我也尝试在正文部分使用FutureBuilder
:
FutureBuilder<LocationData>(
future: currentLocation,
builder: (context, snapshot)
if (snapshot.hasData)
LocationData currentLocation = snapshot.data;
return GoogleMap(
onMapCreated: _onMapCreated,
initialCameraPosition: CameraPosition(
target: LatLng(
currentLocation.latitude, currentLocation.longitude)),
myLocationEnabled: true,
);
else if (snapshot.hasError)
return (Text("$snapshot.error"));
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.orangeAccent,
),
);
,
),
当我不得不从 http GET 请求中检索数据时,它的作用就像一个魅力,但这次它只会导致无穷无尽的CircularProgressIndicator
。
我从堆栈问题尝试了许多其他解决方案,包括当currentLocation
为空时返回空Container
,为FutureBuilder snapshot.connectionState
创建条件,同样没有成功。
有趣的是,当我深入研究Location.getCurrentLocation()
方法时,我发现:
/// Gets the current location of the user.
///
/// Throws an error if the app has no permission to access location.
/// Returns a [LocationData] object.
Future<LocationData> getLocation() async
return LocationPlatform.instance.getLocation();
然后转到:
/// Gets the current location of the user.
///
/// Throws an error if the app has no permission to access location.
/// Returns a [LocationData] object.
Future<LocationData> getLocation()
throw UnimplementedError();
这让我怀疑这个插件是否可以工作。
这是我的flutter doctor -v
结果:
[✓] Flutter (Channel master, v1.18.0-6.0.pre.82, on Mac OS X 10.15.4 19E287, locale pl-PL)
• Flutter version 1.18.0-6.0.pre.82 at /Users/Vuco/flutter
• Framework revision f35b673f2b (26 hours ago), 2020-04-19 02:45:01 +0530
• Engine revision a5e0b2f2f2
• Dart version 2.9.0 (build 2.9.0-1.0.dev 5b19445d9c)
[✓] android toolchain - develop for Android devices (Android SDK version 29.0.3)
• Android SDK at /Users/Vuco/Library/Android/sdk
• Platform android-29, build-tools 29.0.3
• Java binary at: /Users/Vuco/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/192.6308749/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build 1.8.0_212-release-1586-b4-5784211)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 11.4.1)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Xcode 11.4.1, Build version 11E503a
• CocoaPods version 1.9.1
[✓] Android Studio (version 3.6)
• Android Studio at /Users/Vuco/Library/Application Support/JetBrains/Toolbox/apps/AndroidStudio/ch-0/192.6308749/Android Studio.app/Contents
• Flutter plugin version 45.0.1
• Dart plugin version 192.7761
• Java version OpenJDK Runtime Environment (build 1.8.0_212-release-1586-b4-5784211)
[!] IntelliJ IDEA Ultimate Edition (version 2020.1)
• IntelliJ at /Users/Vuco/Applications/JetBrains Toolbox/IntelliJ IDEA Ultimate.app
✗ Flutter plugin not installed; this adds Flutter specific functionality.
✗ Dart plugin not installed; this adds Dart specific functionality.
• For information about installing plugins, see
https://flutter.dev/intellij-setup/#installing-the-plugins
[✓] VS Code (version 1.44.0)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.9.1
[✓] Connected device (1 available)
• iPhone 8 • F60856B8-2C6E-401D-A0F9-06FFC7E09876 • ios • com.apple.CoreSimulator.SimRuntime.iOS-13-4 (simulator)
! Doctor found issues in 1 category.
以及我使用的依赖项:
google_maps_flutter: ^0.5.25+3
location: ^3.0.2
【问题讨论】:
【参考方案1】:您在获得初始位置之前渲染地图的问题,我相信您意识到FutureBuilder
会起作用,但可能会过度杀戮。您真正需要的只是一个布尔值。
GoogleMapController mapController;
LocationData currentLocation;
Location location;
bool _serviceEnabled;
PermissionStatus _permissionGranted;
CameraPosition _center =
CameraPosition(target: SOURCE_LOCATION, zoom: CAMERA_ZOOM);
bool isLoading = false;
@override
void initState()
super.initState();
location = new Location();
_getLocation();
_getLocation() async
setState(()
isLoading = true;
);
initialize();
currentLocation = await location.getLocation();
if (currentLocation == null)
return;
_center = CameraPosition(
target: LatLng(currentLocation.latitude, currentLocation.longitude),
zoom: CAMERA_ZOOM);
setState(()
isLoading = false;
);
print("CurrentLocation: $currentLocation");
Future<void> initialize() async
_serviceEnabled = await location.serviceEnabled();
if (!_serviceEnabled)
_serviceEnabled = await location.requestService();
if (!_serviceEnabled)
return;
_permissionGranted = await location.hasPermission();
if (_permissionGranted == PermissionStatus.DENIED)
_permissionGranted = await location.requestPermission();
if (_permissionGranted != PermissionStatus.GRANTED)
return;
void _onMapCreated(GoogleMapController controller)
mapController = controller;
@override
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.orangeAccent,
title: Text('Map'),
centerTitle: true,
),
body: isLoading
? CircularProgressIndicator()
: Container(
child: GoogleMap(
onMapCreated: _onMapCreated,
initialCameraPosition: _center,
myLocationEnabled: true,
),
),
);
【讨论】:
按照您的建议解决了我的问题,非常感谢! 没问题很高兴帮助 getLocation() 函数永远存在并且永远不会返回我按照上述所有步骤操作,授予权限,它只是不继续并且不返回 null 这里发生了什么? @RagehElAzzazy 我已经有一段时间没有在 Flutter 中工作了,但是您是否有可能忘记生成 Google Maps API 密钥并将其添加到您的项目中?我当时使用的 google_maps_flutter 版本还需要向 Info.plist(适用于 iOS)添加权限消息,但这可能会在当前版本中发生变化,因为我现在在任何地方都看不到该说明。您是否关注过我在帖子中链接的 Medium 文章? 与@RagehElAzzazy 相同。仍然无法在 iOS 上运行。【参考方案2】:我建议改用Geolocator 包。这是我在获取位置和订阅位置所需的所有应用程序中使用的,并且有据可查。尝试使用它,如果您的 FutureBuilder 与该软件包仍然存在问题,请使用您的新代码更新帖子,我可以尝试进一步帮助您。
如果您在构建地图之前没有初始化和检索位置,则可以使用 FutureBuilder。
【讨论】:
以上是关于Flutter iOS - 在加载 Google Maps 小部件之前无法获取 initialCameraPosition 的当前位置的主要内容,如果未能解决你的问题,请参考以下文章
Flutter Google Maps 插件在 iOS 上无法正常工作
使用 Google 登录无法在 Android 上运行(仅在 iOS 上) - Flutter
Flutter for Web 中的 WebView 未加载 Google 地图或其他
在 iOS 上退出 Google 登录无法在 Flutter Firebase 中运行
使用 google_mobile_ads 加载横幅时 Flutter App 崩溃
MissingPluginException(在通道 plugins.flutter.io/google_sign_in 上找不到方法 init 的实现)