Dunfey · Hotel WWDC as data, est. 1983
Front desk everything
Years
Topics

2020 App Services

WWDC20 · 26 min · App Services

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.

Watch at developer.apple.com ↗

Transcript all transcripts

Code shown on screen · 10 snippets

CarPlay scene manifest xml · at 4:24 ↗
// 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>
CarPlay app lifecycle swift · at 5:12 ↗
// 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
}
Create a CPListTemplate swift · at 5:54 ↗
// 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)
Handle user selection in a list item swift · at 6:09 ↗
// 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 = ...
Create a CPTabBarTemplate swift · at 7:58 ↗
// 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])
Create a CPListImageRowItem swift · at 9:34 ↗
// 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)
Configure the shared now playing template swift · at 12:50 ↗
// 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])
    }
}
Handle Point of Interest Template map region changes swift · at 19:46 ↗
// CPPointOfInterestTemplateDelegate

func pointOfInterestTemplate(_ template: CPPointOfInterestTemplate, 
                             didChangeMapRegion region: MKCoordinateRegion) {

    self.locationManager.locations(for: region) { locations in
        template.setPointsOfInterest(locations, selectedIndex: 0)
    }
}
Create points of interest swift · at 20:23 ↗
// 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)
}
Point of interest selection buttons swift · at 21:05 ↗
// 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

Resources