【问题标题】:How do I correctly use "openParentApplication" and "handleWatchKitExtensionRequest" so that "reply()" is called?如何正确使用“openParentApplication”和“handleWatchKitExtensionRequest”以便调用“reply()”?
【发布时间】:2015-05-02 08:48:17
【问题描述】:

情况:我在Watch应用中使用openParentApplication在主应用中调用handleWatchKitExtensionRequest。这在模拟器中运行良好,并且在 iPhone 应用程序处于活动/打开状态时也适用于实际设备(Apple Watch 和 iPhone)。

问题:当我在实际设备(Apple Watch 和 iPhone)上运行它时,handleWatchKitExtensionRequest 不会在主 iPhone 应用程序未激活/未打开时将数据返回到 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 );
  }
}

【问题讨论】:

    标签: ios objective-c watchkit


    【解决方案1】:

    当 iPhone 上的主应用程序未激活时,可能无法到达reply(),因为后台任务之前被操作系统杀死。

    解决方案是在handleWatchKitExtensionRequest 中显式启动后台任务,如documentation 中指定的那样。如果像这样启动后台任务,它最多可以运行 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];
       } );
    }
    

    如果需要异步获取数据,请使用如下方式确保方法不会立即返回(不调用reply):

    - (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];
      });
    }
    

    【讨论】:

    • 有什么方法可以在模拟器中测试吗?因为我没有真正的手表。 @vomako
    • 问:为什么它在模拟器中运行正常,但在模拟器中运行手表应用时 iPhone 应用在后台。
    • 感谢您的回答。你能把它翻译成斯威夫特吗?我会自己做,但我遇到块问题。
    • @vomako 信号量方法似乎由于某种原因没有解除阻塞。成功的情况下怎么不派发信号?
    • 为什么我们需要 dispatch_after?不就是延迟1秒吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-29
    • 1970-01-01
    • 2019-06-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多