Flutter iOS调用location包获取位置时应用立即崩溃
Flutter location包调用时崩溃的解决方案
问题描述
在Flutter v3.0.5中使用location ^4.4.0包获取设备位置时,调用该包的任意方法都会导致应用崩溃。已在Info.plist中添加相关权限配置:
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key> <string>...</string> <key>NSLocationAlwaysUsageDescription</key> <string>...</string> <key>NSLocationWhenInUseUsageDescription</key> <string>...</string> <key>UIBackgroundModes</key> <string>location</string>
实现代码直接取自包示例,但在location.serviceEnabled()处崩溃:
user_location.dart代码
import 'package:location/location.dart'; class UserLocation { Location location = Location(); late bool _serviceIsEnabled; late PermissionStatus _permissionGranted; late LocationData _locationData; Future<LocationData?> getLocation() async { print("Getting location"); _serviceIsEnabled = await location.serviceEnabled(); // 在此处崩溃 <- if (!_serviceIsEnabled) { _serviceIsEnabled = await location.requestService(); if (!_serviceIsEnabled) 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; } }
main.dart相关代码
Future main() async { await dotenv.load(); runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( home: MyHomePage(), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({Key? key}) : super(key: key); @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { LocationData? _userLocation; @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { setState(() async { final location = await UserLocation().getLocation(); _userLocation = location; }); }); } }
解决方案
配置iOS端初始化代码
location包在iOS上需要额外的初始化配置,否则会因插件注册问题崩溃。修改ios/Runner/AppDelegate.swift(Swift项目):import UIKit import Flutter import location @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { GeneratedPluginRegistrant.register(with: self) // 添加location插件注册回调 LocationPlugin.setPluginRegistrantCallback { registry in GeneratedPluginRegistrant.register(with: registry) } return super.application(application, didFinishLaunchingWithOptions: launchOptions) } }若为Objective-C项目,修改
ios/Runner/AppDelegate.m:#import "AppDelegate.h" #import "GeneratedPluginRegistrant.h" #import <location/LocationPlugin.h> @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [GeneratedPluginRegistrant registerWithRegistry:self]; // 添加location插件注册回调 [LocationPlugin setPluginRegistrantCallback:^(NSObject<FlutterPluginRegistry>* registry) { [GeneratedPluginRegistrant registerWithRegistry:registry]; }]; return [super application:application didFinishLaunchingWithOptions:launchOptions]; } @end修复异步调用的错误写法
setState的回调不能是异步函数,这会导致状态更新逻辑异常。修改_MyHomePageState的initState方法:@override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) async { final location = await UserLocation().getLocation(); setState(() { _userLocation = location; }); }); }将
async移至addPostFrameCallback的回调函数上,确保异步操作完成后再调用setState更新状态。清理项目缓存并重新构建
执行以下命令清理旧的构建缓存,避免残留文件导致的问题:flutter clean flutter pub get cd ios && pod install && cd .. flutter run确保权限描述不为空
Info.plist中的权限说明字符串不能是占位符...,需要替换为实际的用途说明,比如:<key>NSLocationWhenInUseUsageDescription</key> <string>需要获取您的位置信息以提供定位服务</string>
内容的提问来源于stack exchange,提问作者Ryan Roberts
相关产品推荐
相关产品推荐

