Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

iMessage + Apps + Messages App

DZone's Guide to

iMessage + Apps + Messages App

iMessage service, Apple’s secure instant messaging service, accessible via the Messages apps on iOS and macOS, recently got an upgrade with iOS 10: third-party iMessage Apps and the Messages App store. Read on to find out more.

· Mobile Zone
Free Resource

Get gorgeous, multi-touch charts for your iOS application with just a few lines of code.

iMessage service, Apple’s secure instant messaging service, accessible via the Messages apps on iOS and macOS, recently got an upgrade with iOS 10: third-party iMessage Apps and the Messages App store.  Currently, the Messages App on macOS can view messages created on iOS Messages App.

Let’s first take a brief look at terminology related to iMessage service.

Terminology

  • iMessage: Apple’s Instant Messaging service, which boasts end-to-end encryption.
  • Messages Apps: The messaging apps on iOS and macOS developed by Apple, or now the platform for stickers and 3rd party apps
  • iMessage Apps: Apps developed by 3rd-party app publishers / developers that reside in Messages App. 
  • Messages App store: An app store accessible within Messages App to browse, buy and install Messages Apps.
  • Messages Framework: Apple Messages Framework offers a number of classes that iMessage apps leverage  to interact with the Messages app.
  • App Extension: App Extension is a way to extend your app’s functionality to other apps on a user’s device.  E.g. Share a picture from within Photos app to Twitter.  The Twitter iOS App and Twitter App Extension have different life cycles and run independently of each other.  iMessage Apps are implemented as app extensions.
  • iMessage Application: The project that you use in Xcode to create an iMessage App.

Using the Messages Framework in iOS 10 app publishers can create an app extension that lets users interact with your app directly within the Messages app.

Messaging users get easy access your content and functionality, without having to leave and launch the Messages app. They can conveniently share content, edit photos, play games, send payments, and collaborate with friends within a custom interface that you design.

Messaging users can easily create and share content, add stickers, send payments, and collaborate expressively with friends without needing to switch to another app and leave the messaging conversations.

We have been writing extensively about bots and apps that use messaging as a platform in the article: Mobile Messaging: Yesterday vs. today & tomorrow.

Types of iMessage Apps

App publishers can use the Messages framework to create two types of app extensions: Sticker packs and iMessage apps. Both extension types can be created as standalone apps for Messages or as app extensions within a containing iOS app.

  • Standalone iMessages App: You write an app extension, using the iMessage extension point to extend the functionality and content of your app to the iOS Messages App.
  • Standalone Sticker pack app: App publishers can build a basic sticker pack made up of images or animated images, without writing code.
  • Sticker pack extension to iOS app: App publishers can bundle a sticker pack within an iOS app.
  • iMessage extension to iOS app: An iMessage extension can include the same features as a standalone iMessage app, and is distributed inside an iOS app. To learn more about developing iMessage Apps, watch WWDC videos part 1 and part 2 and see the reference here.

Messages Framework

The classes, protocol and enumerations made available by Apple to app developers to create iMessage Apps, are collectively part of the Messages Framework.

Use the MSMessagesAppViewController as the base class for your view controller to manage your Messages app extension. It has life-cycle management methods and supports the compact and full-screen presentation style.

Your app can insert text, stickers, or media into the Messages app’s input field.  The app users have to explicitly click on the arrow icon to send the inserted content to the remote participants.  The MSConversation class provides methods to insert content, and access to local participant (the sender) and array of remote participants (one or more receivers).

App-specific data is carried in instance of MSMessage class. Recipient updatable messages (for instance collaborative messages) are initialized explicitly with MSSession.   The appearance of MSMessage objects is managed via the MSMessageLayout.

PyzeiMessageApps Curated Event Class

Pyze has a large library of curated events for various verticals ranging from mobile commerce to app-controlled drones.  We just added another curated event class to allow iMessage App extensions to track creating and inserting stickers, iMessages, attachments, and text messages into a user’s messages. The API also has lifecycle methods to manage message lifecycle.

