You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 09:59:14