Streaming is available in most browsers,
and in the Developer app.
-
Accelerate your app with CarPlay
CarPlay is the smarter, safer way for people to use iPhone in the car. We'll show you how to build great apps for the car screen, and introduce you to developing CarPlay apps in categories like EV charging, parking, and quick food ordering. We'll also share how existing audio and communication apps can take advantage of improvements to the CarPlay framework to create a more flexible UI.
Resources
Related Videos
WWDC22
WWDC19
WWDC18
-
Download
Hello, and welcome to WWDC.
Greetings, racing fans, and welcome to "Accelerate Your App with CarPlay." I'm Jonathan Hersh from iOS Car Experience. Today, we're going to add an amazing car experience to your apps with CarPlay. Buckle up, and away we go. If you've driven with CarPlay, you're probably familiar with some incredible third-party navigation apps, like Waze and Google Maps. These navigation apps built their CarPlay experience with the CarPlay framework, a set of APIs first introduced in iOS 12. The CarPlay framework provides several types of template objects, which your app can configure to build an amazing CarPlay experience. But until now, CarPlay templates have only been available to navigation apps.
Today, we are thrilled to announce a brand-new set of CarPlay templates, plus some amazing improvements to existing templates, that together make CarPlay available to a whole new set of apps for the first time in iOS 14.
iOS 14 introduces several new templates for audio apps. Apple Books has created an amazing new CarPlay experience for your audiobooks in iOS 14 with these new audio templates. If you've built a CarPlay audio app before, you're probably familiar with the playable content API. In iOS 14, playable content will be deprecated. Audio templates open up a whole new world of possibilities for your audio apps.
We're introducing new templates for communication apps, like messaging and calling apps.
We have new templates to drive your EV charging and parking apps.
And we have new templates that support quick-service restaurants in CarPlay. We're going to take a scenic drive through all of these new templates in just a few minutes. But first, let's review some design principles that you should keep in mind while building your app in CarPlay. CarPlay is designed for the driver, not for passengers. Think about optimizing your app for tasks that make sense in the car.
CarPlay apps are purposeful. Start with the most common scenarios in your app and distill them down to glanceable, streamlined interactions, each interaction being a task the driver can complete in just a few seconds.
Whenever possible, reuse configuration from your app to minimize or eliminate any setup your user has to do in CarPlay.
Your app's first-run experience should already be completed on-device before the user starts driving.
And remember, your app may be launched first in CarPlay, and only in CarPlay. When the user taps your app on the CarPlay home screen, your app will connect to a car scene, not an iPhone scene.
So it's very important that you eliminate any logic in your app that depends on being launched on iPhone.
This is easy to do with UIScene, and in fact, your app must adopt UIScene to use the CarPlay framework, so you'll want to transition away from the legacy UIWindow and UIApplicationDelegate APIs.
And with those design principles in mind, let's take a drive through new CarPlay templates for audio apps. And even if you're not developing an audio app, stay tuned, because your app can use some of these new templates too.
I mentioned a minute ago that until now, if you were building an audio app for CarPlay, you would implement the playable content API. Playable content is a metadata-based API. You describe your app's data, like albums and songs, and the system assembles a tree-style UI on your behalf. Keep in mind that if you want to deploy your app to iOS 13 and earlier, playable content and audio templates can coexist in your app.
On iOS 13 and earlier, the system will launch your app with playable content. And in iOS 14, the system will launch with your CarPlay templates if you've provided them. So let's take a look at converting your playable content app's life cycle to CarPlay templates.
Now, I mentioned earlier that you'll need to adopt UIScene to use CarPlay templates, and here you can see just how easy that is. A key part of adopting UIScene is declaring a Scene Manifest for your app. You can add this manifest to your app's Info.plist as a new top-level key.
This is a sample scene configuration for the CarPlay template application scene. You'll want to specify a scene configuration for your CarPlay scene, like this example, in addition to a scene configuration for your app on iPhone. If you're building a navigation app, you can also provide a scene configuration for the CarPlay dashboard.
We're also specifying the name of a class that serves as the scene delegate in your app for the CarPlay scene.
Here, we're implementing the class that we specified in our scene configuration. This is the connect method from the CPTemplateApplicationSceneDelegate protocol in the CarPlay framework.
The CarPlay framework calls this connect method when your app has been launched on the CarPlay screen.
First, you'll probably want to hold onto this CPInterfaceController object, because you'll need it later.
And here, I'm setting a CPListTemplate as my app's root template, and it's just that easy. We now have a template on the car screen. And here, in the disconnect method, we can release the interface controller that we were holding.
Let's look at the list template in a little bit more detail. We'll start by creating a list item. Each list item represents a single row in our list template. Here, I'm starting with just a title and subtitle in a list template with a single section.
When the user selects your list item, the list item handler will be called. The handler receives two arguments. The first is the list item that was selected, and the second is a completion block.
When a list item is selected, your app probably has some work to do. For example, you might initiate playback of the item that the user selected, or you might configure and present a new template. After you finish any work, you must call the completion block. But if you don't immediately call the completion block, that's okay.
CarPlay will display a spinner to let the user know that your app is busy. When you call the completion block, that signals to CarPlay that you've finished processing the user's selection, and CarPlay will remove the spinner from your list item.
Also new in iOS 14, we've added support for dynamic list item updates. Many properties on CPListItem that were previously read-only are now writable. In this example, it might take my app some time to fetch an album artwork image over the network.
Updating my list item to show that image is as easy as assigning a value to the newly writable image property in the list item, and CarPlay will automatically reload only the affected rows in your list template. It's like magic. For example, Apple Podcasts uses these dynamic updates to keep the progress indicator updated with your listening progress. Let's now turn to another new template in iOS 14, the tab bar template. This is a new type of container template. It can display several of your app's templates in a tab-bar-style interface that's instantly familiar to CarPlay users.
So, let's make a tab bar template. We'll start by creating two tabs for the tab bar: one of them a list template and the other a grid template. Here's a list template to show some of my favorite albums. In iOS 14, every CarPlay template inherits some new properties to let you customize how that template appears in the tab bar.
You can set the tab's title, pick a system tab image, or provide your own custom tab image, and indicate whether the tab should show a badge.
We can create a tab bar template by providing an array of templates, and each template in the array becomes a tab on the tab bar.
We can also dynamically update the tab bar template. We can add new tabs, remove tabs, rearrange tabs, or in this example, we can show and hide the badge on one or more tabs.
Let's turn now to some new additions in the list template for audio apps. Here, Apple Podcasts is using the new tab bar template plus some new list item customizations. You'll find a host of new properties available in CPListItem for audio apps, like the playback progress indicator and the Now Playing bouncing bars.
And here, in iOS 14, Apple Books is using the new CPListImageRowItem, which brings this stunning artwork grid to your audiobooks in CarPlay.
The list image row item is available for your apps too. It's as easy as adding the list image row item to your list template.
So let's try out those new list items. Here, I'm creating an imageRowItem to show some recently played audiobooks in a grid of artwork.
And just like the other list items, the image row item has a listItemHandler. It's called when the user selects the title in the image row item. So, in this example, I might push a new list template to show even more of the user's recent audiobooks.
And just like in the other list items, make sure to call the completion handler after your app finishes any asynchronous work.
Each artwork in the grid is individually selectable, so in addition to that title handler, we'll also specify a listImageRowHandler. In the image row handler, we can take some action in response to the specific audiobooks that the user selected. For example, we might start playback of that book. Let's turn now to the cornerstone of your audio app in CarPlay...
the nowPlayingTemplate. The Now Playing screen is instantly familiar to CarPlay users, and with templates, you have even more control over its appearance and behavior.
Your app can optionally enable the "Playing Next" button and the "Album Artist" button. You may also optionally provide custom Now Playing buttons across the bottom of the Now Playing screen. Your Now Playing buttons can use your own custom images, or you can choose from several system-provided images that cover many common playback actions. The nowPlayingTemplate is unique among templates, and it has several special behaviors that you should keep in mind. First, the nowPlayingTemplate is a shared instance. There's only one instance of this template in your app. You should configure the properties of that shared instance, and, if you enable the optional "Playing Next" and "Artist" buttons, you should add at least one observer for those button actions.
You should perform that initial Now Playing configuration as soon as possible, immediately after your app launches in CarPlay. Why? Because the system may display the nowPlayingTemplate on your behalf. For example, when the user taps the Now Playing button on the CarPlay home screen, the system will launch your app and immediately present the shared nowPlayingTemplate.
When your app becomes the Now Playing app, the system will also add the Now Playing bar button to your app's navigation bar or tab bar. If the user taps that button, the system will present the same shared nowPlayingTemplate. If a different app becomes the Now Playing app, the system will automatically remove the Now Playing bar button from your navigation bar or tab bar in CarPlay.
Lastly, only the list template may be pushed on top of the nowPlayingTemplate in the template stack. For example, if your app enables the "Playing Next" button in the nowPlayingTemplate, then pushing a new list template is a great way to show your user the upcoming playback queue.
So, let's revisit our template life cycle example from earlier. When your app is launched in CarPlay, you'll always want to configure the shared nowPlayingTemplate instance immediately, because the system may be launching your app just to show Now Playing, and when your app connects to the CarPlay scene, that's a great time to set up the shared nowPlayingTemplate.
In this example, I'm configuring a playback rate button that will call a handler when the user selects it.
This would also be an ideal place to enable the "Playing Next" button and add observers for the nowPlayingTemplate buttons. With that initial configuration done, your app is ready for the system to present Now Playing on your behalf, and you can always update the shared nowPlayingTemplate later. That was a quick look at some new CarPlay templates. We saw the new tab bar template, a foundational interface for all kinds of apps in CarPlay, plus the nowPlayingTemplate and other list-item updates for audio apps. Next up, my colleague, Allen, will take us on a drive through the other new CarPlay app categories.
Thanks, Jonathan. I'm Allen Langmaier from iOS Car Experience. Now that we've seen how improvements to existing templates will make current apps that much better, I'd like to introduce a whole new set of app categories for CarPlay.
Starting in iOS 14, communication apps can take advantage of the CarPlay framework to provide an experience right on the car's display. And for the first time, EV charging, parking, and quick food ordering are brand new categories of apps that can now be brought to CarPlay. Communication apps are what were previously known in CarPlay as Messaging and VoIP calling apps that traditionally worked by leveraging SiriKit and CallKit. Communication apps must continue to use SiriKit and CallKit to provide voice and telephony features. But starting in iOS 14, they can also take advantage of the CarPlay framework to show contacts, organize message lists and display message status. Here's an example of a communication app that makes use of these new features of the CarPlay framework.
This app uses the new tab bar template, as we saw earlier, to intuitively allow the user to choose contacts and listen to messages.
A common feature of communication apps is the ability to show a list of message threads. Starting in iOS 14, we are introducing a new list item subclass called CPMessageListItem that includes a number of useful properties to help create a rich user experience.
For this type of list template item, handlers are not called when tapped by the user. Instead, Siri will be automatically invoked using the parameters you specify in the message list item, and the user will continue a message compose, read, or reply flow through Siri.
On the leading side, you can choose to display an unread indicator, a pin, a star, or icon. Use some or all of these options to match the capabilities of your app.
And the trailing end can be configured with a mute indicator, text and an optional image.
And like other items, CPMessageListItem supports dynamic list updates, allowing you to easily change elements of a message just by updating its properties. Another important feature for communication apps is the ability to show contact information. The contact template is a brand new template in iOS 14 that will bring your address book to the foreground. In this example, the app has set up the contact template with an image, descriptive text, a set of action buttons, and navigation bar buttons.
Note the template supports up to three lines of text and up to four buttons that can individually be configured with custom images and text. With all these new features available to communication apps, we can't wait to see the experiences you'll bring to the CarPlay screen. Now let's look at new app categories appearing for the first time in iOS 14: EV charging, parking, and quick food ordering. These type of apps have many things in common. They're all intimately involved with the driving experience, as they help find destinations on a map.
Additionally, these apps make it possible to check availability, reserve chargers or parking, and place orders.
We're excited to introduce a set of new templates in iOS 14 that enable your apps to provide these features in CarPlay.
Let's start by looking at an example of a quick food ordering app. The app has four tabs across the top for nearby store locations, previous purchases, favorites, and order information.
Notice that the app is streamlined, and everything is immediately actionable.
There is no detailed food menu, account management, or other settings. Focus your CarPlay experience on providing easy, one-step access to the most common tasks. Whether you are looking for a nearby drive-through, a charging station for your electric vehicle, or a nearby parking garage, your first task is to identify a location. iOS 14 includes the brand new point of interest template.
The point of interest template combines an interactive map provided by the MapKit framework accompanied by an information panel.
Use it to show nearby locations and let users pick one.
Your app supplies a list of locations and optional images to show on the map.
The template provides pan and zoom capabilities and will notify you of changing map regions.
To create a point of interest template, start by constructing a list of up to 12 CPPointOfInterest instances.
Each of these includes a title, an optional subtitle, and an informative text that will be shown on the information panel.
Remember to show only the most relevant information to drivers in CarPlay. On iPhone, your app might show all possible locations, but in CarPlay, you should limit the list to those that are most relevant or nearby. If multiple locations appear close to each other on the map, CarPlay will automatically group them.
The point of interest template supports dynamic property updates like other CarPlay templates.
Here, to indicate selection, we have updated the pin image property of a location to use a different color.
When a location is selected from a list, you may choose to show a secondary card for that point, revealing additional information and up to two buttons. These buttons could be used for a variety of tasks. For instance, they may signal you to switch to a navigation app for driving directions or push to another template to display additional information for that location. Let's take a look at how to update the template in response to either user pan and zoom actions, or movement. All three of these events will result in the visible map region changing, and your app should update the template with a new list of locations that correspond to that region. Start by assigning the template an object conforming to CPPointOfInterestTemplateDelegate so it can be notified each time the map region changes.
Here we see the delegate method being defined...
and new locations being computed...
and then passed to the template.
At this time, CarPlay will update your locations list and map with the new values.
Next, let's take a closer look at how your app may go about managing all your relevant points of interest.
In the previous slide, we saw the need to compute new locations for a region.
You may choose to query your own locations database or leverage MapKit's to determine nearby destinations.
Then you'll need to construct a list of CPPointOfInterest models, initializing each with the data from your lookup. This is where you bring coordinate values, titles, and other available data from your app and make them available to the template.
In this example, the app attempts to reuse models whenever possible as an optimization and to reduce work for the template.
And it's just that easy. By responding to map region changes and keeping the template current, you'll enable your users to find nearby destinations.
And lastly, let's add one more bit of functionality to your app.
Having just enabled location browsing, your users will likely need to pick one to proceed.
Making use of the optional button properties of CPPointOfInterest is a convenient approach in making locations selectable.
Here we assign a CPPointOfInterest instance a primary button that will appear on the information panel.
As you can see, a "Select" button is now available for the location.
As noted earlier, the information panel supports up to two buttons and several lines of descriptive text for each point.
The next step is to assign the button a handler. The button's handler will be called when tapped, and here we're maintaining both selection state, in addition to updating annotation images to make it more clear which location is selected on the map.
Again, any changes to template properties will immediately translate to car screen updates. In this case, assigning the selectedIndex of the location will have the template show the new state. And that completes our quick tour of the point of interest template, taking us from handling map region changes to making locations selectable. Now, once the user has chosen a location or performed a task, you may need to show a summary or otherwise finalize the interaction.
The information template is new in iOS 14. It brings everything together in a one-stop shop for displaying text and receiving user responses.
The information template is created with a list of labels that may be configured in either one or two columns and a set of footer buttons. The template can serve many purposes where full-screen interaction is needed. For quick food ordering apps, the information template may be used as an order summary, as seen here, or even a confirmation page.
And for EV charging apps, the information template can be used to show important information about a charging station.
That takes us to the end of this quick overview of some of the new templates in iOS 14. The contact template takes the address book in your communication apps to the foreground...
and the point of interest template is making it possible to build EV charging, parking, and apps for quick-service restaurants...
while the information template ties everything together by providing the ability to display text and receive user responses on the car screen.
We're excited to see all the great apps you'll come up with making use of them. And now back to Jonathan to wrap things up for us today. Thanks, Allen. Today, we took a scenic drive through some new additions to the CarPlay framework. If you're working on a navigation app, then you can use many of the new templates and improvements we discussed today.
Your audio and communication apps can now take advantage of new templates, like the tab bar template, plus some improvements to existing templates, like the list template. We also introduced brand new app categories that are supported in CarPlay for the first time.
We saw new templates for EV charging and parking apps, like the new point of interest template. Apps whose primary function is EV charging or parking can now provide a great experience in CarPlay.
And if your app serves quick-service restaurants, you can add CarPlay to your app to allow users to easily choose recent or favorite items and order them for pickup or drive-through. Now, keep in mind that the car is a special place. If you have an app in one of the categories we've discussed today, then you'll need to apply for an entitlement to enable CarPlay for your app.
CarPlay apps must be single-category. You will need to choose the category that you are supporting with your app and use a single entitlement.
The entitlement you choose will determine which CarPlay templates are available to your app. And remember, if you're building an audio app, and you want to deploy to iOS 13 or earlier, that playable content and audio templates may coexist in your app.
For much more about CarPlay templates, check out the updated CarPlay App Programming Guide on developer.apple.com/carplay. This is also where you can go to request entitlements for your app. There's also much more detail here about which entitlements may use which CarPlay templates.
If you're deploying an audio app to iOS 13 or earlier, you may want to revisit the playable content documentation. And if you're building a communication app, your app must implement SiriKit. There's a wealth of documentation and resources available on the CarPlay developer site.
If you're working on a navigation template app, check out our session from WWDC 2018. Thank you so much for joining us today. We are so excited to accelerate your apps onto the car screen and to see what you build with CarPlay templates.
-
-
4:24 - CarPlay scene manifest
// CarPlay Scene Manifest <key>UIApplicationSceneManifest</key> <dict> <key>UISceneConfigurations</key> <dict> <key>CPTemplateApplicationSceneSessionRoleApplication</key> <array> <dict> <key>UISceneClassName</key> <string>CPTemplateApplicationScene</string> <key>UISceneConfigurationName</key> <string>MyApp—Car</string> <key>UISceneDelegateClassName</key> <string>MyApp.CarPlaySceneDelegate</string> </dict> </array> </dict> </dict>
-
5:12 - CarPlay app lifecycle
// CarPlay App Lifecycle import CarPlay class CarPlaySceneDelegate: UIResponder, CPTemplateApplicationSceneDelegate { var interfaceController: CPInterfaceController? func templateApplicationScene(_ templateApplicationScene: CPTemplateApplicationScene, didConnect interfaceController: CPInterfaceController) { self.interfaceController = interfaceController let item = CPListItem(text: "Rubber Soul", detailText: "The Beatles") let section = CPListSection(items: [item]) let listTemplate = CPListTemplate(title: "Albums", sections: [section]) interfaceController.setRootTemplate(listTemplate, animated: true) } func templateApplicationScene(_ templateApplicationScene: CPTemplateApplicationScene, didDisconnect interfaceController: CPInterfaceController) { self.interfaceController = nil }
-
5:54 - Create a CPListTemplate
// CPListTemplate import CarPlay let item = CPListItem(text: "Rubber Soul", detailText: "The Beatles") let section = CPListSection(items: [item]) let listTemplate = CPListTemplate(title: "Albums", sections: [section]) self.interfaceController.pushTemplate(listTemplate, animated: true)
-
6:09 - Handle user selection in a list item
// CPListTemplate import CarPlay let item = CPListItem(text: "Rubber Soul", detailText: "The Beatles") item.listItemHandler = { item, completion, [weak self] in // Start playback, then... self?.interfaceController.pushTemplate(CPNowPlayingTemplate.shared, animated: true) completion() } // Later... item.image = ...
-
7:58 - Create a CPTabBarTemplate
// CPTabBarTemplate import CarPlay let item = CPListItem(text: "Rubber Soul", detailText: "The Beatles") let section = CPListSection(items: [item]) let favorites = CPListTemplate(title: "Albums", sections: [section]) favorites.tabSystemItem = .favorites favorites.showsTabBadge = true let albums: CPGridTemplate = ... albums.tabTitle = "Albums" albums.tabImage = ... let tabBarTemplate = CPTabBarTemplate(templates: [favorites, albums]) self.interfaceController.setRootTemplate(tabBarTemplate, animated: false) // Later... favorites.showsTabBadge = false tabBarTemplate.updateTemplates([favorites, albums])
-
9:34 - Create a CPListImageRowItem
// List Items for Audio Apps import CarPlay let gridImages: [UIImage] = ... let imageRowItem = CPListImageRowItem(text: "Recent Audiobooks", images: gridImages) imageRowItem.listItemHandler = { item, completion in print("Selected image row header!") completion() } imageRowItem.listImageRowHandler = { item, index, completion in print("Selected artwork at index \(index)!") completion() } let section = CPListSection(items: [imageRowItem]) let listTemplate = CPListTemplate(title: "Listen Now", sections: [section]) self.interfaceController.pushTemplate(listTemplate, animated: true)
-
12:50 - Configure the shared now playing template
// Now Playing Template import CarPlay class CarPlaySceneDelegate: UIResponder, CPTemplateApplicationSceneDelegate { func templateApplicationScene(_ templateApplicationScene: CPTemplateApplicationScene, didConnect interfaceController: CPInterfaceController) { let nowPlayingTemplate = CPNowPlayingTemplate.shared let rateButton = CPNowPlayingPlaybackRateButton() { button in // Change the playback rate! } nowPlayingTemplate.updateNowPlayingButtons([rateButton]) } }
-
19:46 - Handle Point of Interest Template map region changes
// CPPointOfInterestTemplateDelegate func pointOfInterestTemplate(_ template: CPPointOfInterestTemplate, didChangeMapRegion region: MKCoordinateRegion) { self.locationManager.locations(for: region) { locations in template.setPointsOfInterest(locations, selectedIndex: 0) } }
-
20:23 - Create points of interest
// CPPointOfInterest creation func locations(for region: MKCoordinateRegion, handler: ([CPPointOfInterest]) -> Void) { var tempateLocations: [CPPointOfInterest] = [] for clientModel in self.executeQuery(for: region) { let templateModel : CPPointOfInterest = self.locations[clientModel.mapItem] ?? CPPointOfInterest(location: clientModel.mapItem, title: clientModel.title, subtitle: clientModel.subtitle, informativeText: clientModel.informativeText, image: clientModel.mapImage) tempateLocations.append(templateModel) } handler(templateLocations) }
-
21:05 - Point of interest selection buttons
// Point of Interest Template location selection let primaryButton = CPPointOfInterestButton(title: "Select") { button, [weak self] in let selectedIndex = ... if selectedIndex != NSNotFound { // Remove any existing selected state on previous location self?.selectedLocation.image = defaultMapImage // Change annotation for selected POI self?.selectedLocation = templateModel templateModel.image = selectedMapImage // Update the template with new values self?.pointOfInterestTemplate.selectedIndex = selectedIndex } } let templateModel: CPPointOfInterest = ... templateModel.primaryButton = primaryButton
-
-
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.