8

I am working on my current iPhone audio app to be supported in CarPlay. I already got approved by Apple and received the development entitlement, 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
}

I re-wrote it to an Objective-C version like following:

- (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; 
}  

However I found that the property "screens" of UIScreen always return 1 element (the main screen), no matter when testing on a real device or simulator. So when my app is running on the simulator or a real car with CarPlay system, the app is just blank and said "Unable to connect to "My App name"" (see the image below). My ViewController has a simple UILabel though.

enter image description here

My question is: what should I do to make my app to be connected by CarPlay? That is, how should I obtain the screen that has UIUserInterfaceIdiomCarPlay idiom, not just always the main screen? Thanks a lot in advance.

stspb
  • 193
  • 2
  • 12
  • 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. – stspb Aug 07 '17 at 07:08

2 Answers2

5

CarPlay audio apps are controlled by the MPPlayableContentManager. You are required to implement the MPPlayableContentDelegate and MPPlayableContentDatasource protocol in order to connect with CarPlay. The UI is controlled by CarPlay - all you need to do is feed it data for tabs+tables (datasource) and respond to playable items (delegate).

Billy Caruso
  • 149
  • 11
  • Thanks for your comments, Billy. CarPlay audio apps cannot use UIScreen based approach shown in the WWDC 2017 video. This is why my CarPlay app doesn't see any UI. – stspb Aug 02 '17 at 08:05
  • Still have a question: To build CarPlay UI, I should use MPPlayableContentManager APIs (MPPlayableContentDataSource & MPPlayableContentDelegate) in a class which is a subclass of NSObject, then instantiate and initialize that NSObject subclass in the method -application:didFinishLaunchingWithOptions: of AppDelegate.m. Is this correct? Thanks again. – stspb Aug 02 '17 at 08:19
  • Yes - you can initialize this class anywhere. application:didFinishLaunchingWithOptions is a good choice if you want CarPlay available for all users. Make sure your NSObject subclass also subclasses `MPPlayableContentDataSource` & `MPPlayableContentDelegate`. – Billy Caruso Aug 02 '17 at 14:35
  • Billy, did you mean the NSObject subclass conforms to MPPlayableContentDataSource & MPPlayableContentDelegate protocols, or subclasses MPPlayableContentDataSource & MPPlayableContentDelegate ? Thank you. – stspb Aug 02 '17 at 16:34
  • Conform to the protocol. https://www.objc.io/issues/13-architecture/subclassing/#alternative-protocols – Billy Caruso Aug 03 '17 at 16:13
  • 1
    Thanks, Billy. I created an NSObject subclass (CarPlayDemo) conforming to MPPlayableContentDataSource & MPPlayableContentDelegat. I assigned the dataSource and delegate properties of MPPlayableContentManager in -init method of CarPlayDemo.m, and implemented MPPlayableContentDataSource required methods -numberOfChildItemsAtIndexPath: and -contentItemAtIndexPath: in CarPlayDemo.m as well (but I haven’t implemented MPPlayableContentDelegat methods yet). However I found that MPPlayableContentDataSource methods never got called. Any idea with that? Thanks again. – stspb Aug 04 '17 at 10:41
  • @BillyCaruso Do you have any sample code to implement contentItemAtIndexPath to return MPContentItem. – Dinesh Kumar Dec 07 '18 at 07:23
  • @BillyCaruso As of iOS 14 I see in Apple's documentation, "Starting with iOS 14, CarPlay audio apps may use the CarPlay framework to present a customized user interface. CarPlay audio apps that use the CarPlay framework must include the com.apple.developer.carplay-audio entitlement." Do you know if your answer is still the only case? I don't see any instructions on how to create the custom UI it mentions. – SolidSnake4444 Mar 04 '22 at 23:39
2

Custom UI is only available for CarPlay navigation apps. For audio apps, the MediaPlayer framework contains all the necessary API to work with CarPlay.

DrMickeyLauer
  • 4,455
  • 3
  • 31
  • 67
  • 1
    hi @DrMicketLaurer I have my own navigation app which uses GLKitView (using OpenGL ES) to draw my app and show the turn-by-turn navigation there. Can I put this in the map template? – iadcialim24 Jul 26 '21 at 08:31
  • 1
    @iori24 Yes, this is allowed. When/If you get an entitlement for CarPlay Map development, you can do that. – DrMickeyLauer Jul 30 '21 at 14:33