如何正确使用“openParentApplication”和“handleWatchKitExtensionRequest”以便“reply()”被调用?

情况:我在Watch应用程序中使用openParentApplication在主应用程序中调用handleWatchKitExtensionRequest 。 这在模拟器中很好地工作,它也适用于实际的设备(苹果手表和iPhone),当iPhone应用程序是主动/打开。

问题:当我在实际设备(Apple Watch和iPhone)上运行它时,当主iPhone应用程序未处于活动状态或打开状态时, handleWatchKitExtensionRequest不会将数据返回到openParentApplication

WatchKit扩展中的InterfaceController.m中的代码:

 NSDictionary *requst = @{ @"request" : @"getData" }; [InterfaceController openParentApplication:requst reply:^( NSDictionary *replyInfo, NSError *error ) { // do something with the returned info }]; 

iPhone上的主应用程序的代理代码:

 - (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void ( ^)( NSDictionary * ))reply { if ( [[userInfo objectForKey:@"request"] isEqualToString:@"getData"] ) { // get data // ... reply( data ); } } 

当iPhone上的主应用程序未处于活动状态时,可能无法达到reply()因为之前的操作系统已经终止了后台任务。

解决scheme是在handleWatchKitExtensionRequest显式启动后台任务,如文档中所述。 如果像这样启动后台任务,最多可以运行180秒。 这可确保iPhone上的主应用程序在发送其答复之前不会暂停。

iPhone上的主应用程序的代理代码:

 - (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void ( ^)( NSDictionary * ))reply { __block UIBackgroundTaskIdentifier watchKitHandler; watchKitHandler = [[UIApplication sharedApplication] beginBackgroundTaskWithName:@"backgroundTask" expirationHandler:^{ watchKitHandler = UIBackgroundTaskInvalid; }]; if ( [[userInfo objectForKey:@"request"] isEqualToString:@"getData"] ) { // get data // ... reply( data ); } dispatch_after( dispatch_time( DISPATCH_TIME_NOW, (int64_t)NSEC_PER_SEC * 1 ), dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0 ), ^{ [[UIApplication sharedApplication] endBackgroundTask:watchKitHandler]; } ); } 

如果您需要asynchronous获取数据,请使用以下方法确保该方法不会立即返回(没有调用回复):

 - (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void ( ^)( NSDictionary * ))reply { __block UIBackgroundTaskIdentifier watchKitHandler; watchKitHandler = [[UIApplication sharedApplication] beginBackgroundTaskWithName:@"backgroundTask" expirationHandler:^{ watchKitHandler = UIBackgroundTaskInvalid; }]; NSMutableDictionary *response = [NSMutableDictionary dictionary]; dispatch_semaphore_t sema = dispatch_semaphore_create(0); [ClassObject getDataWithBlock:^(BOOL succeeded, NSError *error){ if (succeeded) { [response setObject:@"update succeded" forKey:@"updateKey"]; } else { if (error) { [response setObject:[NSString stringWithFormat:@"update failed: %@", error.description] forKey:@"updateKey"]; } else { [response setObject:@"update failed with no error" forKey:@"updateKey"]; } } reply(response); dispatch_semaphore_signal(sema); }]; dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); dispatch_after(dispatch_time( DISPATCH_TIME_NOW, (int64_t)NSEC_PER_SEC * 1), dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [[UIApplication sharedApplication] endBackgroundTask:watchKitHandler]; }); }