Pyze APICurated class PyzeiMessageApps

Sample Code and Assets

Creating an iMessage App extension

This section is about creating an iMessage App extension and posting events to https://growth.pyze.com about how your iMessage App is being used.

Prerequisites

Note, you need the latest Xcode version 8.0+ from App Store on OS X El Capitan or macOS Sierra (preferred).

Creating the iMessage Application

  • Start Xcode and create a new Xcode project of type: iMessage Application.
    screen-shot-2016-10-03-at-8-42-41-am
  • Compile and build the project
  • Close the Xcode Project (Important:  We will create a workspace and use it going forward, instead of a project created in Xcode)
  • Start Terminal and change directory to the folder where you created the above project.
  • Install the Pyze SDK using Cocoapods Pyze SDK using cocoapods.  If you are new to cocoapods see here.
  • cd to the folder where you created the project and create the pod file using pod init.
cd path/to/your/iMessageApp/project/
pod init
  • Open the created podfile in your favorite code editor and add pod ‘pyze-sdk-iOS’ in the MessagesExtention target as shown.
...
target 'MessagesExtension' do
    ...
    # Pods for MessagesExtension
    pod 'pyze-sdk-iOS'
end
  • Run pod update to create a workspace which we will use instead of project file.
pod update
  • Open the created workspace instead of project. From terminal using open <workspacename> or double click the workspace in Finder
open path/to/your/xcode/workspacefile.xcworkspace
  • Locate MessagesViewController.m under MessagesExtention folder
  • Add a reference to Pyze module
@import Pyze;
  • Goto growth.pyze.com, Add a new app and get a Pyze App Key.
  • Add the following in MessagesViewController.m,  using the Pyze App Key you obtained from growth.pyze.com
+(void) load {
    [Pyze initialize:@"replace with pyze app key obtained above" 
   withLogThrottling:PyzelogLevelMinimal];
}
  • Create three buttons in your storyboard to send a sticker, iMessage and PDF.  You will later create button handlers for creating a sticker, message, and attachment.

screen-shot-2016-10-03-at-4-01-13-pm

  • Insert the following code in MessagesViewController.m
