Today we are incredibly excited to introduce a brand new Airbnb iMessage app for iOS 10! We believe it will greatly enhance the way you plan your trip with friends and family.
Planning a trip pre-iOS 10
If you plan a trip today using our mobile app and iMessage, your experience will most likely look like this. You find a beautiful place to stay:
You share it via SMS:
And when you do, you end up with something like this:
As you can see, we’ve completely lost the appeal of the original home after sharing it, since it’s now just plain text. The transition from Airbnb to iMessage is lacking visual richness, in a time where an appealing presentation of data is of great value. Even though we have no control over how the listing is presented in the conversation thread, it directly affects how guests perceive our app, and the Airbnb experience as a whole.
The experience with iOS 10
We started out looking to define the grand vision of planning your Airbnb trip within Messages — what would that look like on this new platform? Over the course of just a few weeks before the iOS 10 release, our team rapidly prototyped on a variety of ideas. We started with countless drawings and mockups of possible features, and as we became more familiar with the possibilities and limitations of the Messages Framework, a product began to form. Once we had something we could use, a group iMessage thread between engineers, designers, and product managers allowed us to quickly discover the features we wanted — a rather meta approach. At this point, we had an iMessage app where people could share homes between friends and view key details about the accommodation.
A key decision in this process was determining which listings to present. Conveniently, Airbnb already has two great ways to organize listings: Wish Lists and recently viewed listings. We leveraged existing resources to build these into the iMessage app.
By using a convenient tab-based UI, you can switch between both while remaining in the collapsed app view. When it came to presenting listing information, we knew most guests only needed to see a few key features to help shape their decision of which home to book. The new app presents price, photos, location, host information, and house details, all in a concise user interface, so that collaboration remains the focus.
Speaking of collaboration, an iMessage app wouldn’t be complete without an additional social feature: voting. When sharing a message with friends, each collaborator can vote on homes they like and see who else has voted on them. This gives the trip organizer a bird’s-eye indication of the most popular listing, greatly simplifying the decision of which one to book.
Developing with the Messages Framework
Personalizing the experience
Apple is fully committed to privacy, and so are we. It’s something that everyone wants, but it also raises certain engineering challenges. The main implication as applied to iMessage apps is the inability to acquire any contact information of conversation participants at all. We could only get the participants’ UUIDs, which can then be used as placeholder labels, that iOS replaces with user names inside the conversation thread. However, this is not ideal for us as we would like to know a little bit more information about participants to be able to access their recently viewed listings and Wish Lists, among other things.
It turns out we can solve the problem by requiring everyone to be logged in to the main Airbnb app. By creating a shared App Group, we can use the keychain to share data between the main app and its iMessage counterpart. Once they are logged in, we can fetch all the required information in the extension and use it to personalize the UI, and make network calls.
A small note on testing. When we started using the shared keychain to personalize the experience, we noticed we could no longer use the iOS Simulator to test group conversations. This is because, even though you can impersonate the current participant either as the Simulator default Kate Bell or John Appleseed, they still use the same instance of the keychain and therefore are considered to be the same runtime user. To work around this limitation, we had to always test on device.
Race conditions when sending messages
Human race conditions happen when multiple users interact with the same message at the same time. Consider the following example: Jie shares a listing with Michelle and Noah. They both open the interactive message, vote, and send a reply back. If Michelle’s message arrives last, it will overwrite Noah’s message. Additionally, as all the messages from the same session are collapsed into a single bubble, one has no way of accessing previous replies, resulting in data loss.
Why does this happen? Well, the Messages Framework conveniently lets you attach a URL to an MSMessage instance. This enables us to add URL parameters and share state in a single message session among all participants. If multiple replies are composed in parallel, only one of them will land in the conversation. Hence, every other message will be overwritten and information in them will unfortunately be lost.
From a participant’s perspective, the message can be in 3 states — unopened, opened in edit mode, and staged (i.e. waiting for them to hit “Send”). We don’t have to do anything about the first case, but we can be smart about the other two.
When you interact with the message by tapping on its bubble in the conversation thread, it becomes a selected message in the active conversation. MSMessagesAppViewController requests the transition to the expanded presentation style by invoking the method on its delegate:
func willTransitionToPresentationStyle(presentationStyle: MSMessagesAppPresentationStyle)
At this point, the iMessage app displays an expanded view of the currently selected message. In this state, a new message for the same session may arrive, likely containing updated data in the URL. MSMessagesAppViewController then notifies the app by calling:
func didReceiveMessage(message: MSMessage, conversation: MSConversation)
This updates the current presentation with the new incoming data. This approach solves the problem of overriding valid data by keeping the current message up to date with incoming replies before it is sent.
The third use case arises when the message is staged in the input box and is ready to be sent. While the message is staged, a new message may arrive which will again trigger the didReceiveMessage callback. The recommended approach would be to read the URL of the incoming message, merge its data with the current message’s URL, then re-stage the current message. Re-staging is achieved by simply inserting the message into the current conversation thread a second time; the insert method on MSConversation will replace the old message in the input box.
While the two approaches above will greatly assist in keeping data safe, they don’t mitigate the case when two or more messages are transmitted at the same time. It is extremely hard to prevent data loss here, since they are now outside of the message’s lifecycle.
Using server-side resources to persist data is the most reliable way to maintain data integrity, and is also the suggested approach by Apple. We started out with URLs and eventually transitioned to server-side resources. Message URLs are treated like immutable tokens and so once created, don’t change during the entire session. This makes them inherently great to be used as unique IDs of their counterpart server-side resource, on which we save message state. All clients write data to the same resource, and every time a message is opened, they re-fetch the data and update the UI.
When should data be persisted?
There is a delicate balance to maintain when persisting message state on the server. As previously mentioned, MSConversation allows new messages to be inserted into the input field using the method:
func insert(message: MSMessage, completionHandler: ((Error?) -> Void)? = nil)
It does not, however, send the message. A participant must explicitly send the message to actually commit that action. In our case, they need to do that to send a vote.
Apple doesn’t expect data to be persisted on the server until the message is actually staged and sent. However, this poses the risk of data loss as there’s no guarantee a network request to store data would be successful. After some brainstorming, we decided it would be more reliable to persist state data before the message is staged and sent, making sure that remote data resources are always up to date.
Those not on iOS 10 will unfortunately not be able to enjoy this rich messaging experience. When the iMessage app sends a message, unsupported devices will receive two separate messages — an image and a URL. We still try to provide all participants with the best Airbnb experience possible, by forming URLs in such a way that, when opened in the browser, we know they’re part of an iMessage conversation. For this specific scenario we display listing details as usual, but additionally also allow voting on it!
Consequently, voting data is made available back to the users in the iOS 10 conversation thread. By generating push notifications server-side to notify iOS 10 users that new data is available, we maintain the real-time nature of the conversation flow for everyone.
Before leaving you to try out the app yourself, we’d like to address one more challenge we faced: app discoverability. Hopefully by reading this article, you now are fully aware of the new capabilities we are introducing to the Airbnb app, but not everyone will be! We want to make it extremely easy for everyone to see that this new iMessage app is available. However, there are no APIs to easily deep link from the parent app into the iMessage settings screen to enable the corresponding app extension. One has to first open Messages, tap to open the app drawer, go to the iMessage App Store, select the “Manage” tab, then enable the app.
We attempted to mitigate this lack of discoverability by introducing an educational prompt right after sharing a listing — the most common action in the main app that relates to sending messages. Our hope is that this promotes the iMessage app right when it is needed the most!
We’re incredibly excited to see the Airbnb iMessage app for iOS 10 go live to the Airbnb community worldwide today. We had so much fun planning and implementing this new functionality, and are proud to be present on this brand new platform on day one!
However, the journey has only just begun. We will continue exploring new ways to improve trip planning conversations, and to provide as seamless of an experience as we can. Imagine having the full set of collaborative features from the main Airbnb app as different types of interactive messages — searching for a home, comparing listings on a map, sending referrals and travel credits to friends, assisting in the account registration process, etc. We are just getting started.
Download the Airbnb app for iOS, iMessage, watchOS, and tvOS on the App Store.