简体   繁体   English

位置服务无法在WatchKit调用的后台运行

[英]Location Services not working in background called by WatchKit

My Apple Watch app requires some data and requests it from the corresponding iPhone app. 我的Apple Watch应用程序需要一些数据并从相应的iPhone应用程序请求它。 To fulfill the request the iPhone app requires the users location. 要满足请求,iPhone应用程序需要用户位置。 After receiving and testing with a real Apple Watch I found out that my iPhone app does not receive location updates when running in background. 在使用真正的Apple Watch接收和测试后,我发现我的iPhone应用程序在后台运行时没有收到位置更新。 If the iPhone app is active in foreground it works without issues. 如果iPhone应用程序在前台处于活动状态,则可以正常运行。 With the simulator it worked in both cases. 使用模拟器,它在两种情况下都有效。

In both cases (active and background) the WatchKit extension calls and starts successfully the iPhone app and goes all the way until startUpdatingLocation is called in the iPhone app. 在这两种情况下(活动和后台),WatchKit扩展程序会成功调用并启动iPhone应用程序并一直运行,直到在iPhone应用程序中调用startUpdatingLocation。 But in case the app is running in background didUpdateLocations is never called. 但是,如果应用程序在后台运行,则永远不会调用didUpdateLocations。

I tried with requestAlwaysAuthorization as well as requestWhenInUseAuthorization. 我尝试使用requestAlwaysAuthorization以及requestWhenInUseAuthorization。 No difference. 没有不同。 I also activated then the "location updates" background mode within capabilities. 我还激活了功能内的“位置更新”后台模式。 But again no difference. 但再没有区别。

Has someone else faced the same problem and found a way to receive the location also in background? 有其他人遇到同样的问题,并找到了在后台接收位置的方法吗?

Here some code. 这里有一些代码。 First the check if authorization is required. 首先检查是否需要授权。

// iOS 8 check to avoid crash on older iOS
    if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)])
    {
        [self requestLocationAlwaysAuthorization];
    }
    else
    {
        [self runLocationUpdate];
    }

Here the check for the proper Location Manager rights. 在这里检查正确的位置管理器权限。

- (void)requestLocationAlwaysAuthorization
{
CLAuthorizationStatus currentAuthStatus = [CLLocationManager authorizationStatus];

if (currentAuthStatus == kCLAuthorizationStatusDenied)
{
    //request user to change setting
}
else if (currentAuthStatus == kCLAuthorizationStatusRestricted)
{
    //request user to change setting
}
else if (currentAuthStatus == kCLAuthorizationStatusNotDetermined)
{
    [self.locationManager requestAlwaysAuthorization];

    [self runLocationUpdate];
}
else if (currentAuthStatus == kCLAuthorizationStatusAuthorizedWhenInUse)
{
    //maybe when in use is also enough?
    [self runLocationUpdate];
}
else if (currentAuthStatus == kCLAuthorizationStatusAuthorizedAlways)
{
    //all ok
    [self runLocationUpdate];
}

} }

Here the call of startUpdatingLocation. 这里调用startUpdatingLocation。 The didUpdateLocations delegate will only be called when iPhone app is active. 只有在iPhone应用程序处于活动状态时才会调用didUpdateLocations委托。

-(void)runLocationUpdate
{
    [self.locationManager startUpdatingLocation];
}

Three things to check and be aware of: 要检查和注意的三件事:

  1. Location Permissions like [self.locationManager requestAlwaysAuthorization]; 位置权限如[self.locationManager requestAlwaysAuthorization]; are only acknowledged once by the OS. 仅由操作系统确认一次。 If you have already requested permission, doesn't matter the level, the OS will NOT display a request to the user. 如果您已经请求了权限,则无论级别如何,操作系统都不会向用户显示请求。 The OS will just pass over the request and leave the permission level as is. 操作系统将仅传递请求并保留权限级别。 The only time you can be assured that the OS will display the request to the user is if the [CLLocationManager authorizationStatus] returns kCLAuthorizationStatusNotDetermined . 只有当[CLLocationManager authorizationStatus]返回kCLAuthorizationStatusNotDetermined时,才能确定OS将向用户显示请求的唯一时间。 In every other case, you must manually request permission by displaying an Alert or other form of UI display. 在所有其他情况下,您必须通过显示警报或其他形式的UI显示来手动请求权限。 Also note that the OS retains whether or not it already displayed the request, even if you delete your app and reinstall it. 另请注意,即使您删除了应用并重新安装,操作系统仍会保留其是否已显示请求。 So to test, you need to reset your Simulator's Content or your iPhone's Location Privacy. 因此,要进行测试,您需要重置模拟器的内容或iPhone的位置隐私。

  2. Make sure you have added the plist keys for NSLocationAlwaysUsageDescription AND NSLocationWhenInUseUsageDescription If you don't add this to your plist, the OS will ignore any Location Permission Requests. 确保已为NSLocationAlwaysUsageDescriptionNSLocationWhenInUseUsageDescription添加了plist密钥如果不将其添加到plist,操作系统将忽略任何位置权限请求。

  3. If you want to use requestAlwaysAuthorization to get location data from the phone (not the watch app extension) while the phone app is in the background, will also require you register for Background Modes Location updates under Project>Target>Capabilities. 如果您想在手机应用程序处于后台时使用requestAlwaysAuthorization从手机(而不是手表应用程序扩展程序)获取位置数据,还需要在Project> Target> Capabilities下注册后台模式位置更新。

UPDATE Use a background task to give your app time to respond when in the background. 更新使用后台任务为您的应用程序提供在后台进行响应的时间。 Something like this: 像这样的东西:

-(void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void (^)(NSDictionary *replyInfo))reply{

    UIApplication *app = [UIApplication sharedApplication];

    UIBackgroundTaskIdentifier bgTask __block = [app beginBackgroundTaskWithName:@"watchAppRequest" expirationHandler:^{

        [[UIApplication sharedApplication] endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;

    }];

//make your calls here to your tasks, when finished, send the reply then terminate the background task

//send reply back to watch
reply(replyInfo);

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
        [app endBackgroundTask:bgTask];
        bgTask=UIBackgroundTaskInvalid;
    });
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM