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.
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.
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);
}];
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With