GoogleMap API与CLocationManager无法显示当前位置及功能求助
解决Google Maps & Core Location定位问题 + 目的地接近通知实现
先帮你一步步拆解问题,从定位不显示的排查,到目的地处理,再到接近提醒的实现:
一、先搞定「当前位置无法显示」的问题
不管是Google Maps还是Core Location,定位不显示大概率是权限配置或代码逻辑的问题,按下面的步骤排查:
1. 必做:Info.plist权限键配置
iOS 14+ 必须在Info.plist中添加对应的权限描述,否则权限请求会直接失败:
- 仅前台定位:添加
NSLocationWhenInUseUsageDescription,值填比如"需要获取您的位置以显示地图" - 前后台定位:添加
NSLocationAlwaysAndWhenInUseUsageDescription,同时还要开启Xcode中Capabilities的「Background Modes」里的「Location updates」
2. Core Location代码校验
确保你的CLLocationManager逻辑正确:
// 在ViewController里声明CLLocationManager属性 @property (nonatomic, strong) CLLocationManager *locationManager; // 初始化并配置 - (void)setupLocationManager { self.locationManager = [[CLLocationManager alloc] init]; self.locationManager.delegate = self; // 先检查定位服务是否开启 if (![CLLocationManager locationServicesEnabled]) { // 提示用户开启定位服务 return; } // 请求权限 CLAuthorizationStatus status = [CLLocationManager authorizationStatus]; if (status == kCLAuthorizationStatusNotDetermined) { [self.locationManager requestWhenInUseAuthorization]; // 或requestAlwaysAuthorization } else if (status == kCLAuthorizationStatusAuthorizedWhenInUse || status == kCLAuthorizationStatusAuthorizedAlways) { [self.locationManager startUpdatingLocation]; // 开始更新位置 } } // 实现delegate方法获取位置 - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations { CLLocation *currentLocation = locations.lastObject; NSLog(@"当前位置:%f, %f", currentLocation.coordinate.latitude, currentLocation.coordinate.longitude); // 可以在这里更新Google Maps的相机位置 GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:currentLocation.coordinate.latitude longitude:currentLocation.coordinate.longitude zoom:15]; self.mapView.camera = camera; }
3. Google Maps当前位置显示校验
确保你开启了「我的位置」功能,并且API配置正确:
// 在AppDelegate中初始化Google Maps API(必须在didFinishLaunchingWithOptions里) - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [GMSServices provideAPIKey:@"YOUR_GOOGLE_MAPS_API_KEY"]; return YES; } // 在地图ViewController里开启我的位置 self.mapView.myLocationEnabled = YES; // 设置我的位置按钮 self.mapView.settings.myLocationButton = YES;
另外检查API Key是否启用了「Maps SDK for iOS」和「Geocoding API」(如果需要地址转坐标),并且没有设置IP限制导致请求被拒。
二、获取用户目的地
有两种常见方式:
- 地址搜索转坐标:用Google Maps的
GMSGeocoder或苹果的CLGeocoder把用户输入的地址转成经纬度
// Google Maps地理编码示例 GMSGeocoder *geocoder = [[GMSGeocoder alloc] init]; [geocoder geocodeAddressString:@"北京市天安门广场" completionHandler:^(GMSReverseGeocodeResponse *response, NSError *error) { if (error) { NSLog(@"地理编码失败:%@", error.localizedDescription); return; } GMSPlacemark *placemark = response.firstResult; CLLocationCoordinate2D destinationCoord = placemark.coordinate; NSLog(@"目的地坐标:%f, %f", destinationCoord.latitude, destinationCoord.longitude); }];
- 地图选点:监听
GMSMapView的点击事件,让用户直接在地图上选目的地
- (void)mapView:(GMSMapView *)mapView didTapAtCoordinate:(CLLocationCoordinate2D)coordinate { // 这里可以添加标记 GMSMarker *marker = [[GMSMarker alloc] initWithPosition:coordinate]; marker.map = mapView; self.destinationLocation = [[CLLocation alloc] initWithLatitude:coordinate.latitude longitude:coordinate.longitude]; }
三、接近目的地时发送通知
推荐两种方案,根据你的需求选择:
方案1:Core Location区域监测(低功耗,适合后台)
创建一个圆形区域,当用户进入该区域时触发通知:
// 初始化区域(半径设为50米,可根据需求调整) CLCircularRegion *region = [[CLCircularRegion alloc] initWithCenter:self.destinationLocation.coordinate radius:50.0 identifier:@"DestinationRegion"]; region.notifyOnEntry = YES; region.notifyOnExit = NO; // 开始监测区域 [self.locationManager startMonitoringForRegion:region]; // 实现delegate方法处理区域进入事件 - (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region { if ([region.identifier isEqualToString:@"DestinationRegion"]) { [self sendArrivalNotification]; // 停止监测,避免重复触发 [self.locationManager stopMonitoringForRegion:region]; } } // 发送本地通知 - (void)sendArrivalNotification { UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init]; content.title = @"即将到达目的地"; content.body = @"您距离目的地已不足50米,请做好准备"; content.sound = [UNNotificationSound defaultSound]; UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:1 repeats:NO]; UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"ArrivalNotification" content:content trigger:trigger]; [[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:nil]; }
注意:需要先请求通知权限,在App启动时调用:
[[UNUserNotificationCenter currentNotificationCenter] requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) { if (!granted) { NSLog(@"用户拒绝了通知权限"); } }];
方案2:实时计算距离+预估时间(更精准,适合前台)
如果需要结合预估时间,可以在didUpdateLocations里实时计算:
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations { CLLocation *currentLocation = locations.lastObject; CLLocationDistance distance = [currentLocation distanceFromLocation:self.destinationLocation]; NSLog(@"距离目的地:%.2f米", distance); // 用苹果地图的MKDirections计算预估时间(需要导入MapKit) MKPlacemark *sourcePlacemark = [[MKPlacemark alloc] initWithCoordinate:currentLocation.coordinate addressDictionary:nil]; MKMapItem *sourceItem = [[MKMapItem alloc] initWithPlacemark:sourcePlacemark]; MKPlacemark *destPlacemark = [[MKPlacemark alloc] initWithCoordinate:self.destinationLocation.coordinate addressDictionary:nil]; MKMapItem *destItem = [[MKMapItem alloc] initWithPlacemark:destPlacemark]; MKDirectionsRequest *request = [[MKDirectionsRequest alloc] init]; request.source = sourceItem; request.destination = destItem; request.transportType = MKDirectionsTransportTypeWalking; // 或Driving MKDirections *directions = [[MKDirections alloc] initWithRequest:request]; [directions calculateETAWithCompletionHandler:^(MKETAResponse *response, NSError *error) { if (error) { NSLog(@"计算预估时间失败:%@", error.localizedDescription); return; } NSTimeInterval remainingTime = response.expectedTravelTime; NSLog(@"预估剩余时间:%.0f分钟", remainingTime/60); // 当距离小于100米 或 剩余时间小于5分钟时发送通知 if (distance < 100 || remainingTime < 300) { [self sendArrivalNotification]; [self.locationManager stopUpdatingLocation]; // 停止更新,避免重复触发 } }]; }
最后提醒:如果是后台需要持续定位,一定要开启Background Modes的Location updates,并且使用requestAlwaysAuthorization权限。
内容的提问来源于stack exchange,提问作者mnm
相关产品推荐
相关产品推荐

