[ Applause ]
Good evening, everyone.
My name is Eugene.
I'm an engineer on the Messages team and I am super excited to be here tonight to speak with you about what's new in iMessage apps.
Let's dive in here.
We've got a couple of things on the agenda this evening.
First one, we want to show off a little bit of what's new in the iMessage app area in iOS 11.
Some of the stuff you saw in the keynote plus a little bit more.
After that, we're going to be introducing our awesome new Direct Send API.
After that, my colleagues Jay and Stephen will be coming on stage to talk to you about our new Live Message Layouts.
And finally, we'll be wrapping up the talk with a couple best practices tips and tricks for your iMessage apps.
So a lot of what we're talking about this year builds off the fundamentals that we established last year with iOS 10 and the introduction of the Messages framework.
So if you need a refresher about the Messages framework or iMessage apps in general, we highly recommend watching our previous year session iMessage Apps and Stickers Part 2, which is available on the developer portal.
So give that a look if you'd like a refresher.
So let's get into the cool stuff.
What's new in the Messages app area.
So as you all saw on Monday, we've updated a little bit of the Messages app UI for iOS 11.
So I just saw on Monday when a user enters the conversation now we put all the app icons right there at the bottom of the screen which makes it really easy for users to launch applications right when entering a conversation.
As with iOS 10, your application still lives in kind of the keyboard area but we still have the application icons down at the bottom.
Now users can scroll this application list left and right to quickly find the application they want to launch.
We've also divided the strip into two different sections, as you can see up here.
The left-hand side we have the users favorite section which is ordered by the user, and on the right-hand side we have the most recently used applications.
So users can also rearrange their applications out of the recent section and into their favorites for easy use and for accessibility right when they enter the conversation.
So we think this is a great way for users to enter a conversation, tap the app they want and be able to use your application immediately.
One really cool change their making this year revolves around how we handle app installations.
So now in iOS 11 if you download an application from the iMessage app store or you download from our primary app store we will enable your application by default and the Messages app drawer.
In addition [ Applause ]
So in addition, we will order your applications icon to the very first item in the most recently used apps so users can find it easily and launch the application immediately.
So there's just a couple changes that we have for the Messages app UI.
A lot of it you guys have today.
Next up we have our brand new Direct Send API.
We're super excited to share this with all of you.
So in iOS 10, the only way to share content out of your Messages app would be to call an insert API which puts your message into the Messages entry view.
And so while this works great for many applications, for some user experiences like this game when the users say makes the game move next logical step would probably be the message actually being sent and inserting that message into the entry view kind of adds an extra tap.
So we thought this year how can we make this easier, how can we make this a better user experience?
So in iOS 11 you can send any content that you would have normally inserted into the Messages entry view directly from your application.
So how does this work?
In iOS 10 we introduced MS conversation which defined the following insert APIs.
Insert message ,insert sticker, insertText, and insertAttachment which supports any of our standard Messages attachment types.
In iOS 11 we have a very simple analogist API called Send Message, Send Sticker, Send Text, and Send Attachment.
So calling into anyone of these will bypass the Messages entry view and insert send you a message immediately in the conversation.
So really quick and easy API.
[ Applause ]
So you may ask which API which user experience is best for my application, both Insert Draft and Send Message APIs are first party citizens in iOS 11, and it's up to you to decide which one is best for your application.
So the Insert Draft API is still the recommended API for most applications as it allows for richer composition experience.
For example, user can insert a message and then say append a comment to the end of the message, or send with a screen effect or a full screen moment.
So it's a really great way to enrich the content that you would already be sending.
In addition, it gives the user an opportunity to verify the content that will be sent which is extremely important.
On the other hand, Direct Send API offers a superfast quick and easy user experience that's great for, say, games and stuff like we saw above.
So it's great for any application where the insert flow has tapping the entry view button feel like an extra step that you really don't need.
However, when using this API it is extremely important to maintain user trust in your application.
So it's important to very clearly indicate to the user exactly what content is going to be sent and also to clearly denote to the user exactly what user interaction or interface element within your application will trigger send.
So to help promote a great user experience with a direct send API Messages enforces a couple requirements on this APIs use.
Firstly, your application must be the visible Messages app on screen.
As you may know, your Messages app extension may be running in the background within Messages and not actually be the current foreground application.
So first requirement is your application must be visible.
In addition, our target user experience for this is to have the user tap the screen or interact with your application and then to have a send be triggered.
So to facilitate this, Messages will detect user interaction on your app and allow for a direct send API call to be made upon detection of that user interaction.
Subsequent direct send calls will fail until we detect another user interaction, so kind of keeping with one-to-one the user press something on your screen and a send is allowed.
So to help you as developers understand what's happening with the send API, we are introducing two new air codes, MSMessage air codes.
We have sendwithoutRecentInteraction and sendwhileNotVisible.
So as always, use great air handling so your application can catch these dates.
And that's Direct Send.
It's very simple.
I think it's going to be a great user experience for the apps where it makes sense for.
Definitely consider whether Insert Draft or Send makes the most sense for your application, and we're very excited to see what you-guys can build with it.
So next I'd like to invite Stephen up stage to introduce you to Live Message Layouts.
[ Applause ]
So today I'm excited to return to the stage to you to talk to you about Live Message Layouts.
Now in iOS 10 we introduced Messages framework and the ability for you to bring your app experience right into Messages.
When you would build your iMessage app, your app could be shown here in the keyboard area in Messages or in a full screen presentation, and these would be the compact and expanded presentation styles that you could use.
And then when you would send the message your app would use a template driven or we would use a template driven layout approach for your app message.
Now this template layout had customization objects or options such as image and the text properties here, and it allowed you to provide some pretty good rich app messages, however, it's still limited by what the template provides.
In iOS 11, I'm excited to announce that you can now completely customize what your app messages look like using these liveLayouts.
So this is actually a view provided by the application itself here in the Messages transcript.
The app could also drive a view as a draft message, and in fact can provide custom views to represent many messages simultaneously in the transcript.
Of course we support the world where maybe your app isn't the only one on screen, but really we only care about your app.
We're here to talk to you about that today.
So I'd like to give you a quick demo of what that looks like in action.
So here I have a simple iMessage app that I've built called Event Countdown, and this is just a simple list of upcoming events that I'm excited about and want to share with my friends via Messages.
So for example, if I tap the batch here you'll see a completely custom message is presented here as a draft message.
It's live updating, it has this great countdown that's building anticipation for the upcoming event.
And when I send it, that same view is put in the transcript that would be seen on the other side.
In fact, if we go into the recipient side or to see what a recipient might have sent or the other side might have sent, here I have an invitation from Eugene.
This is a similar app message, but my iMessage app has chosen to render a completely different view on the receiver side.
I'm representing an unaccepted invitation at this point.
If I tap this app message bubble here, I mark the event as accepted and now it switches to that live countdown mode.
I was able to do all that without even having to launch my iMessage app in this context.
Now here in the top right I have a little infoButton.
Not all experiences are appropriate to try to shove into an app message.
By tapping this infoButton, I can actually request that my app be presented in a different presentation style to see more information about my event.
So I hope you can see that here with Live Message Layouts you can build a really rich user experience, complete with interactions and live updating content, and it's really easy to do.
So let's talk about how this works.
So here when the iMessage app is being shown in the compact presentation style, we have instantiated an instance of the MSMessages app view controller subclass and configured it in the compact presentation style.
When an app message with a liveLayout is shown on screen, we'll instantiate another instance of that same base class and configure it with a transcript presentation style.
In fact, for each message displayed in the transcript we will instantiate a new instance of this class configured again in that transcript presentation style.
There is a strict one-to-one relationship between these instances and an app message that they represent on screen.
So that's a quick overview of Live Message Layouts.
Now to walk you through more of the API and how to get started, I'd like to invite Jay on stage.
[ Applause ]
Well thanks, Stephen, for the introduction.
My name is Jay and I'm here to introduce to you some of the new APIs we've added for Live Message Layout.
So let's get started.
As some of you may be familiar, you were able to customize your app bubble using MSMessageLayout.
With existing MSMessage template layout you're only able to customize a limited set of appearances such as captions and images.
In iOS 11, to support a fully customizable bubble we're adding a new subclass MSMessageLiveLayout.
So let's take look at this real quick.
As you can see, there aren't that many things to fill out as you have to do for the template layout.
Well that's because now you have the opportunity to fully express how these app bubbles should look like.
Though you may have noticed that there is one property called Alternate Layout and so what is this?
Now there will be a few instances where your app bubble won't be supported by the receiving devices.
In cases such as they don't have your extension installed or they're just running on older Apple iOS versions, iOS, macOS, or watchOS.
So in these scenarios, they'll be seeing this template layout as a fallback representation by if they can actually support their extension then they'll be seeing the bubble on the right.
So how do we use this API?
It's very similar to how you did in iOS 10.
First, create the template layout.
And with a template layout you're going to create liveLayout.
And with a liveLayout say it's a message and send.
So really similar to what we did in iOS 10.
So that was it for the MSMessageLiveLayout.
We have some new additions in MSMessagesAppViewController.
Now as some of you may be familiar, this was the principle class through extension point.
So by configuring this view controller you're able to customize the appearance in your app in the keyboard area, in the compact mode.
So the bubbles in the transcript are also backed by View Controller, and in fact they have the same class.
Okay. So what does this mean?
That means that this view right here in the bottom and that view on the top are coming from the same class.
So to distinguish these two cases we've added a new presentation style transcript.
So when it comes time to configuring these view controllers, you can use a combination of presentationStyle and selectedMessage to determine what you want to show in your view controller.
And one really simple pattern you can follow is something along the line of path factory pattern where you can return appropriate child view controller depending on the state of these properties.
So you're going to have one for transcript and one for compact.
So if you're already following a similar pattern and code it will look something like this.
So for the compact case we have a helper method presentSummaryViewController and this helper method you will create the right child view controller and configure a view controller appropriately.
For the case of expanded, you'll have another helper method presentDetailViewController and will do something very similar to what you did for the compact case.
So to handle another case for the transcript, we can just have another helper method something along the line of presentTranscriptViewController.
So that was it for the presentation style, but we actually have one more thing to go over before you get this live bubble started.
And that is sizing.
Now, the view controllers are intended to use for transcript will conform to the new protocol called MSMessagesAppTranscript Presentation.
It has one method called ContentSizeThatFits.
In this function, return a size that best represents your view in the transcript.
So to illustrate, here's an example.
Now, we want our size to always fit all the sub views nicely without getting clipped or any extras base or anything like that.
For this particular example, we have the map view timer and the button.
And we decided that we'd only care about the size of the map view or the timer changing, but we want the button to adjust accordingly based on the system font.
So let's give it a static number, 217, for the map view and the timer, and then the line hide right here will be the size of the button that takes the system font into consideration.
So by adding these two numbers we'll get the right size or the right height that encompasses all the sub views in our view.
So with this configuration, I think the height is about 235 points.
Now keep in mind that this function will be called again when there is a change in transcript size, change in locale or change in system font.
In these events, these functions will be called again for a new size.
So here's an example of change in system font.
As you can see, the fonts are slightly bigger.
In this case, we just said that we didn't care about the map view or the timer growing or shrinking so let's look at the same 217.
But because we're using a dynamic font for the button, it automatically picked up a size.
And with this configuration, you can appropriately return 244.
We'll take this value and resize your view accordingly.
So that was a lot of talking.
To summarize everything I just talked about I'd like to show a quick code demo.
And I know a lot of you-guys are very eager to be at the bash so we'll work on a sample app that shows you a countdown timer to the bash.
So we have our nice X Code here and this is the device I have on the table right now.
So in this demo I'd like to show how you can extend an existing iMessage app and start using our LiveMessageLayout.
So if you remain on iMessage app it will look something like this.
So you have an app in the compact mode and when you're trying to send it will show a template layout.
So how about we start using LiveLayout instead templateLayout as showing on the shelf?
So let's get to the code.
And here I'm in MSMessagesAppViewController sub class.
And somewhere in this code were probably creating a template layout.
So let's look for that.
Found it. So we have this helper function called sendMessage and it seems like we are creating the message, configuring it, create a templateLayout and then set that layout to the message and we're inserting it into the conversation.
So I think this is a great place to start using our liveLayout objects.
So here I'm going to go ahead and create a liveLayout.
There's the template layout.
And then we can set that as Messages layout property.
And let's see okay.
So with this change you should be seeing a liveLayout.
And this is definitely a liveLayout, but this doesn't look right.
This actually looks exactly like what you just saw in the compact mode.
So what went wrong?
Let's get back to the code and let's try to find out where we're actually creating this table view controller that you see in the compact mode.
And a good place to check that right now, I'm going to go into willBecomeActive, okay, I see updatePresentation.
See what this does.
Oh and I see presentViewController.
Now this seems like a problem right here.
For anything that is not expanded we're always creating a table view controller and, as mentioned before, the same view controller class is used for both transcript, compact and expanded so we need to handle case for transcript which is not supporting this code right now.
I'm going to leave this code as it is now.
I'm going to create a new function so they can start handling this case.
So I have this presentTranscriptView and I have this [inaudible], I have to know if it's for me or if it's pending because I want to decide if I need to show the invitation button or not.
So now that I have this transcriptView I can go ahead and add it to a sub view with the Auto Layout Magic.
Then I have to call this method somewhere so I'm going to go back to updatePresentation.
It's right here.
And here I can start configuring this viewController for transcript.
TranscriptView, event, conversation, and for everything else I'm just going to do what we've always been doing for compact and expanded.
Cool. So let's see how this change will look like.
So with this change you should always see the event detail in app bubble.
So it's succeeded.
So I'm going back to our device.
Right. Shut up.
Cool. So I see something now, but it is kind of big and I don't know where the map view went but we're getting there.
As you can see there's like an awkward wide blue space.
It is definitely bigger than I expected.
So what went wrong is seems like we didn't implement content size that fits the last part of this liveLayout adoption.
So I'm going to go ahead and implement that real quick.
And then from the demo, from the slides, you wanted to height to be about 217, and then for the title button you want it to by dynamic and it was fetched from transcriptView.titleFont and then lineHeight.
We want our width to be the maximum width possible which is the path and size parameter so we can just return the exact value.
And then for the height, we can add these two values.
And this would be a good size to return two messages.
So let's see how that looks like.
So it's loaded.
This is what we saw in the demo.
Nice little size with the events and the timer ticking.
We only have like an hour and twenty minutes until bash, so hang in there.
So I'm going to send this.
There we go.
It's in a transcript live and the timer's ticking.
So this was a quick demo to how to adopt Live Message Layout.
So let's talk more about some of the interactions in viewControlLifecycle.
I would actually like to bring Stephen back on stage to talk more about it.
[ Applause ]
Thank you Jay.
So, now we've seen a little bit of an introduction of what it looks like to use the new API, to use Live Message Layouts in your iMessage app.
If you'll think back to the demo I did at the beginning of the session, we had some interactive elements to our iMessage app bubbles.
And so I'd actually like to return to Xcode now to do just that.
So return to my device here.
We're going to go back to Xcode just where we left off.
And I'm going to get my device ready for this demo.
Okay. So the first thing we want to do is here we have this EventCountdownTranscriptView and that's the view that gets imbedded in that app message in the transcript and so we want to configure that with some inner activity.
So I'm going to go ahead and jump into that class and you'll see that I have a number of properties here that are configured, and here in setupSubviews I have a tap adjuster recognizer that's set up so that when the user taps my view this method user to tap gets called.
If I jump to the implementation, of course the implementation right now is empty and it's ready for us to add something.
So the inner activity we'll want to add first is specifically when the app message represents an unaccepted invitation.
So if the event is not for me or if the app message is not for me and it's not been accepted then we want to have that interactive element to it.
So the first thing we'll do is say if is not accepted and it's not from me then we'll change our view flag to have is accepted equals true.
And the other thing I want to do is update the model that I have here.
Normally I would use correct MVC and also update maybe my service to indicate that the event has been updated, but for the purposes of this demo I'm just going to mark this in the defaults.
Great. So I've updated some state now I need to update my view state, so I'll just use a quick animation block here to call into my updated view state and then I'll trigger a layout pass.
Now this updateViewState, it just looks at the different flags and properties on my view and configures the view correctly.
So wait for our demo device to come back up and I'll show you what that looks like in practice.
Great. So here we have our unaccepted invitation being shown in our demo and it's ready for us to test out that interaction that we just added.
So if you see that when I tap that message that state gets updated and we see that live countdown, and you can tell that I have very little time left so I better keep going.
Now the one thing that we're missing here is that nice infoButton on the top right that really gave me that rich detail about the event that I don't want to necessarily put here in my app message.
So if I go back to the code here you'll see that this infoButton is just waiting to be implemented.
But before we do that, we need to add the infoButton to the view hierarchy.
So here in setupSubViews you can see that I have this infoButton that's already been configured, including with that target action I just need to add it as a sub view.
I also want to add some constraints like it's laid out properly.
And then we'll go and jump into the implementation for infoButtonTapped and call into our delegate.
Now the delegate of this view is our app view controller, and the app view controller is the object that knows how to change presentation styles, so I need to call out to it.
You'll see that this method hasn't been implemented yet in my delegate.
So we're going to jump over to that delegate really quick.
Here is a delegate protocol declaration where we see that method hasn't been defined.
So go ahead and add it.
And then we'll jump over to where this protocol is implemented and add our new method that we just added.
Now all we need to do is request that new presentation style and that's it.
When I do that, the app view controller requests that new presentation style and Messages will instantiate the new view controller in that expanded presentation.
So this is the same thing that was just implemented here in the code.
We have the infoButton in the top right, and when you tap it we get that nice expanded presentation with the additional content.
So that's it.
We have a completed demo that's showing you thank you.
[ Applause ]
So with the completed demo you see that we can add completely custom layouts that really add some richness to that experience in the transcript, including inner activity and live updating content.
So when we think about interaction with these live message layouts, we really want to keep it simple.
Stick to simple button taps and tap gestures, and let me use the scroll views.
This app message is being imbedded in a fairly complicated UI, the Messages transcript, and the user's used to interactions like vertically scrolling the transcript, horizontally scrolling the transcript, and other gestures that take place.
And so if you add too many complicated things here it can be disorienting to the user.
The other thing to remember is that there's no keyboard input allowed for these app message views, and so if you want keyboard input you should request an expanded presentation style where your app can use the keyboard.
Now these views are really light weight for a reason.
When you think about their lifecycle, they're only instantiated when the user comes into the conversation to look at it.
As soon as the user leaves the conversation or leaves the app, your iMessage app will be torn down.
So it's not an appropriate place to put something like a 3D game engine.
If you do want to do that, you should request that expanded presentation style for the user to take part in your extended interaction.
Now I want to cover this again because I think this is important.
When requesting the expanded presentation style, your transcript app view controller is not reconfigured with new presentation style it's left in place in the transcript.
If no view controller exist in the compact or expanded presentation style, Messages will instantiate a new object, configure it accordingly, and then add it and show it here.
If one does exist then it will reconfigure it to the new presentation style.
And this is specifically if it already has one that is compact or expanded.
It will then change the selected message on that view controller and you will get the didn't select message callback on that view controller.
Now the transcript app view controller that's left in place as is or the static selected message because it always represents that message in the transcript.
Now when we talk about lifecycle a little more of your iMessage app, in iOS 10 these methods on MSMessagesAppViewController applied specifically to your extension lifecycle because there was only one instance of the view controller created and it was closely coupled with the lifecycle of your iMessage app, so you could rely on it for extension lifecycle notification.
However, in iOS 11, we can instantiate many instances of your principle class.
So these methods really pertain more to the view controller lifecycle and you need to think of it from that perspective.
If you do need to pay attention to extension lifecycle events of your iMessage app, you should observe the NS extension related notifications.
Now in a particular instance of your transcript app view controller is created, the lifecycle methods proceed like this.
First, we'll initialize the view controller and call viewDidLoad.
Then we'll call willBecomeActive and didBecomeActive with conversation as part of the Messages API contract.
Then the view appearance methods will be called as your view controller is inserted into the view hierarchy for display.
Lastly, contentSizeThatFits will be called.
Now when willBecomeActive and didBecomeActive with conversation are called, you have all the information you need to correctly configure your view controller by looking at that presentation style and selected message on the view controller.
Now when thinking about contentSizeThatFits getting called last, this is because it may be called multiple times.
Think about the Messages application on an iPad in split view mode.
As the user changes the size of the Messages app, the metrics of the Messages application, and therefore the transcript, change.
We'll then call into your contentSizeThatFits method with an updated size or maximum size, and you should update your app size accordingly.
It can also be, of course, updated for dynamic text size changes and locale changes.
The last thing I want to cover is pending messages.
Now remember, your view controller can be configured to represent app messages in a transcript presentation style both for an unsent message and the message that has been sent in the transcript.
Now most of the time you should keep the same application view in both states because the user is really previewing the content that's going to be sent here.
But if you do need to differentiate between the two, you can check the isPending flag which is a new property on MSMessage that will let you know the difference between these two states.
So that's all we have for you today to introduce Live Message Layouts.
Remember, this is interactive iMessage apps in the transcript, which I think is incredibly cool and I can't wait to see what you build with it.
We're using the same MSMessage app view controller sub class, and the new layout, the MSMessagesLiveLayout with a new presentation style for you to use as a tool to build these rich new experiences.
I'm really looking forward to what you build with this and I think you're going to come up with things that we haven't even thought of yet.
And with that, I'd like to bring up Eugene to introduce some best practices when using the Messages framework.
[ Applause ]
Thank you, Stephen.
Live Message Layouts, super exciting.
So we want to wrap up our talk today with just a couple best practices tips and tricks for your iMessage apps just to give your apps that little extra shine and polish that we think will make them look really great.
So, we have a couple of tips for you guys today.
Let's get into it.
So the first thing we'd like to talk about is the iMessage app area insets.
So this is the area at the bottom of the screen underneath the app strip as well as at the bottom of the screen in expanded mode.
So similar to like navigation controllers, Messages UI can include the area displayed by your application so you can have that nice blurred effect when scrolling scroll views.
So to determine your app area insets, you can look at the UIViewController top and bottom layout guides, or new in iOS 11 check out UIViewsafeAreaInsets.
These will define all the areas of your application's view that are un occluded by Messages UI.
Of course, you can always use Autolayout to add constraints to the UIViewController's top and bottom layout guides.
So for applications linked on iOS 10, we will continue to use old legacy insets.
But a great way to keep up with the change in UI Messages and have your application adapt appropriately is to properly adopt either the UIViewsafeAreaInsets or UIViewController top and bottom layout guides.
Next up we have message summary text.
So iOS 10 introduced MSMessage and a property on it called summaryText.
In iOS 10, summaryText was used for Messages with an MS Session attached to it, so kind of session based messaging and we'd insert a very small succinct summary inline the transcript of that message.
In iOS 11, we are expanding the use of the summaryText property to all MSMessages sent.
So where do you see the summaryText?
MSMessage summaryText will now be used in the conversation list preview as well as places like notification center so you can give context to your application's message notifications.
So this is a really great way for users at a quick glance to see the content that you send in your app message.
So iOS 11 summaryText and every single one here, MSMessages.
Next up we have stickers.
So the introduction of sticker packs in iOS 10 we're seeing tons of them released.
I absolutely love them, download new ones every week.
Keep up the awesome work on the sticker packs.
We love it.
We do want to give a couple tips about making your sticker packs faster and send quicker.
Overall, sticker pack performance is a function of your sticker's file size.
This function of the sticker's file size is a function of your sticker's pixel size as well as its frame rate.
A really great resource for you to look at is the Messages Human Interface Guidelines which is available in the developer portal which will tell you the target sticker sizes for either the small, medium or large stickers that we support.
In addition, consider the frame rate of your sticker.
Stickers with higher frame rates or longer loop times have a higher memory overhead and will negatively impact the performance of your sticker application as well as negatively impact send times.
So for quick fast sending stickers and quick launching sticker apps, make sure your stickers are sized correctly and either use short loops or lower frame rates.
So looking forward to seeing all the new sticker packs you guys make in iOS 11 as well.
And last up on our list is MFMessageComposeViewController.
MSMessageComposeViewController is the Messages share sheet that can be invoked from your parent application.
So in iOS 10 we introduced a new property on the share sheet called Message, which predictably takes an MSMessage instance.
So if you already have an iMessage app, your parent companion app can actually send the same application balloons either a template layout or a live Layout that you can send in the Messages app itself.
So you get a very nice consistent sharing experience between your parent application and your iMessage app.
App balloons that are received, can either then be opened within your iMessage app or can bounce the user out to their parent application via the open URL command.
So definitely take a look at Message property on MFMessageComposeViewController.
And with that we've wrapped up our tips!
Just a couple things for everyone to keep in mind.
Look at your layout margins.
Set summaryText on all MSMessages in iOS 11.
Consider sticker sizes and frame rate for faster sticker packs.
And also keep on making awesome stickers.
And finally, you can now send app balloons from MFMessageComposeViewController.
So certainly check that out for consistent user experience.
So what did we learn today?
We went over a couple new things with MSMessages app UI.
We saw the direct send API for an awesome new setting experience in your iMessage apps.
Stephen and Jay led you through Live Message Layouts.
I cannot wait to see what all of you build with that.
And finally, a couple best practices tips and tricks.
If you'd like more information check out our session webpage right here.
In addition, we also have a couple related sessions happening tomorrow.
We have, at 10:00 a.m. in this hall, Introducing Business Chat, which I know all of you are probably really excited to hear about.
In addition, we are very lucky this year to have one of our Messages HI designers who will be doing a design short tomorrow at 11:00 a.m. in the Executive Ballroom.
Thank you for being here tonight and enjoy the bash!
[ Applause ]