// Initialize Pyze in the load method
+(void) load {
    [Pyze initialize:@"QF3zSg9SRwWdV6rsncEMBw" withLogThrottling:PyzelogLevelMinimal];
}
// Helper Method to create a dynamic image we will use when sending a message
-(UIImage *) snapShot {
    CGRect frameRect = CGRectMake(self.view.frame.size.width, self.view.frame.size.height, 300, 300);
    UIView * frameView = [[UIView alloc] initWithFrame:frameRect];
    frameView.backgroundColor = [UIColor whiteColor];
    
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(75, 75, 150, 150)];
    [label setFont:[UIFont systemFontOfSize:40.0f]];
    label.backgroundColor = [UIColor blackColor];
    label.textColor = [UIColor colorWithRed:69 / 255.0f green:165 / 255.0f blue:238 / 255.0f alpha:1.0f];
    label.text = [NSString stringWithFormat:@"%d", (int)++self.tokenCounter];
    label.layer.cornerRadius = CGRectGetWidth(frameRect) / 2.0f;
    label.clipsToBounds = YES;
    label.textAlignment = NSTextAlignmentCenter;
    
    [frameView addSubview:label];
    [self.view addSubview:frameView];
    
    UIGraphicsBeginImageContextWithOptions(frameRect.size, NO, [[UIScreen mainScreen] scale]);
    [frameView drawViewHierarchyInRect:frameView.bounds afterScreenUpdates:YES];
    UIImage * image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    [frameView removeFromSuperview];
    
    return image;
}
// Create and Insert an iMessage upon button click
- (IBAction)createiMessage {
    
    UIImage * image = [self snapShot];
    MSConversation * conversation = self.activeConversation;
    if (image && conversation) {
        MSMessageTemplateLayout * activeLayout = [[MSMessageTemplateLayout alloc] init];
        activeLayout.image = image;
        activeLayout.caption = @"Message Counter";
        activeLayout.subcaption = @"Message subcaption";
        activeLayout.trailingCaption = @"Trailing caption";
        activeLayout.trailingSubcaption = @"Trailing Subcaption";
        activeLayout.mediaFileURL = [NSURL URLWithString:@"Path to media URL"];
        activeLayout.imageTitle = @"Image counter";
        activeLayout.imageSubtitle = @"Image subtitle";
        
        MSMessage * message = [[MSMessage alloc] init];
        message.layout = activeLayout;
        message.URL = [NSURL URLWithString:@"Empty URL"];
        message.summaryText = @"This is Summary";
        
        [conversation insertMessage:message completionHandler:^(NSError * error) {
            NSLog(@"error %@",error);
            NSMutableDictionary * dictionary = [self fillMessagingAttributes:message conversation:conversation];
            [PyzeiMessageApps postInsertMessageWithAttributes: dictionary];
        }];
    }
}
//Create and Insert Sticker upon button click
- (IBAction)createSticker
{
    NSURL * urlPath = [[NSBundle mainBundle] URLForResource:@"pyzeLogo" withExtension:@"png"];
    if (urlPath) {
        MSSticker * sticker = [[MSSticker alloc] initWithContentsOfFileURL:urlPath
                                                      localizedDescription:@"Pyze logo" error:nil];
        MSConversation * conversation = self.activeConversation;
        if (conversation && sticker) {
            [conversation insertSticker:sticker completionHandler:^(NSError * error) {
                NSLog(@"error %@",error);
                NSMutableDictionary * attributes = [NSMutableDictionary dictionary];
                
                // conversation details
                attributes[@"localParticipantHash"] = [Pyze hash:[conversation.localParticipantIdentifier UUIDString]];
                if (conversation.remoteParticipantIdentifiers)
                    attributes[@"remoteParticipants"] = @(conversation.remoteParticipantIdentifiers.count);
                
                NSMutableString * remoteParticipantHashes = [NSMutableString string];
                for (NSUUID * uuid in conversation.remoteParticipantIdentifiers) {
                    [remoteParticipantHashes appendString:[Pyze hash:[uuid UUIDString]]];
                }
                
                if (remoteParticipantHashes && remoteParticipantHashes.length)
                    attributes[@"remoteParticipantsHashes"] = remoteParticipantHashes;
                
                
                [PyzeiMessageApps postInsertStickerWithLocalizedDescription:true
                                              withStickerImageFileURLString:true
                                                             withAttributes:attributes];
            }];
        }
    }
}
//Create and Insert an attachment upon button click
- (IBAction)createAttachment
{
    NSURL * urlPath = [[NSBundle mainBundle] URLForResource:@"PyzeGrowthIntelligence" withExtension:@"pdf"];
    if (urlPath) {
        MSConversation * conversation = self.activeConversation;
        
        [conversation insertAttachment:urlPath
                 withAlternateFilename:nil
                     completionHandler:^(NSError * error) {
                         NSLog(@"error %@",error);
                         NSMutableDictionary * attributes = [NSMutableDictionary dictionary];
                         
                         // conversation details
                         attributes[@"localParticipantHash"] = [Pyze hash:[conversation.localParticipantIdentifier UUIDString]];
                         if (conversation.remoteParticipantIdentifiers)
                             attributes[@"remoteParticipants"] = @(conversation.remoteParticipantIdentifiers.count);
                         
                         NSMutableString * remoteParticipantHashes = [NSMutableString string];
                         for (NSUUID * uuid in conversation.remoteParticipantIdentifiers) {
                             [remoteParticipantHashes appendString:[Pyze hash:[uuid UUIDString]]];
                         }
                         
                         if (remoteParticipantHashes && remoteParticipantHashes.length)
                             attributes[@"remoteParticipantsHashes"] = remoteParticipantHashes;
                         
                         [PyzeiMessageApps postInsertAttachmentWithURL:true
                                                 withAlternateFileName:true
                                                        withAttributes:attributes];
                         
                     }];
    }

}
-(NSMutableDictionary *) fillMessagingAttributes:(MSMessage *)message
                                    conversation:(MSConversation *)conversation
{
    NSMutableDictionary * attributes = [NSMutableDictionary dictionary];
    // Message details
    if (message) {
        if (message.URL) attributes[@"URL"] = @"1";
        if (message.summaryText) attributes[@"summaryText"] = @"1";
    }
    // message layout details
    MSMessageTemplateLayout * layout = (MSMessageTemplateLayout *)message.layout;
    if (layout) {
        if (layout.caption) attributes[@"caption"] = @"1";
        if (layout.subcaption) attributes [@"subcaption"] = @"1";
        if (layout.trailingCaption) attributes[@"trailingCaption"] = @"1";
        if (layout.trailingSubcaption) attributes[@"trailingSubcaption"] = @"1";
        if (layout.image) attributes[@"image"] = @"1";
        if (layout.mediaFileURL) attributes[@"mediaFileURL"] =  @"1";
        if (layout.imageTitle) attributes[@"imageTitle"] = @"1";
        if (layout.imageSubtitle) attributes[@"imageSubtitle"] = @"1";
    }
    // conversation details
    if (conversation) {
        attributes[@"localParticipantHash"] = [Pyze hash:[conversation.localParticipantIdentifier UUIDString]];
        if (conversation.remoteParticipantIdentifiers)
            attributes[@"remoteParticipants"] = @(conversation.remoteParticipantIdentifiers.count);
        
        NSMutableString * remoteParticipantHashes = [NSMutableString string];
        for (NSUUID * uuid in conversation.remoteParticipantIdentifiers) {
            [remoteParticipantHashes appendString:[Pyze hash:[uuid UUIDString]]];
        }
        
        if (remoteParticipantHashes && remoteParticipantHashes.length)
            attributes[@"remoteParticipantsHashes"] = remoteParticipantHashes;
    }
    return attributes;
}
  • Finally, add the Pyze methods to didReceiveMessage,  didStartSendingMessage, and didCancelSendingMessage
