Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
121 views
in Technique[技术] by (71.8m points)

ios - How do I correctly use "openParentApplication" and "handleWatchKitExtensionRequest" so that "reply()" is called?

Situation: I use openParentApplication in the Watch app to call handleWatchKitExtensionRequest in the main app. This works nicely in the simulator and it also works on the actual devices (Apple Watch and iPhone) when the iPhone app is active/open.

Problem: When I run it on the actual devices (Apple Watch and iPhone), handleWatchKitExtensionRequest does not return data to openParentApplication when the main iPhone app is not active/open.

Code in InterfaceController.m in the WatchKit Extension:

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

Code in the app delegate of the main app on iPhone:

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

When the main app on the iPhone is not active, reply() may not be reached because the background task is killed by the OS before.

The solution is to explicitly start a background task in handleWatchKitExtensionRequest as specified in the documentation. If a background task is initiated like this, it can run up to 180 seconds. This ensures that the main app on the iPhone is not suspended before it can send its reply.

Code in the app delegate of the main app on 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];
   } );
}

In case you need to asynchroneously fetch data, use the following approach to ensure that the method does not return immediately (without calling 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];
  });
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...