Swift-Radio-Pro icon indicating copy to clipboard operation
Swift-Radio-Pro copied to clipboard

New experimental CarPlay branch ๐Ÿš˜๐Ÿ“ฒ

Open fethica opened this issue 7 years ago โ€ข 22 comments

Hey everyone!

Edit: The CarPlay support is now part of the main project, enabled in the SwiftRaion-CarPlay Target.

~~I created a new branch that supports CarPlay for the SwiftRadio~~

CarPlay SwiftRadio

Also I created a step by step post to show how to implement this feature:

Add CarPlay support to Swift Radio

Cheers ๐ŸŽ‰

fethica avatar Feb 11 '19 04:02 fethica

Yes! Thx

losgranos avatar Feb 11 '19 08:02 losgranos

You don't need a such workaround to make it to work on simulator.

            // Workaround to make the Now Playing working on the simulator:
            // Source: https://stackoverflow.com/questions/52818170/handling-playback-events-in-carplay-with-mpnowplayinginfocenter
            UIApplication.shared.endReceivingRemoteControlEvents()
            UIApplication.shared.beginReceivingRemoteControlEvents()

I have a radios application that support carPlay too and run in simulator without workaround (written in objC).

- (void)playableContentManager:(MPPlayableContentManager *)contentManager initiatePlaybackOfContentItemAtIndexPath:(NSIndexPath *)indexPath completionHandler:(void (^)(NSError * _Nullable))completionHandler {
    
    SHOUTcastAPI *shout = _appDelegate.shoutCastAPI;
    
    NSUInteger indexCount = indexPath.length;
    NSUInteger tabIndex = [indexPath indexAtPosition:[indexPath length] - 1];
    
    Station *station;
    
    if ([indexPath indexAtPosition:0] == 1 && indexCount == 2) { // FAVORITES
        self.stations = [shout getFavoritesStations];
        station = self.stations[tabIndex];
    }
    else if ([indexPath indexAtPosition:0] == 2 && indexCount == 2) { // TOP 500
        station = [shout getTopStationForIndex:tabIndex];
        self.stations = [shout getTopStations];
    }
    else {
        if (indexCount == 3) {
            station = [shout getStationForIndex:tabIndex indexOfGenre:(unsigned long)[indexPath indexAtPosition:1]];
            self.stations = [shout getStationsForIndexOfGenre:(unsigned long)[indexPath indexAtPosition:1]];
        }
        else {
            station = [shout getStationForIndex:tabIndex indexOfSubgenre:[indexPath indexAtPosition:2] indexOfGenre:(unsigned long)[indexPath indexAtPosition:1]];
            self.stations = [shout getStationsForIndexOfSubgenre:(unsigned long)[indexPath indexAtPosition:2] indexOfGenre:(unsigned long)[indexPath indexAtPosition:1]];
        }
    }
    dispatch_async(dispatch_get_main_queue(), ^{
        _station = station;
        [self play];
        
        completionHandler(nil);
    });
    
    // Update MPNowPlayingInfo
    [self updateUIWithTitle:nil andAlbumTitle:nil andArtwork:nil];
}
- (void)updateUIWithTitle:(NSString *)title andAlbumTitle:(NSString *)albumTitle andArtwork:(UIImage *)artworkImage
{
    // UI Update
    dispatch_async(dispatch_get_main_queue(), ^{
                ...
                ...
                NSMutableDictionary *nowPlayingInfo = [[MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo mutableCopy];
                if (!nowPlayingInfo) {
                    nowPlayingInfo = [[NSMutableDictionary alloc] init];
                }
                
                nowPlayingInfo[MPMediaItemPropertyArtist] = _stationLabel.text;
                nowPlayingInfo[MPMediaItemPropertyAlbumTitle] = albumTitle ? albumTitle : JMOLocalizedString(@"Unknown album", @"");
                nowPlayingInfo[MPMediaItemPropertyTitle] = _songLabel.text;
                nowPlayingInfo[MPMediaItemPropertyArtwork] = itemArtwork;
                if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10.0) {
                    nowPlayingInfo[MPNowPlayingInfoPropertyIsLiveStream] = @(1.0);
                    nowPlayingInfo[MPNowPlayingInfoPropertyMediaType] = @(MPNowPlayingInfoMediaTypeAudio);
                }
                nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = self.isPlaying ? @(1.0) : @(0.0);
                nowPlayingInfo[MPNowPlayingInfoPropertyDefaultPlaybackRate] = self.isPlaying ? @(1.0) : @(0.0);
                
                [MPNowPlayingInfoCenter defaultCenter].nowPlayingInfo = nowPlayingInfo;
                ....
    });

MPNowPlayingInfoPropertyPlaybackRate is very important:

The documentation say:

MPNowPlayingInfoCenter Use MPNowPlayingInfoCenter to populate the CarPlay Now Playing screen with information. MPNowPlayingInfoCenter allows you to specify metadata such as title, artist, elapsed time, playback queue, playback rate and album artwork. When running your app in the Simulator, the media playback features are not the same as running on iPhone. On iPhone running CarPlay, the play button in the CarPlay Now Playing screen is automatically managed by iOS and changes state based on whether audio is playing. In contrast, the play button in the Simulator relies on the state of the playback rate in Now Playing Info Center. You should ensure that Now Playing Info Center always has the correct playback rate. When playback is stopped, be sure to set the MPNowPlayingInfoPropertyPlaybackRate property to 0.0. Apple recommends you always supply a MPMediaItemPropertyPersistentID property. If your app has the concept of a playback queue, set MPNowPlayingInfoPropertyPlaybackQueueIndex and MPNowPlayingInfoPropertyPlaybackQueueCount. Starting in iOS 10, this information is shown on the Now Playing screen. If your app plays live streaming content, set MPNowPlayingInfoPropertyIsLiveStream to YES.

iDevelopper avatar Feb 11 '19 12:02 iDevelopper

@fethica is the man! ๐ŸŽ‰๐Ÿ™

analogcode avatar Feb 11 '19 16:02 analogcode

Thanks for the feedback @iDevelopper I will check your code.

fethica avatar Feb 12 '19 02:02 fethica

The best player and the best tutorial for Apple Car Play. I did try blatantly to implement the same by my own a time ago and now seeing your code so clean and detailed only i can say KUDOS! Thanks for share!

urayoanm avatar Feb 12 '19 15:02 urayoanm

@fethica But if we have not a paid account developer, we cannot test it with real phone?? When I opened https://developer.apple.com/contact/carplay/ it said that I have not the permission to view this page ๐Ÿคจ Is there a solution for "free" out there ?

DavidKalajdzic avatar Jun 15 '19 15:06 DavidKalajdzic

@DavidKalajdzic if you can't access the CarPlay form page with a regular account, so I think you have to get a paid developer account!

fethica avatar Jul 16 '19 14:07 fethica

Even with this workaround - UIApplication.shared.endReceivingRemoteControlEvents() UIApplication.shared.beginReceivingRemoteControlEvents()

Nowplaying screen not appearing on the simulator, what could be the reason? Please help.

sarafdar avatar Jul 16 '19 15:07 sarafdar

This works beautifully on XCode 10 but not so on XCode 11.0 beta (11M336w) running iOS 13... Anyone else just get a blue button? Screen Shot 2019-08-14 at 22 24 44

nimisis avatar Aug 14 '19 21:08 nimisis

Yes

iDevelopper avatar Aug 15 '19 03:08 iDevelopper

How can we make carPlayTab colorful instead of blue overlay?

tester89 avatar Aug 15 '19 14:08 tester89

This is an Apple Simulator Bug in Xcode 11 beta. It works fine in a car!

iDevelopper avatar Aug 15 '19 16:08 iDevelopper

This is an Apple Simulator Bug in Xcode 11 beta. It works fine in a car!

Hi, I did try in my Hyundai car CarPlay but it still shows blue icon.

adminholic avatar Aug 17 '19 15:08 adminholic

Please contact Hyundai! I have a BMW and it works fine with my app and with this example!

iDevelopper avatar Aug 18 '19 16:08 iDevelopper

Please contact Hyundai! I have a BMW and it works fine with my app and with this example!

And you being a developer for some reason thought contacting Hyundai will solve the problem? Didn't you said above it was bug in Xcode 11? And I am using latest version of Xcode, not the beta version.

I tried with another CarPlay head unit, its a some problem. I bet your BMW was custom made with stable Xcode installed lol.

adminholic avatar Aug 24 '19 20:08 adminholic

I said it is a bug in Xcode 11 using the example on simulator. Works fine in my car either with Xcode 10 or 11.

iDevelopper avatar Aug 25 '19 09:08 iDevelopper

Works fine using iOS 12, but any version of iOS 13 presents the bugs mentioned above and it is impossible to get it working in the CarPlay simulator.

DanBurkhardt avatar Jan 07 '20 03:01 DanBurkhardt

Hi Fethica, Hope you doing well. I made an navigation app for my apple car play. Its icon and start screen is displaying fine over the carplay simulator but the map is not displaying. Is there any way by which we can show only map directly to carplay screen instead of home screen.

Regards Sj

Sj7800 avatar Jan 30 '20 17:01 Sj7800

Hello,

Just offering insight here: the issue is a bug that Apple needs to fix with iOS 13 and CarPlay in the simulator.

Instead of using an iOS 13 simulator, choose an iOS 12 simulator and it should work.

On Jan 30, 2020, at 11:08 AM, Swapangeet [email protected] wrote:

๏ปฟ Hi Fethica, Hope you doing well. I made an navigation app for my apple car play. Its icon and start screen is displaying fine over the carplay simulator but the map is not displaying. Is there any way by which we can show only map directly to carplay screen instead of home screen.

Regards Sj

โ€” You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

DanBurkhardt avatar Jan 30 '20 18:01 DanBurkhardt

Hello, Just offering insight here: the issue is a bug that Apple needs to fix with iOS 13 and CarPlay in the simulator. Instead of using an iOS 13 simulator, choose an iOS 12 simulator and it should work. โ€ฆ On Jan 30, 2020, at 11:08 AM, Swapangeet @.***> wrote: ๏ปฟ Hi Fethica, Hope you doing well. I made an navigation app for my apple car play. Its icon and start screen is displaying fine over the carplay simulator but the map is not displaying. Is there any way by which we can show only map directly to carplay screen instead of home screen. Regards Sj โ€” You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

Dan can we run both on same machine or we should remove one of it as the later version will ask for update. Thanks

Sj7800 avatar Jan 30 '20 19:01 Sj7800