Inconsistent behavior of openParentApplication in my WatchKit App

I’m developing an Apple Watch application that uses the openParentApplication:reply: method to communicate with its parent app.

The parent app communicates with a web service and sends back the data it gets to the watch extension by means of calling the reply method with a NSDictionary containing the data.

  • How can I change the label “Cancel” from modal segue in Apple Watch
  • Pass data from Parse tableview to WatchKit
  • WatchKit Simulator Won't Load App
  • Render a line graph on Apple Watch using watchOS 2
  • How to establish a communication channel between Apple Watch Extension/App and iOS App
  • WatchKit 2 Complication Text Only Shows Up in Preview
  • The app works perfectly when the parent app is open in the foreground or background. But if I open the parent app and then terminate it using the task switcher, the first time the watch extension makes a call to openParentApplication:replyInfo:, it gets the following error and the parameter replyInfo comes in as nil.

    UIApplicationDelegate in the iPhone App never called reply()

    But every single openParentApplication:replyInfo: call the extension makes after that gets a proper response.

    I checked and found out that the first time the watch extension makes the call, the handleWatchKitExtensionRequest:reply: is never get called on the parent app.

    What could be the possible reason for this?

    I’m performing all operations in the handleWatchKitExtensionRequest:reply: in a background task, as suggested in the docs. Here’s some of my code:
    Code from my extension:

    NSDictionary *params = @{@"requestCode": @(RequestGetLoggedIn)};
    
    [WKInterfaceController openParentApplication:params reply:^(NSDictionary *replyInfo, NSError *error) {
        // Do something with the result
    }];
    

    Code from the parent app:

    - (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void (^)(NSDictionary *))reply
    {
        self.backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
            [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
        }];
    
        NSNumber* requestCode = userInfo[@"requestCode"];
    
        // Perform some request and then call reply()
    
        // End the background task
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTask];
        });
    }
    

    Edit 1: The problem occurs both on the Simulator and on a real Apple Watch.

    2 Solutions Collect From Internet About “Inconsistent behavior of openParentApplication in my WatchKit App”

    It looks like there’s a bug in iOS 8.4.

    I’ve added NSLog‘s to the beginning of application:didFinishLaunchingWithOptions: and handleWatchKitExtensionRequest:reply:, performed the actions that lead to the problem and then checked the device log and got this:

    --- Notice>: (Warn ) WatchKit: <SPCompanionAppServer.m __91-[SPCompanionAppServer launchCompanionAppForGizmoAppWithIdentifier:withUserInfoData:reply:]_block_invoke_2:1450> Got BSActionErrorCodeResponseNotPossible for com.xyz.xyz.watchkitapp. This will translate to WatchKitApplicationDelegateWatchKitRequestReplyNotCalledError
    
    ... Irrelevant stuff
    
    --- WatchKit Extension[1686] <Warning>: __59-[InformationController getNotificationListIncremental:]_block_invoke (null)
    **--- <Warning>: MY LOG: Application did launch with parameters (null)**
    

    This log shows that application:didFinishLaunchingWithOptions: gets called AFTER the OS gives an error about not getting a response from the parent app. How’s the app gonna give a response if it’s not getting launched first?

    I’ve temporarily solved the problem by calling the openParentApplication:reply: method again when this problem occurs.

    The way I’ve implemented the retry once behaviour is by creating a method that wraps the call and using that one instead the original method. I added this as a class method to a utility class, but it can be a global function as well.

    + (void)openParentApplication:(NSDictionary*)params reply:(void(^)(NSDictionary *replyInfo, NSError *error))reply
    {
        [WKInterfaceController openParentApplication:params reply:^(NSDictionary *replyInfo, NSError *error) {
            if (error.domain == WatchKitErrorDomain && error.code == WatchKitApplicationDelegateWatchKitRequestReplyNotCalledError)
            {
                dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                    [WKInterfaceController openParentApplication:params reply:^(NSDictionary *replyInfo, NSError *error) {
                        reply(replyInfo, error);
                    }];
                });
            }
            else
                reply(replyInfo, error);
        }];
    }
    

    I am getting the same issue. See the following bare bones project I made for a bug report to Apple: https://www.dropbox.com/s/ayltpprjck37ins/HandleWatchkitExtensionError%202.zip?dl=0.

    @Cihan Tek – how are you calling openParentApplication:reply: again? Are you calling it in the reply block? I am still receiving the error when I do that.