Last month, we announced the release of our experimental iMessage App, Watch This, which allows you to easily share media-rich TV and movie recommendations without leaving your conversation. At the time, our new creation was only available in the United States, and on iPhone. This week, that changes. We’re excited to announce that Watch This is now available worldwide, and with iPad support to boot. You can get the app right here.
During our weeks of tinkering with the new Messages framework, we spent some time jotting down our thoughts and learnings, which in turn lead to a cornucopia of tips, tricks, and what we’d consider best practices.
Now, we impart that wisdom onto you: Here are our top recommendations and advice for designing and developing iMessage apps.
The Design Perspective - Best Practices
When it comes to designing for this new platform, it’s worth it to note that iMessages apps switch between two presentation styles: Compact and expanded.
The compact view is the default mode when users launch the messages app, and it’s good to think of it as a sort of keyboard. In iOS 10, the height is fixed to the same height as the default keyboard, and horizontal scrolling is not an option because this gesture is utilized to quickly switch between recent Sticker and iMessage apps that have been used.
The expanded view is the default mode when a user initiates the app by tapping on an interactive message. One almost gets a full screen viewport in the expanded view, except header and footer chrome persist from the messages app.
If the app has a companion iOS app, a button is shown in the top left cover giving the user the option to launch that full-scale companion app.
Recommendation #1: Provide options for task completion from the compact mode.
Design the default compact view so that users have options to choose content from here without switching into the expanded view.
For us, this meant including some default shows. Even if most interactions with the app include triggering a search through the expanded mode, these options help provide a visual clue to the purpose of the app.
Recommendation #2: Avoid triggering keyboard from the compact view.
iMessage apps are presented as a supplemental view to creating a message, and the text field where users compose text remains visible in both the compact and expanded views. Displaying additional text input in the iMessage app is possible, but can be visually confusing. Avoid this unless text-based search is essential.
Recommendation #3: Focus on the purpose of the app.
Don’t attempt to create an app that allows users to create stickers and interactive messages. Do one or the other (or create a separate app for each).
Don’t attempt to create an app that is optimized for both collaborative experiences (where at least one recipient also has the app installed) and content creation experiences (where only the sender has the app installed). Trying to do both creates too many variations that will complicate the experience. Do one or the other.
Recommendation #4: Be creative with the message template constraints.
There are a fixed number of layouts that you can create with the interactive message template, and space limitations with the text captions.
The image caption doesn’t do any contract checking, and will always be shown as a light text. Therefore, if you’re using content that might include a light background, it makes sense to process the image to darken the background behind the caption to make sure it’s always legible.
A good example of possible creativity is Yelp’s iMessage app: Instead of using text captions for the image, Yelp dynamically incorporates the property name and star rating directly into the image, which also provides utility for users receiving the message who don’t have iOS 10.
The template that iOS 10 provides for displaying messages doesn’t allow for a star rating to be added, but you’re free to insert this directly into the app, which has the benefit of also appearing for people who receive the message on a device earlier than iOS 10 or macOS Sierra.
The Development Perspective: Tips + Advice
When users launch a message app, the mental model is similar to switching into the emoji keyboard. The launch time should be as quick as possible. Avoid a default screen that produces any latency. If you need to load content from a remote source, show cached content first.
Recommendation #1: Encode interactive message content in the URL.
Users don’t need internet connectivity to use the Messages app, so as much as possible, interactive messages should also work without internet connectivity.
If you have an interactive message that displays additional information when users tap on it to trigger the iMessage app expanded view, consider encoding as much information as possible within the associated URL so that this feature is still usable when an internet connection is not available.
var components = URLComponents()components.scheme = “https”components.host = “fallback.messageapp.com”let idItem = URLQueryItem(name: “id”, value: “63247”)let titleItem = URLQueryItem(name: “title”, value: “Westworld”)let overviewItem = URLQueryItem(name: “overview”, value: “A dark odyssey about the dawn of artificial consciousness and the future of sin.”)components.queryItems = [idItem, titleItem, overviewItem]components.url// -> https://fallback.messageapp.com?id=63247&title=Westworld&overview=A%20dark%20odyssey%20about%20the%20dawn%20of%20artificial%20consciousness%20and%20the%20future%20of%20sin.
The downside to consider with this approach is that users who don’t have iOS 10 (and are therefore sent the fallback message) are going to see a messy long URL.
Recommendation #2: Use a placeholder image while waiting for remote images.
If you’re inserting an interactive message into the conversation programmatically, any existing message will be overwritten. This is actually very convenient because if your interactive message has a resource (image, video, or audio) that you need to load from a remote resource, you can insert a message with placeholder content, and then replace it immediately with the remote resource as it becomes available.
//private func createMessage(with content: MessageContent, andImage image: UIImage) -> MSMessage// helper method that returns a message}let placeholderBackground = UIImage(named: “placeholderBackground”)// Insert message with placeholder imageself.activeConversation?.insert(createMessage(with: messageContent, andImage: placeholderBackground))// Grab the remote resource asynchronously and update message with returned imageImageManager.shared.getBackgroundImage(from: remoteImageUrl, completed: { image inif let image = image {self.activeConversation?.insert(self.createMessage(with: messageContent, andImage: image))}})
Development Tip #1: Triggering keyboard input from compact view.
If you attempt to have an element become the first responder while in the compact view iOS will throw an exception.
If you show an element that can trigger the keyboard in the compact view (for example a search bar) then you’ll need to do a two-step process in showing the keyboard: first prevent the element from becoming first responder, then transition to the expanded view, and finally request the search bar to be first responder.
// UISearchBarDelegatefunc searchBarShouldBeginEditing(_ searchBar: UISearchBar) -> Bool {switch presentationStyle {case .compact:requestPresentationStyle(.expanded)return falsecase .expanded:return true}}// MSMessagesAppViewControlleroverride func didTransition(to presentationStyle: MSMessagesAppPresentationStyle) {if case .expanded = presentationStyle {searchBar.becomeFirstResponder()}
}
Conversely, when transitioning from expanded to compact view, you need to have the search bar resign being the first responder before being back to compact mode.
// MSMessagesAppViewControlleroverride func willTransition(to presentationStyle: MSMessagesAppPresentationStyle) {if case .compact = presentationStyle {searchBar.resignFirstResponder()}}
Development Tip #2: Launching other apps.
Normally when you want to open another app all you need to know is it’s URL scheme. For example if I want to launch the Hulu app and start watching the episode with the id 286745 the following code would work on an iOS app.
// check to make sure url is validif let url = URL(string: “hulu://w/286745”){// check to see if url can be opened on appif UIApplication.shared.canOpenURL(url) {// open the url!UIApplication.shared.open(url, options: [:], completionHandler: nil)}else {// probably want to launch iTunes store to install Hulu app}}
In the iMessage extension Xcode will prevent this from building with a compiler error.
Apple documentation says that extensions can instead use their extension context to open a url, but this only works in the Today extension:
if let url = URL(string: “hulu://w/286745”){// only works in `Today` extensionsself.extensionContext?.open(url, completionHandler: nil)}
Alternatively…
// helper function that crawls up the chain of responders until// one can perform the openURL messagefunc openUrl(url: URL) {var responder: UIResponder? = selfwhile let r = responder {if r.responds(to: “openURL:”) {r.perform(“openURL:”, with: url)break}responder = r.next}}
Finally, here are some additional resources from our team:
Behind The Scenes: ustwo’s Sketch file for Watch This
Apple Human Interface Guidelines for Messages app
Apple Messages API Developer references
https://developer.apple.com/reference/messages/msmessagetemplatelayout
Now that you have your tips and tricks, it’s time to get out there and start creating iMessage apps! And don’t forget to check out Watch This, now available for both iPhone and iPad, worldwide.
This piece was originally published on ustwo.com
✨ We’re ustwo. We build digital products, services and businesses that make a meaningful impact on the world.
👏 If you’d like to create something incredible with us, get in touch — hello@ustwo.com
📥 Sign up right here to get the freshest ustwo thinking delivered direct to your inbox.