WWDC2016 Session 224

Transcript

[ Music ]
[ Applause ]
>> Good afternoon.
Welcome to "iMessage Apps
and Stickers, Part 2".
My name's Alex and with me today
helping present is Stephen.
He's going to do the demos.
So, in the first part
of this talk, Bhaskar
and Lily introduced
stickers, sticker packs,
and simple iMessage apps focused
on providing sticker
data to messages.
Today we're going to talk
about interactive messages
and we're going to dive
deeper into the iMessage apps
and the Messages framework.
So, what are interactive
messages?
Well, you can see one
here behind me highlighted
in the Messages transcript.
This is a special type of
message bubble provided
by a Messages extension and
you can see that's shown here
in the screenshot highlighted.
Messages extensions
allow your users
to compose interactive messages
and then they allow them
to insert them on the
input field, as shown here.
They also allow a user to
reply to an interactive message
by tapping one in the transcript
and in this point an extension
will be launched full screen,
as shown here.
The user can interact with this
extension to compose a reply.
The user can interact with this
extension to compose a reply.
Your extension can then
insert this new content
into the messages and it will
show here on the input field
and the user can send it.
So, now we're going to
welcome Stephen to the stage
and he's going to show
you our sample app running
in the simulator.
[ Applause ]
>> I'm going to show you a
completed iMessage application
that I've written to demo all
of the APIs that we're going
to learn in today's session.
If you look here in the
simulator, you'll see the icon
from my iMessage app
called Ice Cream.
When I tap this, my iMessage
app is revealed here running
within the context of Messages.
All of the UI with this
pink background is code--
is UI provided by my extension.
Now, my iMessage app is
a collaborative ice cream
sticker-building application
and here you see a history
of ice cream stickers
that I've already built.
When I tap this Add button here,
my iMessage app will expand
When I tap this Add button here,
my iMessage app will expand
to take the full screen and I'll
have this nice sticker-building
experience here.
If I choose an ice cream cone,
my iMessage app dismisses
and stages an interactive
message
in the input field
for the user to send.
Now, on iOS 10, we've
added support for you to--
for you to develop and test
your iMessage apps right
within the simulator.
If you go back to the
conversation list here,
you'll see two ends of a
simulated conversation.
Tapping the second one shows
the simulated received message.
When I tap this, my iMessage app
is launched with the next step
in the ice cream
building process.
I can select my favorite
ice cream, mint chip,
stage that message, and send it.
Now, if I go back to that first
conversation or the first end
of the conversation
and tap this message
and select the final part of
the ice cream, my topping,
and send it, I now have
a completed ice cream
that I've built.
In fact, now when I go
back into my iMessage app,
you'll see that it appears
here in my ice cream history
as a sticker that I can then
apply anywhere I want to.
And that's a quick
sample of what you can do
with interactive messages.
And now back to Alex.
[ Applause ]
>> Thanks, Stephen.
That was just a great
quick demo of some
of the features of
iMessage apps.
So, let's talk about how we can
accomplish this with our APIs.
I'm going to go through
four things.
One of them-- so I'm going
to give you an overview
of the API followed by
number two, a little look
into the extension lifecycle.
Number three, we're
going to talk about how
to compose a message
using our APIs.
Number four, we're going
to talk a little bit
Number four, we're going
to talk a little bit
about how the message is sent.
So, starting with
the API overview.
We have our iMessage
app running here,
shown in compact presentation
mode and this is an extension.
Extensions have a
principal class
and for iMessage apps
this will be a subclass
of the
MSMessagesAppViewController.
Now, ultimately,
the MSMessagesAppViewController
is a subclass
of UIViewController, so it's
providing your extension's UI.
Above the extension, we
have the conversation
and specifically the
conversation transcript.
This is represented in our API
by the MSConversation object.
And finally we have
a message itself.
We have this bubble
here in the transcript
and this is represented
by the MSMessage class.
Also, you'll note in this slide
we have another two classes
shown, the MSSession and
MSMessageTemplateLayout.
These provide some control
over how the message is sent
These provide some control
over how the message is sent
and how the message
appears in the transcript.
So, let's move on and talk about
iMessage extension lifecycle.
Here we have a timeline and
when an extension is launched,
perhaps from the app drawer,
we're going to launch a process.
Shortly afterwards, we'll
call didBecomeActive
with conversation and
we're going to pass
in a conversation object
that represents the conversation
your app is running within.
And since this is a
UIViewController subclass,
we'll also call will--
viewWillAppear and viewDidAppear
as your extension
appears onscreen.
Now, what happens
when your app remove--
is removed from the screen?
We're going to call
this resigning active
and what happens is first you
will receive viewWillDisappear,
viewDidDisappear calls
on your principal class.
This is followed by
a viewWill-- sorry--
This is followed by
a viewWill-- sorry--
this is followed
by a willResignActive
call with conversation.
At this point, we're about
to teardown the connection
between Messages
and your extension.
So, this is the last time
you get to do anything
with the conversation.
And then at some point later
your process will be terminated
and this-- just to stress-- is
because your process is built
on extensions and extensions
are short-lived processes
and they're terminated
aggressively.
So, let's see now that we have
a process running and showing UI
within Messages, your user is
going to interact with this UI
and build a message and
let's see how we're going
to deal with that in our API.
Well, the first thing
you're going
to do is create an MSMessage
object and we're going
to set some properties
on that object.
In this case, I'm
setting an https URL
so the message is URL property
and I'm encoding some detail
about the ice cream
that we're building
in the query string of that URL.
The only platform that is
able to generate iMessage--
The only platform that is
able to generate iMessage--
these messages is iOS, but
these messages will be sent
to macOS and to watchOS.
When they're delivered on
macOS, they'll be shown
in full fidelity in the
conversation transcript
and clicking on a message
in the transcript will try
and get this URL and open
it in your web browser.
So, if you provide an https URL
here, then your website is able
to show-- should be able
to show some representation
of the message for
users on macOS.
Moving on, we have an
accessibility label
property here.
This is used by screen readers
when reading the transcript.
So, I'm setting this
to a description
of the message bubble
so that our users
who use screen readers get
a great rich description
of the bubble as it is
displayed in the transcript.
And finally I'm going to talk
about-- we've got layout.
And I'm going to talk about this
in a little bit more detail now.
The layout object is how
we specify the appearance
of a message in the transcript.
Right now we only
have one layout
and that's the
MSMessageTemplateLayout.
We can set some properties
on this
and this affects how
the bubble is built.
So, right here we
have an image property
and this takes a UI image
and it provides content
for the area highlighted
onscreen.
We also have a mediaFileURL
property.
The mediaFileURL also provides
content for the same area
as the image, but here you
can provide content that's not
supported by UI image.
For instance, you could provide
a URL to a local video file.
A short video would be then
looped in the background
of the message bubble
in the transcript.
Let's take a second to
focus a little bit more
on these two properties.
We should note first
that if the image
and the URL are both provided,
then the image is going
to take precedence over the URL.
We had some recommended--
recommendations for the size
of the assets provided
in these properties.
We're recommending that
you provide your assets
We're recommending that
you provide your assets
at roughly 300 point
by 300 point.
You can provide slightly
larger assets
and slightly smaller assets
and I really encourage you
to experiment with asset
sizes here in order
to find what best suits
your app and your needs.
All of these assets, as with
stickers, are provided at 3x
and Messages will downsample
and downscale these images
when they arrive on other
devices as appropriate
for the screen resolution on
that-- on the receiving device.
In the mediaFileURL, we support
PNG, JPEG, GIF, and video.
When I say video,
what I mean here is
that we support any
videos that can be played
with our media player frameworks
and I'd like to refer you
to the media player
framework documentation
to find out more about this.
The other thing that
we're going to do
with this media is we're going
to transcode the assets
when they're sent.
This is in order
to optimize them
for transfer over our networks.
And finally I'd like
to encourage you
And finally I'd like
to encourage you
to avoid rendering
text into this image.
As I said, these images
are scaled down for display
on devices with 1x and 2x
screens, yet we're asking you
to provide them at 3x.
If you were to render
text into this image,
particularly small text, when
these images are scaled down,
the text could be rendered
illegible, but you'll notice
that we actually do show in this
example some text drawn on top
of the image, so let's
talk about how this is done
without degrading quality.
The layout has some additional
properties over image--
the two that provide images--
and these are text properties.
They're transformatted with
the message and drawn natively
on the receiving devices
so we can draw the text
on the receiving devices as
crisply and cleanly as possible.
We have here shown
the image title
and this is text that's
drawn on top of the image
in the lower left hand corner.
We have an image subtitle that's
drawn again on top of the image,
We have an image subtitle that's
drawn again on top of the image,
right below the image
title as shown.
And we have these
caption properties
and these are drawn below
the image in the caption bar.
That's this gray area onscreen.
So, we have caption,
trailing caption, subcaption,
and trailing subcaption.
Now, if you look at the caption
properties, it's also possible
to omit these altogether
or set them all to nil.
If you do that, then
you'll get a bubble
that doesn't have the
caption bar at the bottom
and it'll look something
more like this.
And one last thing to
note on this slide.
We have an icon in the top
left-hand corner of a bubble.
This icon is provided and
drawn by Messages on top
of your content and
this is always going
to be the iMessage app icon of
the app that sent the message.
So, let's move on now and talk
about how we send this message
So, let's move on now and talk
about how we send this message
that we've constructed.
To do that, we're going to need
to get an MSConversation
instance.
You can get this from
your principal class's
active conversation.
Once you have a conversation,
you can call the
insert(message),
pass the message you
constructed, and make sure
that you handle any
errors that are returned.
Doing this will cause
the message
to appear in the input field.
Of course, as mentioned
in the first talk,
you can also send some
other types of data.
We support sending
text, attachments,
and of course stickers.
Once you've got your
content on the input field,
the user is able
to send the message
by tapping the blue Send
button and I should note here
that there's no way
for your extension
to actually automatically
send a message
and we always want the
user to have the final say
as to what gets sent
to their friends.
as to what gets sent
to their friends.
So, now I'd like to hand
you back over to Stephen
who is going to show you
how we implement this
in our sample project.
[ Applause ]
>> Thanks again, Alex.
OK. I've taken the
sample iMessage app
that I showed earlier in
the session and stripped it
down to a very basic minimum
for our starting point.
Here we still have our
history of ice cream stickers
that have already been
built, but you'll notice
that if I tap the Add
button, nothing happens.
Here in Xcode, I have my
MSMessagesAppViewController
subclass shown.
I override the lifecycle
method did become active
with conversation, call super,
and then call present
child view controller
which is a helper
method I've written
which will instantiate an
ice cream history controller
and add it as a child
view controller.
And that's all I have so far.
Now, what I'd like to do is
when I tap this Add
button is start the
when I tap this Add
button is start the
sticker-building process.
Now, this ice cream history
view controller has a delegate
protocol and I have an extension
on my messages view controller
which conforms to this delegate
by implementing the method
historyViewController
AddButtonTapped.
This is where I'm going to
trigger my functionality
and I'm going to also start
by adding a helper method called
composeMessage for iceCream,
which will take an ice cream
model object and will turn it
into an MSMessage for me to
stage in my conversation.
To do so, I'm going to create
an instance of URL components
and set the query items
property of that URL components
to be a query items
representation of my model.
Next thing I'm going to
do is create an instance
of MSMessageTemplateLayout and
set the image of that layout
to be a rendered
version of my model.
I also want to set a
caption for my message
and I'll declare
my caption up here.
and I'll declare
my caption up here.
Now I'm ready to create
my MSMessage object.
I'll do so by declaring
an instance of MSMessage
and set the URL property
to be the URL representation
of my components.
Then I'll set the layout
and the accessibility label.
For brevity in the
demo, I'm just going
to reuse my message caption
as my accessibility label.
Now that I have my message,
I'm ready to stage it
in the conversation.
I'll get a reference to
my active conversation
and call conversation.insert
to insert the message
so it is staged.
Now that I've written my
composeMessage function,
here I'm ready to call it
from my historyViewController
AddButtonTapped method.
And I'll start off
by always adding
or passing a new ice
cream model instance.
Now when I run this
in the iOS simulator
and launch my iMessage
application,
wait for that debugger to attach
and tap the Plus (+) button.
My message is staged
for the user to send.
Now, because I haven't actually
selected any ice cream parts,
I just have a placeholder
image for the ice cream
and you see my caption
below the message.
Now, this is a great start,
but I'd like to get closer
to that final demo that
I showed you earlier.
When I tap that Plus
(+) button, I want to go
into my sticker-building
UI experience.
To do so, I need to introduce
a new concept to you.
Here my iMessage
app is presented
in a compact presentation style.
I can choose to have my
iMessage app presented
in an expanded presentation
style by requesting it.
Instead of calling
composeMessage
for iceCream here, I'll call
a method on my super class,
request presentation style
with the expanded enum case.
This will trigger a lifecycle
callback method called
willTransition to
presentationStyle.
I'll call the super
implementation
I'll call the super
implementation
and then I'll call
my helper method
to present the right
child view controller
for this presentation style.
Now,
my presentChildViewController
currently always presents my ice
cream history view
controller and so I need
to change the logic to take into
account the presentation style
so I present the
correct view controller.
First, I'm going to add a
parameter here so I know
which presentation
style I'm dealing with.
Then I'm going to change this
to only present my history
view controller when I'm
in the compact presentation
style.
If I'm in the expanded
case, I'm instead going
to declare a new instance
of my ice cream model
and let my controller
be an instance
of an ice cream builder
view controller
to which I'll pass
that ice cream model.
Now, lastly, before I add this
as a child view controller,
I need to remove any previous
child view controllers
to clean up my view hierarchy.
Now I need to update the call
sites to my helper method.
Here I'm going to add that--
pass that pending presentation
style and in the didBecomeActive
with conversation method,
I'm going to pass the
current presentation style,
which I can get as a property
on my parent view controller.
Should be right.
Lastly-- actually, let's see--
let's see what this looks like
if I can get this to work.
And I tap that Plus (+) button.
My iMessage application
goes to that expanded state
and I'm presenting that ice
cream builder view-- experience.
However, you'll notice that
when I tap Select nothing
happens yet.
Now, this is because my ice
cream builder view controller
Now, this is because my ice
cream builder view controller
also has a delegate protocol
and I have an extension
on my view controller here--
sorry to take you through that
so fast-- that implements
this delegate protocol
by implementing the method
iceCreamBuilderView controller
didSelect iceCreamPart
for iceCream.
This is called whenever that
Select button is tapped.
So, this is the right
point for me to call
that helper method I wrote,
compose message, and I'll pass
in the updated ice cream
model from this method.
The other thing I'm going
to do is call dismiss here
because my iMessage app is done
preparing content and so I'd
like my iMessage app to dismiss
and display the staged
message for the user.
Now when we launch this,
tap the Plus (+) button
and select an ice cream cone.
I dismiss my iMessage app
and the correct interactive
message is stage ready
and the correct interactive
message is stage ready
for the user to send.
And that's a quick
demo of what it looks
like to send an interactive
message.
Now back to Alex.
[ Applause ]
>> Thank you, Stephen.
Great demo.
So, Stephen has introduced
to you and shown you how
to use our APIs to
insert content
into the conversation
and send it.
Stephen also introduced
presentation styles,
so we're going to
have a quick look
at that in some more detail.
We have two presentation
styles, compact and expanded.
Compact one is shown here
and here we have expanded.
So, there's a couple
of differences
between these two
presentation styles.
In compact mode, you don't
have access to the keyboard.
You also don't have access
to horizontal scrolling,
You also don't have access
to horizontal scrolling,
swipe gesture recognizes.
This is because in the compact
mode the user can swipe left
and right to switch between
iMessage apps quickly.
However, you do have
access to the input field,
so whenever insert
message is called
in compact presentation style,
the message will
be inserted right
into the input fields right away
and the user can
see it immediately.
Subsequent calls to insert
message will cause the current
message to be replaced
with the new one,
so what you can do
here is allow your user
to iteratively build a
message, see it as it progresses
on the input field,
and when they're happy
with it they can send it.
To contrast, in expanded
presentation style we obviously
don't have access to
the input field here,
but we do have access
to horizontal swipe gesture
recognizes and scrolling
and you can use the keyboard.
The user can always
transition your extension
The user can always
transition your extension
between these two styles by
tapping on the top chevron
from expanded to collapse to
compact presentation style
and when in compact they can
tap on the chevron at the bottom
of the screen to expand your app
into expanded presentation
style.
So, when you're using
iMessage apps,
you need to be very
responsive to the area
in which your app is displayed.
Whenever these transitions
happen, you're going
to get some callbacks
on your principal class.
The willTransition to
presentationStyle will be called
as the transition
starts and at the end
when the transition is complete
will call didTransition(to:
presentationStyle).
As Stephen showed, you can
request presentation style
expanded or compact by calling
the requestPresentationStyle
method on your principal class.
And again, as was shown in
the demo, you can call dismiss
and this will dismiss
your iMessage app
and show the keyboard.
So, let's move on and talk
about how we reply to a message.
We have two cases here to cover.
One case when your extension is
inactive and there's a bubble
in the transcript that the
user taps and we're going
to look at that first.
We'll come back to
the second case.
So, looking at our
timeline again,
this should be very familiar.
The bubble is tapped by the user
and your process
will be launched.
And now we go through exactly
the same set of steps that we do
when your app is launched
from the app drawer.
You'll get a didBecomeActive
with conversation followed
by the viewWillAppear
and viewDidAppear.
When this is done, you'll--
your app will be presented in
expanded presentation style.
We always present apps in
expanded presentation style
when the user taps a button
to launch it-- sorry--
taps a bubble in the
transcript to launch it.
taps a bubble in the
transcript to launch it.
Now, looking at our second case,
the extension is already active.
In this case it's showing UI in
the compact presentation style.
So, looking again at our
timeline, in this case,
the bubble is tapped
and the app is active.
So, we're not going to
call willBecomeActive
or didBecomeActive.
Instead, you'll receive
a call to willTransition
to presentationStyle expanded.
This is followed by a didSelect
message and conversation.
This is called on your principal
class and it lets you know
that the user tapped on a
bubble in the transcript
and selected a message.
Then finally as the transition
to expanded presentation
style completes you'll get the
didTransition to
presentationStyle.
So, now at the end of
both of these timelines,
your app is presenting the UI in
the expanded presentation style
and you'll want to get that
message that was tapped,
so this is done using the
MSConversation's selectedMessage
property and you can get this
from the current
active conversation
on your principal class.
You're going to want to show
the selected message in your UI
and allow the user to
compose a response.
Now I'd like you to hand
you back over to Stephen
for one final demo
showing you how
to implement reply
in our sample app.
[ Applause ]
>> OK, so we left off
with a staged message
we're sending here,
which I'll go ahead and send.
And now if I go back to the
conversation list and go
to the other end of
that conversation I have
that received message.
When I tap that message,
my iMessage app is
correctly launched; however,
my ice cream building experience
doesn't show the next step
in the ice cream
building process.
I'm not ready to select ice
cream scoops yet and this is
because every time
that I currently present
this view controller,
I'm always passing in a
new ice cream model object.
I'm always passing in a
new ice cream model object.
What I need to do is look
at the selected message
on the conversation and use
an ice cream model object
from that selected
message if it exists.
So, I'll go back up here
to where I'm instantiating
that ice cream builder
controller and get a reference
to my active conversation
.Then I will use a failable
initializer here that looks at
the message on the conversation
and if that initializer
fails then I know
that I don't have anything in
progress and I'll just create
that new ice cream model, but
if it does exist then I can pass
in the in progress ice cream.
The other thing I want
to do is make sure
that I am passing the
correct caption text depending
on the ice cream part
that has been selected.
To do so, I'm going to need
to pass a new parameter
into this method, which is
the selectedIceCreamPart.
Now, this message caption here
I'll change to a declaration
Now, this message caption here
I'll change to a declaration
of the string type and
then I'm going to switch
on the selectedIceCreamPart
to choose a correct
message caption.
Oh, and I also need to update
the call site to my method here
to pass in that new parameter.
Now when I launch my iMessage
app, tap the Plus (+) button,
send that first message and then
go back to the conversation list
and to the other end
of the conversation
and now I'll tap the received
message and you'll see
that my ice cream builder view
controller is correctly set
up to pick an ice cream scoop.
Now I can select some
mint chip, send it,
Now I can select some
mint chip, send it,
go back to the other end
of the conversation once
more, and select a topping.
So, now you can see
what it looks
like to send interactive
messages back and forth
and accomplish a
task collaboratively.
However, you'll see that
in my conversation UI,
my partially built ice
creams are starting
to pollute my conversation
a little bit.
I don't really need to see the
partially built ice creams,
I only really care about
the completed ice cream.
What I'd like to do is
collapse those previous messages
and maybe leave behind
a succinct summary
of those messages.
To do so, I'm going to make use
of a new object called MSSession
to group messages together.
Here when I'm composing
my message,
I'm going to move my reference
to my active conversation
a little bit so that
when I declare my session
object I can look to see
if I have a session already on
the selected message and use
if I have a session already on
the selected message and use
that if it exists so that it
will continue the same grouping.
Otherwise, I'll create
a new MSSession object.
I'll then pass that session here
into my initializer
for MSMessage.
Now, the other thing I want to
do is provide a nice summary
of messages when
they're collapsed.
Here I'm going to
declare a method
or declare a variable
called summary Text
and here I'll choose the right
summaryText depending upon the
ice cream part that was chosen.
Now I could take that
summaryText variable and set it
on my MSMessage object.
And that's it.
Oh, maybe I should
actually assign it.
There we go.
Now when I launch my iMessage
app and go about the process
of building an ice cream--
doesn't ice cream
sound good right now?
I can pick my flavor of
ice cream and you'll see
that that summary text has
already been collapsed and shown
for me there when
I send my message.
Now if I go-- sorry-- I'm going
to go back to the first part
of the conversation, tap
this message once more.
I think chocolate sounds like
a good topping right now.
Now when I send that I have a
completed ice cream message,
but I'm only showing the one--
the one image here and I have a
nice summary text throughout my
transcript there.
Also, when I go into
my Ice Cream app here,
you'll see my newly completed
ice cream sticker ready for me
you'll see my newly completed
ice cream sticker ready for me
to use however I'd like.
And that's it.
We have a completed
demo application.
Now, this was an example of how
to build an interactive
sticker-building application,
but you could take
this to do anything.
You can build-- you
can integrate
with wonderful services
and build nice awesome
collaborative games
and I can't wait to
see what you build.
Now, back to Alex.
[ Applause ]
Thanks, Stephen.
That was another awesome demo
and Stephen implemented
the reply
and also introduced
something new, the MSSession.
So, let's dive into
the MSSession.
What we saw in the demo was a
messy transcript containing lots
of half-completed ice creams
and we saw how to use MSSession
to take that and turn it into
something that looks a bit more
like this, which is a lot
neater and less cluttered.
It's great.
So, to implement this, we
used an MSSession object.
We created an MSSession and
then for our first message
We created an MSSession and
then for our first message
that was part of the session,
we passed that session
into its initializer and we
have this session message.
We can set some summary text
and then we send it using the
conversation's insert message,
as we've seen before.
When we're replying to a
session message, we don't want
to create a new session; we
need to reuse an existing one
and we can get the
existing session
from the current conversation
so the activeConversation
selectedMessage.
The selected message will
have a second session property
if it's a session message.
Then we take that session, we
pass it into the sessions--
the messages initializer,
as we saw before.
We see here the summaryText
is providing text
for the message summary in
the conversation transcript.
You can now also omit this
property or set it to nil
You can now also omit this
property or set it to nil
and if you do that then there
will not be a summaryText entry
in the transcript, but your
message will still partake
in the session behavior.
So, now we've covered the basics
of the API and we've seen how
to build a very simple
iMessage app
that sends interactive
messages between your friends.
We're going to move
on and talk about some
of the more advanced
features of the API.
We'll start by looking at
some more override methods
on your principal class.
We'll move on and talk
about group conversations
and finally we'll discuss
how to identify the sender
of a particular message.
First, when the user
sends a message,
we realize that your app may wan
to know that this has happened.
For instance, if you're a game
and the user plays a move,
we need to know when to update
our model to record that move
and that should really
only happen
when the message
is actually sent.
when the message
is actually sent.
So, we have a
didStartSendingMessage method
on the principal class
and this is called
when the user taps
the send button.
Now, this is important.
That message-- that
does not mean
that the message has actually
been sent or delivered.
All it means is the user
has hit the Send button
and it communicates the
intent to send this message.
We also have, similarly,
a didCancelSending.
This happens when the
user taps the cross
in the top right hand corner of
the message bubble on the shelf.
didCancelSending is your
opportunity to clean
up any resources that have
been accumulated during the
composition of that message.
And lastly we have
didRecieveMessage.
didRecieveMessage happens-- is
called when your app is running
or active and a message has come
in from one of the recipient--
or active and a message has come
in from one of the recipient--
one of the participants
in the conversation.
And it's a-- this is useful,
for example, if your app has--
if your user is editing
a session message
and another message comes
in on the same session,
it's an updated state and
you need to update the UI
that represents this state.
So, let's move on and talk
about group conversations.
iMessage apps are going to be
used in group conversations,
so you're going to
have to consider
that when you're building them.
We have here an example
conversation
between three friends:
Amber, Ben, and Chris.
Ben's getting ice cream
for everyone and he sent
out a question to
Amber and Chris.
Which topping do you-- would
you like on your ice cream?
Chocolate sauce or sprinkles?
Amber is going to reply
with chocolate sauce
and Chris here is going
to reply with sprinkles.
Both users send these messages
at exactly the same time.
Both users send these messages
at exactly the same time.
Let's focus a little bit now
on Ben and see what happens
on his device as
these messages arrive.
First, Amber's reply is going
to arrive on Ben's device
and this is followed
very shortly afterwards
by the reply from Chris.
So, you note Amber's reply was
turned into a summary message
and Chris's reply is shown
as the last bubble
in this conversation.
This could just as easily have
happened the other way around
and we should note that only
the tapped message is available
to your iMessage app, so
we don't really have access
to Amber's reply in our example.
How do we deal with this?
Well, right now we're
recommending
that you store state in
the cloud and this means
that the URL property of the
MSMessage that's passed to
and from the participants in
the conversation only needs to--
and from the participants in
the conversation only needs to--
only needs to take a token
that represents the session
and then you receive the
current state of the session
when the user taps on a message.
And when a user sends a message,
you should push the
current state
of the session up to the cloud.
Moving on, we're going to
talk about sender identifiers.
Here we have a conversation
between Amber, Ben,
and Chris again.
In this scenario,
Amber has replied
with a preference
for chocolate sauce.
Chris has not yet replied.
Focusing again on Ben's
device, we have a message here
and we don't know who to
attribute it to, but we can find
out some information about that.
Now, what we have here are some
sender participant identifiers--
sorry, let me rephrase that.
What we have here are some
participant identifiers.
Apple is very, very
concerned about user privacy
and we really very highly value
the privacy of our customers,
so we don't expose
contact information
at all to iMessage apps.
Instead, we provide these
participant identifiers.
On Ben's device, he has a
local participant identifier
and this is a UUID that
represents Ben on this device.
He also has two remote
participant identifiers.
These represent the
other participants
in the conversation.
In this case, we have two.
We have Amber and we have Chris.
Looking at the incoming message,
we see that the message
has a sender identifier
and this will map to one
of the local participant
identifiers in Ben's list.
Moving back to the big
picture, looking at Amber
and Chris's device, the sending
messages have sender identifiers
and Chris's device, the sending
messages have sender identifiers
and these map to the local
identifier on each device
that sent that message.
You can use these identifiers
to get a handle on the number
of participants in
a conversation.
You can attribute
messages to a sender
so once you've received
one message
with a particular
sender identifier
and you receive a second
with the same identifier,
you know they've come
from the same user.
They can also be used in
conjunction with a web service.
They can be used to
help establish identity.
And one more thing.
You can use these identifiers
or the string representation
of these identifiers prefixed
with a dollar sign in any
of the text passed
to the MessageTemplateLayout's
text properties.
You can also use-- similarly,
you can use these identifiers
You can also use-- similarly,
you can use these identifiers
in the text passed to the
Messages sumamaryText.
When Messages displays the UI
for the bubbles with this type
of formatting in their text,
it will replace the identifiers
with the contact
name of the person
that their identifier maps to.
These identifiers are
unique on each device.
If you noticed on the
earlier slide, every device
for every person the
identifier was different.
And they're scoped to the
install of the iMessage app
and what I mean by this is
that the identifiers themselves
will be stable over time,
but if the user removes
your iMessage app
and then later reinstalls it,
you'll get a completely
different set of identifiers
within the same conversation.
You can get the sender
participant identifier
You can get the sender
participant identifier
from an MSMessage using the
senderParticipantIdentifier
property and you can get the
local participant identifier via
conversation using the
localParticipantIdentifier
property.
And you can get the list of
remote participant identifiers
from the
remoteParticipantIdentifier
property.
So, that wraps our more
advanced topics on the API.
We're going to talk a little bit
more about supported platforms.
Interactive messages will be
delivered on these platforms:
watchOS 3, macOS
Sierra, and iOS 10.
Of these platforms, only iOS 10
will actually generate messages.
On macOS Sierra, the user
can click on a bubble
in the conversation
transcript and the URL passed
in the conversation
transcript and the URL passed
to the Messages URL property
will be opened with Safari.
That will only be if it's
an https or http URL.
On watch, you can hand off
interactive messages to a device
where you're able
to compose a reply.
We also support some
fallback for older platforms.
These messages will be
delivered to watchOS 2, iOS 10--
iOS 9, and OS 10.11,
but they'll be delivered
in a fallback format.
There's two separate messages.
The first one will be
the image as provided
in the template layout.
The second one will be a URL
as provided in the message.
Now, again note if this is
an https URL, we'll send it.
If it's a data URL, we won't.
So, we only-- we'll only
send the https or http URLs
So, we only-- we'll only
send the https or http URLs
in the fallback message.
So, that wraps up our talk.
In summary, we have-- this week,
we've introduced the Messages
framework, iMessage apps.
In the first part of this talk,
Bhaskar and Lily introduced us
to sticker packs
and showed us how
to create simple iMessage apps
that create sticker content.
Today, we've created
iMessage apps
that send interactive
content and we've talked
about how they work
in group conversations
and a few other things.
Now I'm really excited to
see what you guys go out
and make with this API.
I can't wait to see what you
produce and that-- that's it.
[ Applause ]
For more information, you can
check out our session's website
on developer.apple.com.
We have a related session.
If you haven't already seen
"iMessage Apps and Stickers,
Part 1", then please go
and watch it on the web.
And that wraps up our talk.
Thanks to Stephen
for doing our demos.
Thanks to you guys for coming.
[ Applause ]