Adding User Interface in CarPlay

Hi,

I am working on my current iPhone app to be supported in CarPlay. I already got approved by Apple CarPlay team, received the development entitlement, read the CarPlay related programming guide, and watched the video "Enabling Your App for CarPlay" (https://developer.apple.com/videos/play/wwdc2017/719/). In the video there is a piece of Swift code demonstrating how to add CarPlay UI:


func updateCarWindow()
{
    guard let screen = UIScreen.screens.first(where: { $0.traitCollection.userInterfaceIdiom == .carPlay })
        else
        {
            // CarPlay is not connected
            self.carWindow = nil;
            return
        }

    // CarPlay is connected
    let carWindow = UIWindow(frame: screen.bounds)
    carWindow.screen = screen
    carWindow.makeKeyAndVisible()
    carWindow.rootViewController = CarViewController(nibName: nil, bundle: nil)
    self.carWindow = carWindow
}



My questions are:


1. How to add tabs in my app for CarPlay? I have added the following to my Info.plist file:

<key>UIBrowsableContentSupportsSectionedBrowsing</key>

<true/>


What are the next steps to add, for example, 3 tabs, into my app?


2. If I'd like to add a button in my app, how should I do that?


3. I am new in Swift. How to convert the above Swift code, especially the "guard" body, to Objective-C code?


Thanks a lot in advance.

I am using CarPlay Simulator to test the above code. I found that CarPlay is never "connected". Do I have to run the app in a car instead of the simulator? Thanks.

I re-wrote the above Swift method updateCarWindow to the following Objective-C version. However I found that the property screens always returns 1 element (the main screen), no matter when testing on a real device or simulator.


So how should I make it able to connect to CarPlay? Thanks in advance.



- (void) updateCarWindow
{
    NSArray *screenArray = [UIScreen screens];

    for (UIScreen *screen in screenArray)
    {      
        if (screen.traitCollection.userInterfaceIdiom == UIUserInterfaceIdiomCarPlay)    // CarPlay is connected.
        {
            // Get the screen's bounds so that you can create a window of the correct size.
            CGRect screenBounds = screen.bounds;

            UIWindow *tempCarWindow = [[UIWindow alloc] initWithFrame:screenBounds];
            self.carWindow.screen = screen;
            [self.carWindow makeKeyAndVisible];

            // Set the initial UI for the window.
            UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
            UIViewController *rootViewController = [storyboard instantiateViewControllerWithIdentifier:@"VC"];

            self.carWindow.rootViewController = rootViewController;
            self.carWindow = tempCarWindow;

            // Show the window.
            self.carWindow.hidden = NO;

            return;
        }        
    }

    // CarPlay is not connected
    self.carWindow = nil;
}




Some more CarPlay related code in my AppDelegate.m:


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [self updateCarWindow];
    [self setUpScreenConnectionNotificationHandlers];

    return YES;
}

- (void)setUpScreenConnectionNotificationHandlers
{
    NSNotificationCenter *center = [NSNotificationCenter defaultCenter];

    [center addObserver:self selector:@selector(screenDidUpdate:) name:UIScreenDidConnectNotification object:nil];
    [center addObserver:self selector:@selector(screenDidUpdate:) name:UIScreenDidDisconnectNotification object:nil];
}

- (void) screenDidUpdate:(NSNotification*)aNotification
{
    [self updateCarWindow];
}

Hi, i can run Hardware > External Display > CarPlay on XCode, but the connection is with "Iphone Simulation" and i need connect CarPlay screen with real Iphone. Can you Help me?

Regards,

Franco

You will have to have CarPlay app entitlement for development created by Apple, then create a new Provisioning Profile that includes the CarPlay app entitlement.


So did you see your app UI on the Xcode CarPlay simulator?

Some update to this post and my experiments:


1. CarPlay audio apps cannot use UIScreen based approach shown in above updateCarWindow method.

2. If my AppDelegate conforms to MPPlayableContentDataSource and MPPlayableContentDelegate, and if I implement the data source and delegate methods in AppDelegate.m, then I can see my CarPlay UI

Can you advise how you can get the entitlement? I've filled out the form three times on the CarPlay site and its as if goes in to a black hole. No one ever responds. Do you have a suggestion or an esclation point?

After filling out the form (https://developer.apple.com/contact/carplay/), all you have to do is just "Wait". A few weeks later, Apple will contact you, if they decide to let you develop CarPlay app.

I’ve applied two times over the past year or two, but I never hear back from them, not even a “we’re sorry, but no” message. It’s beyond frustrating, and it absolutely feels like a black hole. My music app is no Spotify, but it DOES have hundreds of thousands of active users, as well as tens of thousands of exclusive songs, so it’s not puny either. But it seems like Apple is only interested in the biggest of the big here, only the apps whose absense from CarPlay would upset a significant portion of the userbase. It’s really too bad for us smaller guys.

JacobSyndeo,


My music app is not as big as Spotify either. I am a small guy too. But I did receive the entitlement from the CarPlay team. Just try some more times and see what happen.

Some update to this post: a reference link to adding UI in CarPlay app.


https://stackoverflow.com/questions/45726467/adding-ui-for-carplay-audio-app

Did you get the tab bar working?


<key>UIBrowsableContentSupportsSectionedBrowsing</key>
    <true/>

Yes I did. Starting with iOS 10, CarPlay audio app supports tab bar. Besides setting "UIBrowsableContentSupportsSectionedBrowsing" to YES in Info.plist, you also have to respond to remote control events of MPRemoteCommandCenter. For example:


MPRemoteCommandCenter *remoteCommandCenter = [MPRemoteCommandCenter sharedCommandCenter];

remoteCommandCenter.previousTrackCommand.enabled = YES;
[remoteCommandCenter.previousTrackCommand addTarget:self action:@selector(doSomething)];

remoteCommandCenter.nextTrackCommand.enabled = YES;
[remoteCommandCenter.nextTrackCommand addTarget:self action:@selector(doSomethingElse)];

...............


THen you will see tab bar.

Adding User Interface in CarPlay
 
 
Q