How can I access the image from the MSMessage's layout on the receiving user's end?

1.1k views Asked by At

I am making an iMessage Extension that involves users sending pictures back and forth to one another. They need to both be able to access the images that they receive from each other and use it on their own end. For example, if USER 1 sends a picture of a puppy to USER 2, the image property of the messages layout would be of the puppy. USER 2 should then be able to tap that message, and the puppy load into an image view on screen. So far I don't know how I would do this.

Here's where I set the layout image to that of a puppy.

@IBAction func sendPicturePressed(_ sender: AnyObject) {

    if chosenImage.image != nil {

        let session = MSSession()
        let message = MSMessage(session: session)
        let conversation = self.activeConversation
        let components = URLComponents()

        let layout = MSMessageTemplateLayout()

        let image = chosenImage.image
        layout.image = image

        message.layout = layout
        message.url = components.url!

        conversation?.insert(message, completionHandler: { (error) in

            self.dismiss()

        })

    }
}

Now when the second user taps the puppy, I want to set an image view on their screen to the puppy. Not exactly sure how, but what I'd LIKE to do is:

override func willBecomeActive(with conversation: MSConversation) {

    imageView.image = conversation.selectedMessage.layout.image

    //There is no image property to access this like I've provided, that's just what I'm trying to accomplish.
}
2

There are 2 answers

3
degapps On

Although you cannot access the layout once message is received, you still have once chance to get it. In case extension is launched, message's layout is accessible on arrival in -[didReceiveMessage:conversation:] method of your MSMessagesAppViewController-based class.

On the sender side you can assign your message a URL with custom ID (e.g. UUID) - it will be always accessible – then extract it on the receiver side in the didReceiveMessage together with the image and cache the latter locally with the ID as a name. Here's the code draft:

- (NSURL*) fileURLFromRawURL:(NSURL*)idURL
{
    NSString *fileID = idURL.relativePath;
    NSString *path = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:fileID];

    return [NSURL fileURLWithPath:path];
}

- (MSMessage*) composeMessageWithImage:(UIImage*)image session:(MSSession*)session
{    
    MSMessageTemplateLayout *layout = [MSMessageTemplateLayout new];
    layout.image = image;

    MSMessage *message = [[MSMessage alloc] initWithSession:session];
    message.layout = layout;
    message.URL = [NSURL fileURLWithPath:[[NSUUID UUID] UUIDString]];

    return message;
}

- (void) didReceiveMessage:(MSMessage *)message conversation:(MSConversation *)conversation 
{
    // Assuming that the extension is launched:
    MSMessageTemplateLayout *layout = message.layout;
    UIImage *img = layout.image;  // you've got the image
    NSURL *path = [self fileURLFromRawURL:message.URL];
    if (path && image){
        NSData *data = UIImageJPEGRepresentation((UIImage*)resource, 0.8);
        [data writeToURL:path options:NSDataWritingAtomic error:nil];
    }
}

After that, once message is tapped, the -[didSelectMessage:conversation:] will be called. Here you can get the URL again and read the corresponding image from cache (in case it is available):

- (void) didSelectMessage:(MSMessage *)message conversation:(MSConversation *)conversation
{ 
    NSURL *path = [self fileURLFromRawURL:message.URL];
    if (path){
        NSData *imageData = [NSData dataWithContentsOfURL:path];
        UIImage *img = [UIImage imageWithData:imageData];
    }
}

And don't forget to add all necessary checks for nils, successfull URL creation etc.

0
Jonny On

You can't access the layout image that send from another user. https://forums.developer.apple.com/thread/53174

The selected Message having a nil layout is expected. Received messages won't have a layout object filled in.

What you can, is on the sender side, you not only insert a MSMessage with image layout to MSConversation, but also upload an image copy to your server and mark the web image URL in MSMessage.URL.

So next time when user select a message, you can unwrap MSMessage.URL and find the image URL, then download it from your server.