Streaming is available in most browsers,
and in the Developer app.
-
Meet Watch Face Sharing
Show off your watchOS app's complications and create a watch face worth sharing. Learn how to share watch faces inside your watchOS and iOS apps or host them on the web for anyone to find and download. We'll also explore best practices for using watch face preview images, and show you how to create a smooth installation experience.
Resources
Related Videos
WWDC20
-
Download
Hello and welcome to WWDC.
Hi. My name's Jared McGann. I'm an engineering manager in watchOS. Today, we'd like to talk about Apple Watch face sharing, a new feature in watchOS 7 and iOS 14. Face sharing is exactly what you'd expect: the ability to share a watch face with anyone, configured just the way you like. Watch faces can be shared directly from the watch by long-pressing on your face and tapping the new "share" button. Select a recipient, compose a message, and that's it. In Messages, you'll see an inline preview on your watch, and so will the recipient. They just tap the preview, and they'll be prompted to add the face to their watch.
You can also share watch faces from your iPhone. Just open the iOS Watch app and select a face. Then tap the familiar "share" icon in the upper right-hand corner.
You'll be presented with a share sheet, where you can pick how you'd like to share your watch face. So how can you as a developer take advantage of face sharing? Well, watch faces can be shared directly from your apps and hosted on Web sites. With just a couple taps, the watch face you've configured can be on a customer's Apple Watch. And if you include your complication in the watch face, the customer will be prompted to install your app when they add the face.
If your app's not available in the recipient's region, your complication won't be available on the watch face. It's also worth mentioning that some newer faces are not available on older watches. And Nike and Hermès watch faces can only be generated and added on respective hardware. Watch face files contain all the face's configurations, including color, styles, photos and complications, anything you can configure on a watch. If the watch face has your complication, the file will include a sample entry so it can be previewed on the recipient's device even if your app's not installed. We have exciting new complication API in ClockKit this year. Watch faces now support multiple complications from the same app. And if your complication takes advantage of user info dictionaries or user activities, those preferences can be included in a shared watch face. For example, if a shared face included Dawn Patrol's complication, the user info dictionary could be used to specify which city's surf conditions are displayed. To learn more, please check out the talk "Create Complications for Apple Watch." So this year, we've added new API to ClockKit that allows you to prompt a customer to add a watch face from within your app. Call addWatchFace with the local URL to your preconfigured watch face file, and the customer will be prompted to add the face to their Apple Watch. This API is available in ClockKit on both watchOS and iOS. After a face with your complication is added to a watch, your app will run and respond to a timeline request from ClockKit. At this point, your app can reference the user info dictionary I mentioned earlier. Now I'd like to hand it over to Joe, who's gonna walk us through the process of adding this functionality to an existing app. Thanks, Jared. Hi. My name is Joe Dion, and I'm a software engineer in watchOS. Today, I would like to show you how to easily adopt the new Watch Face Sharing API in your iOS and watchOS apps. I have an app called "Coffee Tracker." This app allows you to track your daily caffeine intake. Here is the main view of my app, where I can view my caffeine intake for the day. If I tap the coffee cup button at the bottom, it opens the drink list view. In the drink list view, I can see a list of caffeinated drinks. If I tap one of these drinks, it will be added to my caffeine intake for the day.
My app also has a watch app with complications that display your current caffeine intake. I think my app's complications are super helpful, and I'd like to share these with my customers within the context of my app. I think implementing watch face sharing in my iOS app is a great way to accomplish this. Let's take a look how to implement this. Here's a rundown of how I will implement face sharing in this app. First, I need to generate a watch face with my app's complication. Next, I will need to import the watch face and face preview into my app's bundle.
Then I will create the UI for displaying and adding the watch face. And finally, I will add support for older watches. So let's see how to do this.
Here I am on my phone. To get started, I need to create a face to share, so I'll open the Watch app.
I'll open the Face Gallery.
Now, let's look for a watch face that complements our app.
I like the classic analog look of the Modular Compact face, so I'll select that. My watch app has a fantastic graphic rectangular complication that would look great at the bottom of this face...
so I'll select the Coffee Tracker complication. This looks great, but I'd like to make this face my own, so I'm gonna pick a color for it. Something to make this face more coffee-ish.
Walnut looks just like a cup of coffee. Now I'll select a good middle complication too.
I think the Breathe complication will help our caffeine-addicted users calm down a little bit.
That looks great. I'm happy with our coffee-tracking watch face now and I'm ready to share it. Before we share, it though, keep in mind that your app needs to have already been published to the App Store before you can share this watch face in your app. With that out of the way, I'm ready to share my face. I just need to tap the "share" button in the upper right-hand corner.
Here in the share view, you can see the "options" button, where you can exclude any of the complications or their data from the shared face. My complication is configured to always record a shot of espresso when tapped using the user info dictionary that Jared mentioned earlier. But I don't want that to be the default for my customers when I share that face with them, so I'll select "Include without data" for my complication.
Everything else looks good, so I'll leave it as is. When you share a face via e-mail, you will get the face file, along with a preview image of the face. The preview image will be very helpful later on. I've already e-mailed the watch face to myself and extracted the contents to my downloads, so let's take a look. Here on my Mac, I've opened my "Downloads" folder. You can see I have the watch face file and its associated preview from the e-mail. I'm gonna add this face file to my Xcode project.
Another important aspect of sharing a watch face in your app is displaying a preview of the face.
Here in the folder, you can see there's a preview image. I'm going to use this preview image when creating the UI, so I'll take this image and drag it into my Xcode assets folder. Now that we have the image, we're finally ready to get coding. I'll start by opening up the DeviceModel class.
I've created this class in order to detect if a watch is paired to the phone. I'll use this in my view to only display my watch face to users that have a watch. I've imported the WatchConnectivity framework as well, which allows me to implement the WCSessionDelegate protocol in this class. By implementing this protocol, I can use WCSession to determine if a customer has a paired watch. I'm going to create an isPaired computed variable in this class using WCSession to indicate if a watch is paired.
Now that I have the isPaired variable, let's go to the DrinkListView.
At the bottom of this drink list, I'd like a navigation link to a view where someone can add the face. However, I'd only like to show this navigation link to someone with a paired Apple Watch, so I'll use my DeviceModel class to create a constant equal to the DeviceModel's isPaired variable. Now I'll use my newly created constant to determine if this view should display a navigation link to the "add face" view. I'm gonna add the check and the UI for this now.
And here is our newly created navigation link. But right now the AddFaceView doesn't have any content in it, so let's go over and take a look at the AddFaceView.
Here in the AddFaceView, I need to display a preview of the watch face and a button for adding the face. I'm going to add the UI for this.
This displays a preview of the watch face that I imported and creates a button for adding the face. It also displays an activity indicator while the button is executing its action block.
I created this button using an asset from the Apple Design Resources Web site. Right now, the button doesn't do anything, though, so I'll fix that by using the new addWatchFace function. First, I will import ClockKit.
Now I'll create a wrapper function for calling addWatchFace.
Let's walk through this code to see how to use the new addFace function.
First, I create a URL that points to the watch face file in my app's bundle.
Next, I use the new addFace function. I use it by creating an instance of CLKWatchFaceLibrary. Then I call the addWatchFace function using my unwrapped watchFaceURL.
In the completion block, we need to account for any errors that might occur when adding the face. For now, I'll just print the error out. Now let's call this method in the button's action block.
Here you can see that I'm calling addFace using the face that I just created and imported to the project. Now let's see the Add Watch Face API in action and run this app.
I'll open the drink view...
and here we can see my navigation link button at the bottom. I'll tap it to open the "add face" view. And here we can see the "add face" view with a preview of our watch face. This face looks super helpful, so I'm going to tap the "Add Watch Face" button.
And here we are in the Watch app. I'll tap "Add to My Faces"...
and now the face is added to my watch. This is great. I think customers are going to find this face to be super helpful.
However, this Modular Compact face is not compatible with Series 3 watches. To support older devices, we can provide a fallback face in case the customer has an older device. Let's go back to Xcode to see how we can do this.
Right now, the addWatchFaceWrapper isn't handling errors it might encounter. Let's change that by trying to add a fallback face when the first face is not compatible.
Now let's call my addWatchFaceWrapper function with a Series 3-compatible fallback face.
I'm using the Modular face as my fallback. I picked this face based off of a list of faces that are compatible with Series 3 watches outlined in the Human Interface Guidelines. I've also already put this file into my Xcode project, so now anyone with an Apple Watch can utilize our app's watch face. Before we move on, let's review some best practices from the demo. First, when you share your watch face, remember that user data can be included. This can be valuable for specifying what content is displayed in your complication, but be careful not to unintentionally include private data.
It's also important to make sure that your complications include sample data so the watch face preview is not blank.
It's also helpful if you use the WatchConnectivity API to detect if a customer has a paired watch before offering a watch face from an iOS app.
Also remember that the best way to obtain a preview image of your watch face is to e-mail it.
Remember that if your watch face is not compatible with Series 3 watches, you should provide a face for those customers as well. Most importantly, don't forget that your app must be published before you can include it in a shared watch face. This is because the App Store Connect ID needs to be included in the watch face file. Now let's go back to Jared. Thanks, Joe. Watch faces can also be shared on Web sites. When a customer downloads a face in iOS, Safari will prompt the customer to add the face to their Apple Watch. Safari is most likely to recognize your file as a watch face if you serve the file using the watch face MIME type shown here.
Here we see an example of what a watch face might look like shared on a Web site. A preview of the watch face should be displayed above the official "Add Apple Watch Face" button. The preview image can be obtained by sharing a watch face via e-mail in the iOS Watch app, as we just saw Joe do. The button can be found on the Apple Design Resources Web site, along with a compact version that can be used in watchOS. If you prefer to display your preview within photographic hardware, as seen here, those images can also be found in the design resources.
If the shared watch face is incompatible with Apple Watch Series 3, it's important to provide an alternate watch face. When you share two watch faces, separate previews and buttons should be included on your Web page. More details, including watch face compatibility, can be found in the watchOS Human Interface Guidelines.
QR codes and NFC tags provide additional opportunities to share watch faces. Just embed a Web link that hosts a watch face file to easily get your complications and app onto a customer's Apple Watch. We hope you'll go configure your own watch faces and adopt the face-sharing API in your app, or host watch faces on your Web site. It's a great way to get your apps and complications onto customers' Apple Watches. Thanks for joining us.
-
-
7:20 - Detect Paired Watch
var isPaired: Bool { if (WCSession.isSupported()) { let session = WCSession.default session.delegate = self session.activate() return session.isPaired } else { return false } }
-
9:01 - Add Face Wrapper
private func addFaceWrapper(withName: String) { if let watchfaceURL = Bundle.main.url(forResource: withName, withExtension: "watchface") { CLKWatchFaceLibrary().addWatchFace(at: watchfaceURL, completionHandler: { (error: Error?) in if let nsError = error as NSError?, nsError.code == CLKWatchFaceLibrary.ErrorCode.faceNotAvailable.rawValue { print(nsError) } isLoading = false }) } }
-
11:04 - Add Face Wrapper with Fallback Face
private func addFaceWrapper(withName: String, fallbackName: String?) { if let watchfaceURL = Bundle.main.url(forResource: withName, withExtension: "watchface") { CLKWatchFaceLibrary().addWatchFace(at: watchfaceURL, completionHandler: { (error: Error?) in if let nsError = error as NSError?, nsError.code == CLKWatchFaceLibrary.ErrorCode.faceNotAvailable.rawValue { if let name = fallbackName { // We failed, trying with fallbackName. addFaceWrapper(withName: name, fallbackName: nil) } } isLoading = false }) } }
-
-
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.