-(void)didReceiveMessage:(MSMessage *)message conversation:(MSConversation *)conversation {
    [PyzeiMessageApps postReceiveMessageWithAttributes:
       [self fillMessagingAttributes:message 
         conversation:conversation]];
}
-(void)didStartSendingMessage:(MSMessage *)message conversation:(MSConversation *)conversation {
    [PyzeiMessageApps postMessageStartSendingWithAttributes:
      [self fillMessagingAttributes:message 
        conversation:conversation]];
}
-(void)didCancelSendingMessage:(MSMessage *)message conversation:(MSConversation *)conversation {
    [PyzeiMessageApps postCancelSendingMessageWithAttributes: 
        [self fillMessagingAttributes:message 
          conversation:conversation]];
}

simulator-screen-shot-oct-3-2016-5-21-55-pmsimulator-screen-shot-oct-3-2016-5-22-40-pmsimulator-screen-shot-oct-3-2016-5-26-17-pm

  • You can track message on growth.pyze.com.

screen-shot-2016-10-03-at-5-11-54-pm

It is important to note that you did not send any message content, or sender or recipients IDs to Pyze using the helper method fillMessagingAttributes above.

.Net developers: use Highcharts, the industry's leading interactive charting library, without writing a single line of JavaScript.

Topics:
app ,ios ,extensions ,app store ,imessage ,mobile

Published at DZone with permission of Dickey Singh, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}