Passing UIImage from iPhone to Apple Watch results

2019-08-12 12:17发布

问题:

My watch needs to request an image from the containing app. In the watch's controller, I have:

- (void)getOrgLogo {
    NSString *host = mfaInfo[@"host"];
    NSDictionary *getOrgLogoRequest = @{@"request":@"getOrgLogo", @"host":host};
    [MyInterfaceController openParentApplication:getOrgLogoRequest reply:^(NSDictionary *replyInfo, NSError *error) {
        if (error) {
            ...
        } else if (replyInfo == nil) {
            // I am always getting into this block!!!
        } else {
            UIImage *orgLogo = replyInfo[@"orgLogo"];
            if (orgLogo != nil) {
                [self.orgLogoImageView setImage:orgLogo];
            }
        }
    }];
}

In my main app, I send a request to the server to get the image, then pass the image back to watch:

- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void (^)(NSDictionary *))reply {
    ...
    if ([[userInfo objectForKey:@"request"] isEqualToString:@"getOrgLogo"]) {
        NSString *host = userInfo[@"host"];
        [self handleWatchKitGetOrgLogoRequest:reply withHost:host];
    }
    ...
}

- (void)handleWatchKitGetOrgLogoRequest:(void (^)(NSDictionary *))reply withHost:(NSString *)host{
    NSMutableDictionary *response = [[NSMutableDictionary alloc] init];

    // A server request to get the image
    [OktaAPIClient getLogoUrlFromHost:host withSuccess:^(UIImage *image) {
        // I'm getting in here - indicating I successfully got the image
        response[@"orgLogo"] = image;
        // I double checked the value of response here - it's not nil!
        reply(response);
    } withFailure:^(UIImage *image) {
        ...
        reply(response);
    }];
}

As commented in the code above, I checked the value of response right before I pass it back to watch and confirmed that it contain a value (a UIImage), however in the callback of the watch code, this reply becomes nil. I do not know what happens in the process. Any thoughts?

回答1:

Another way to do this is to enable app groups and save the images to a shared folder. This is really good if you are saving multiple images.

Start by enabling app groups under the capabilities tab for both your iphone and apple watch target.

Then use this code on the iPhone to save the image.

[OktaAPIClient getLogoUrlFromHost:host withSuccess:^(UIImage *image) {
  NSURL *groupURL = [[NSFileManager defaultManager]
    containerURLForSecurityApplicationGroupIdentifier:@"group.az.simpleSudoku"];

  NSString *sharedFilePath = [groupURL.path 
    stringByAppendingFormat:@"/%@", @"logo.png"];

  [UIImagePNGRepresentation(image) writeToFile:sharedFilePath atomically:YES];

  reply(response);
} withFailure:^(UIImage *image) {
        ...
    reply(response);
}];

And this to load that image on the watch.

NSURL *groupURL = [[NSFileManager defaultManager]
  containerURLForSecurityApplicationGroupIdentifier:@"group.az.simpleSudoku"];

NSString *sharedFilePath = [groupURL.path 
  stringByAppendingFormat:@"/%@", @"logo.png"];

NSData *imgData = [NSData dataWithContentsOfFile:imageFilePath];

[myInterfaceImage setImageData:imgData];

As long as your app groups are set up correctly, this works very well. I use it to pass sudoku board images back and forth in my app.



回答2:

From my experiment, it seems that UIImage can't be serialized and sent over to watch from the phone. So I converted the UIImage to NSData, then pass the data to watch, and then it's working fine.

Code in main app's handleWatchKitExtensionRequest:

NSMutableDictionary *response = [[NSMutableDictionary alloc] init];

[MyAPIClient getLogoUrlFromHost:host withSuccess:^(UIImage *image) {
    NSData *imageData = UIImagePNGRepresentation(image);
    [response setObject:imageData forKey:@"orgLogo"];
    reply(response);
} withFailure:^(UIImage *image) {
    NSData *imageData = UIImagePNGRepresentation(image);
    [response setObject:imageData forKey:@"orgLogo"];
    reply(response);
}];

Code in watch's openParentApplication:reply::

NSData *orgLogoData = replyInfo[@"orgLogo"];
if (orgLogoData != nil) {
    [self.orgLogoImageView setImage:[UIImage imageWithData:orgLogoData]];
}