SeaJelly
SeaJelly

Reputation: 1746

iOS / Apple Watch: iPhone app network request callback blocks not triggered when app is in background

My Apple Watch app sends a message to the companion iPhone app. In the main app's handleWatchKitExtensionRequest, I send a request to the server:

 - (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void (^)(NSDictionary *))reply {
    if ([[userInfo objectForKey:@"request"] isEqualToString:@"getPendingChallenge"]) {
        [MyClient getPendingNotifications:someId withDomain:host withSuccessBlock:^(id responseObject) {
            // process responseObject
            ...
            reply(response);
            return;
        } withFailureBlock:^(NSError *error, NSString *responseString) {
            // error handling
            return;
        }];
    }
}

getPendingNotifications above is just a regular network GET request using AFNetworking.

It all works well when the app is active. Because this network request is used to populate the UI on my Apple Watch, I do not wish the main app to be active. However, when the main app on iPhone is in background, I can see the network request being sent out, but the withSuccessBlock or withFailureBlock callback blocks in the above code never gets triggered.

Can the phone app receive network request responses in background mode? If so, what am I doing wrong?

Upvotes: 1

Views: 825

Answers (2)

SeaJelly
SeaJelly

Reputation: 1746

I have found a solution online that works for me, a post (http://www.fiveminutewatchkit.com/blog/2015/3/11/one-weird-trick-to-fix-openparentapplicationreply) by Brian Gilham.

And here's the code that works for me.

- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void (^)(NSDictionary *))reply {
    // There is a chance that the iOS app gets killed if it's in the background
    // before it has a chance to reply to Apple Watch.
    // The solution is to have the app respond to the request asap, then complete other tasks.
    // The following code begins – and ends, after two seconds – an empty background task right at the beginning of this delegate method
    // Then we kick off a background task for the real work
    // For more details see http://www.fiveminutewatchkit.com/blog/2015/3/11/one-weird-trick-to-fix-openparentapplicationreply

    __block UIBackgroundTaskIdentifier bogusWorkaroundTask;
    bogusWorkaroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        [[UIApplication sharedApplication] endBackgroundTask:bogusWorkaroundTask];
    }];
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [[UIApplication sharedApplication] endBackgroundTask:bogusWorkaroundTask];
    });

    __block UIBackgroundTaskIdentifier realBackgroundTask;
    realBackgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        reply(nil);
        [[UIApplication sharedApplication] endBackgroundTask:realBackgroundTask];
    }];

    if ([[userInfo objectForKey:@"request"] isEqualToString:@"getPendingChallenge"]) {
        [self handleWatchKitGetPendingChallengeRequest:reply];
    }

    [[UIApplication sharedApplication] endBackgroundTask:realBackgroundTask];
}

- (void)handleWatchKitGetPendingChallengeRequest:(void (^)(NSDictionary *))reply {
    ...
    [MyClient getPendingNotifications:someId withDomain:host withSuccessBlock:^(id responseObject) {
        // process responseObject
        reply(response);
        return;
    } withFailureBlock:^(NSError *error, NSString *responseString) {
        // error handling
        reply(nil);
        return;
    }];
}

Upvotes: 2

Yedidya Reiss
Yedidya Reiss

Reputation: 5326

Try to send the request as a synchronous request.

I guess that your request is asynchronous request (as it should be in regular cases). The problem that in background mode, the device will lunch your app in background thread, and you created a new thread for the request.

Upvotes: 0

Related Questions