仅在点击 MKUserTrackingBarButtonItem 时提示位置授权

Posted

技术标签:

【中文标题】仅在点击 MKUserTrackingBarButtonItem 时提示位置授权【英文标题】:Prompt for Location Authorisation Only When MKUserTrackingBarButtonItem Is Tapped 【发布时间】:2014-09-30 14:42:36 【问题描述】:

我正在使用MKUserTrackingBarButtonItem(即指南针图标)在MKMapView 中显示和跟踪用户在被点击时的位置。这在 ios 7 中运行良好。在 iOS 8 中,我开始收到以下消息:

尝试在不提示位置授权的情况下启动 MapKit 位置更新。必须先调用 -[CLLocationManager requestWhenInUseAuthorization] 或 -[CLLocationManager requestAlwaysAuthorization]。

我了解必须添加以下代码:

if ([self->_locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)])

    [self->_locationManager requestWhenInUseAuthorization];

并且 Info.plist 文件必须包含: <key>NSLocationWhenInUseUsageDescription</key> <string></string>

我的问题是在哪里拨打requestWhenInUseAuthorization。如果我把它放在didChangeUserTrackingMode 中,为时已晚,我会收到上述错误消息。如果我在初始化CLLocationManager 时将它放在viewDidLoad 中,它可以正常工作,但它会改变屏幕的行为,即在加载地图时,不会跟踪用户的位置,因此用户应该只有在MKUserTrackingBarButtonItem 按钮被点击。

【问题讨论】:

【参考方案1】:

首先为观察者设置一个静态上下文(将它放在你的@implementation 上方),我们将使用它的地址(&)为我们提供这个类的唯一上下文:

static NSString* kShowsUserLocationChanged = @"kShowsUserLocationChanged";

接下来,您需要观察 MKMapView 的 showsUserLocation 属性:

[self.mapView addObserver:self
                      forKeyPath:@"showsUserLocation"
                         options:(NSKeyValueObservingOptionNew |
                                  NSKeyValueObservingOptionOld)
                         context:&kShowsUserLocationChanged];

如果之前没有确定,那么你需要一个请求授权的方法,作为奖励,我的方法还检查 Info.plist 是否配置正确,如果不是这样,就会提醒开发人员:

-(void)_requestLocationAuthorizationIfNotDetermined
    if([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined)
        BOOL always = NO;
        if([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"])
            always = YES;
        
        else if(![[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"])
            @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"Location usage description missing from Info.plist" userInfo:nil];
        
        static CLLocationManager* lm = nil;
        static dispatch_once_t once;
        dispatch_once(&once, ^ 
            // Code to run once
            lm = [[CLLocationManager alloc] init];
        );
        if(always)
            [lm requestAlwaysAuthorization];
        else
            [lm requestWhenInUseAuthorization];
        
    

最后,需要添加observe方法实现:

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context 
    // if it was our observation
    if(context == &kShowsUserLocationChanged)
        // if its being enabled
        if([[change objectForKey:NSKeyValueChangeNewKey] boolValue])
            [self _requestLocationAuthorizationIfNotDetermined];
        
    
    else
        // if necessary, pass the method up the subclass hierarchy.
        if([super respondsToSelector:@selector(observeValueForKeyPath:ofObject:change:context:)])
            [super observeValueForKeyPath:keyPath
                                 ofObject:object
                                   change:change
                                  context:context];
        
    

您可以通过卸载应用程序来测试它,这会清除下一次部署和运行的授权状态。

【讨论】:

【参考方案2】:

我已经成功地在第一次需要时将呼叫发送到 requestWhenInUseAuthorization,然后回复 didChangeAuthorizationStatus 以开始跟踪。

例子:

https://github.com/mapbox/mapbox-ios-sdk/blob/509fa7df46ebd654d130ab2f530a8e380bf2bd59/MapView/Map/RMMapView.m#L3299-L3323

https://github.com/mapbox/mapbox-ios-sdk/blob/509fa7df46ebd654d130ab2f530a8e380bf2bd59/MapView/Map/RMMapView.m#L3746-L3753

【讨论】:

虽然它不使用MKUserTrackingBarButtonItem。我希望在用户点击 MKUserTrackingBarButtonItem 时出现提示。 我不肯定它会起作用,但尝试子类化 MKMapView 以覆盖 setUserTrackingMode:animated: 以介于按钮和地图属性更改之间。

以上是关于仅在点击 MKUserTrackingBarButtonItem 时提示位置授权的主要内容,如果未能解决你的问题,请参考以下文章

iOS:仅在 iOS 13 上不会触发点击事件

Javascript仅在点击时填充画布的某些部分

Angular6:点击功能仅在某些时候有效

UIbutton 仅在 longPress 上看起来被点击(突出显示)?

Android Webview,仅在链接上启用长点击?

jQuery 提交仅在第二次点击后工作