Best Practices
Store data with userInfo
Both CPListItem and CPListImageRowItem have a userInfo property used to store data. The relationship between CPListItem and userInfo is similar to that between UITableViewCell and the model.
Set item interactivity via isEnabled (iOS 15)
Both CPListItem and CPListImageRowItem have an isEnabled property, which is used to set the interactivity of the item (the default value is true).
The items with isEnabled set to false will be grayed out and unclickable. That means the item handler or CPListTemplateDelegate's didSelect method will not be triggered.
The best practice is:
Set isEnabled to false for items with no interaction, such as "temporarily unavailable items" and "loading," so that the rendered UI looks better. However, this API is only available on iOS 15 and above.
Use handler to respond to item's click event.
Both CPListItem and CPListImageRowItem conform the CPSelectableListItem protocol. There is a handler property, which is used to respond to the item's click event.
Notice:
If you set the handler for the items, clicking on the item will trigger the handler and not trigger the method of CPListTemplateDelegate.
Since CPListTemplateDelegate has been marked as deprecated in iOS 14, it is recommended to use the handler to handle actions.
Compared with CPListTemplateDelegate, the handler has an advantage in handling actions. Handler is for items, while CPListTemplateDelegate is for all items in CPListTemplate. If we use CPListTemplateDelegate, we need to do guard processing for other items, such as "temporarily unavailable items" and "loading." If we use a handler, we can handle the actions of these items individually or not.
Show the playing indicator via the isPlaying property
Use a CPListItem to display audio, and you can also display a playing indicator via the isPlaying property.
The position of the indicator defaults to the left and hides the image. You can also set the indicator position to the right via the playingIndicatorLocation property.
Support open playlist
An excellent audio app's playback page should support opening the current playlist, which is convenient for users to switch songs, and the CarPlay app should also have it. Especially if an album is played through the iPhone app and the CarPlay app doesn't have the album data (the data in the CarPlay and iPhone app may be different). If the user wants to listen to other songs on the album, they can only use the "Previous/Next song" or "iPhone app's playlist" to switch. So it would be great to support opening the current playlist on the CarPlay app.
CPNowPlayingTemplate supports displaying a button to open the current playlist in the upper right corner. After clicking, push a CPListTemplate to display the current playlist.
Page jump
Do you remember the entrance to the CarPlay app?
It serves as the entry controller of our CarPlay app, and we assign a template as rootTemplate to it.
We need it when we want to make a page jump, and it is somewhat similar to UINavigationController.
It supports: push, pop, present, dismiss, etc. (present and dismiss are only used for CPActionSheetTemplate, CPVoiceControlTemplate, and CPAlertTemplate).
For audio apps, the push is generally enough, and the upper left corner of the subpage has its own "Back" button.
Images
Icons and images
Check out the Design Guidelines for CarPlay and send it to your PM and UI designer.
Dark/light mode
The adaptation solution is the same as the iPhone apps. If your app needs two display modes, you must set it up.
Asynchronous images
CarPlay doesn't support GIF images, and the configuration will cause crashes.
Asynchronous images must also adapt to the scale. Otherwise, it will cause blur.
Solutions:
Option 1: We can add extension methods for handling asynchronous images to CPListItem and CPListImageRowItem.
Option 2: Using Kingfisher
Option 3: Using SDWebImage
Reload data
In the case of a poor network, starting the CarPlay app may have the problem of request timeout and no data. Therefore, the solutions are as follows:
1, Do not reload data.
If it is the home page, the user needs to restart the CarPlay app to reload.
If it is a subpage, the user needs to exit and re-enter the subpage to reload.
2, If rootTemplate is CPTabBarTemplate, you can reload selectedTemplate when - tabBarTemplate:didSelectTemplate:.
3, For the second approach, reloading is invisible to the user because you can't or can't add an activity indicator.
The solution is to add a loading item (such as using CPListItem and displaying "Loading") during the request for data.
Then, if the request fails, update the item to a failure item (such as using CPListItem and displaying "Load failed, click to retry").
Then, when the user clicks on the failure item, update the item to the loading item and re-request the data.
We can do it for every page that needs to fetch data from the backend.
Do I need to refresh the data?
If you want to allow the data to be refreshed while using the CarPlay app, you can handle it in a second way. However, in practical applications, users will not use CarPlay for a long time at a time, so there is no need to consider refreshing. Instead, wait until the next app starts to fetch new data.
Therefore, in most cases, we only need to reload the data when the app fails to load for the first time.
Pay attention to user experience in a weak network and no network environment.
In WWDC or related documents, Apple has repeatedly mentioned that paying attention to the user experience in a weak network or no network environment is necessary because drivers may pass the road section or area with a poor network while driving.
For example, the request timeout mentioned above, the problem of reloading data, the problem of data synchronization in CPNowPlayingTemplate, whether the playback control event fails to work, and so on.
Siri
Even if your app does not support SiriKit, you can still use Siri to switch songs/episodes, pause or resume playback because these remote control events naturally support Siri.
Testing
You can test it in a real environment (in a car).
You can test it in CarPlay Simulator. Also, the article "Using the CarPlay Simulator" lists some features you cannot test on the CarPlay Simulator.
For audio apps, the simulator has some limitations in the playback state and does not reflect the real user experience.
To fully debug your app with LLDB, wireless debugging is supported starting in Xcode 9, so you can debug your app while the iPhone is connected to the car.
Notes & Best Practices
1, Singleton issue.
CarPlay uses a singleton. If the CarPlay app is closed, but the iPhone app is not closed, the process is still there, and the singleton has not been released, which may cause some issues.
We can initialize the singleton in:
and release the singleton in:
2, The language of CarPlay follows the iPhone, and so does the Simulator.
3, CarPlay framework needs to be weak reference optional (Target > Build phases > Link Binary With Libraries). Otherwise, it will crash when launching the app under iOS 12.
4, It is recommended to pause playback when CarPlay is disconnected.
5, When CarPlay is disconnected, you can check for memory leaks through the Memory Graph.
6, The Template page should display at least one piece of content, especially if you do not use CPTabBarTemplate as the rootTemplate. Otherwise, the page will be blank, giving the user a bad experience.
For example, when there is no playback record, a CPListItem is filled on the recently played page, and "no playback record" is displayed.
7, There are also some situations to be aware of.
For example, when the iPhone is locked, or the user is not logged in, your app still needs to display perfect functionality in CarPlay.
Follow me on:
Comments