How to make NowPlay screen in CarPlay Xamarin.iOS? and How to set nowPlayingIdentifiers property in MPPlayableContentManager?

Viewed 296

I have created Audio App in Xamarin.Forms, for playing audio I have used MediaManager plugin.

Now I want to make it compatible with CarPlay.

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).

I have used all required CarPlay api for audio app but, the problem is:

  • Not getting now playing screen in CarPlay simulator.
  • How to set ArtWork in MPContentItem ?

MPPlayableContentDelegate class

public class PlayableContentDelegate : MPPlayableContentDelegate
{
    public override void PlayableContentManager(MPPlayableContentManager contentManager, NSIndexPath indexPath, Action<NSError> completionHandler)
    {
        DispatchQueue.MainQueue.DispatchAsync(() =>
        {
            UIApplication.SharedApplication.BeginReceivingRemoteControlEvents();
            completionHandler(null);
            UIApplication.SharedApplication.EndReceivingRemoteControlEvents();

            UIApplication.SharedApplication.BeginReceivingRemoteControlEvents();
        });
    }

    [Export("playableContentManager:initiatePlaybackOfContentItemAtIndexPath:completionHandler:")]
    public override void InitiatePlaybackOfContentItem(MPPlayableContentManager contentManager, NSIndexPath indexPath, Action<NSError> completionHandler)
    {
        try
        {
            DispatchQueue.MainQueue.DispatchAsync(() =>
            {
                UIApplication.SharedApplication.BeginReceivingRemoteControlEvents();

                var itemToPlay = BaseSettingsService.CurrentPlayList[indexPath.Row];
                var NowPlayingInfoCenter = MPNowPlayingInfoCenter.DefaultCenter;

                MPNowPlayingInfo playingInfo = new MPNowPlayingInfo();
                playingInfo.Title = itemToPlay.Title;
                playingInfo.Artist = itemToPlay.Editor;
                playingInfo.AlbumTitle = "1989";
                playingInfo.Genre = "Pop";
                playingInfo.PlaybackDuration = 231;
                playingInfo.PlaybackRate = 22;
                playingInfo.PersistentID = (ulong)111111;
                playingInfo.PlaybackQueueIndex = 3;
                playingInfo.PlaybackQueueCount = BaseSettingsService.CurrentPlayList.Count;
                playingInfo.IsLiveStream = false;
                playingInfo.MediaType = MPNowPlayingInfoMediaType.Audio;
                NowPlayingInfoCenter.NowPlaying = playingInfo;

                var id = itemToPlay.PodcastId.ToString();
                string[] s1 = new string[1];
                s1[0] = id;

                contentManager.NowPlayingIdentifiers = s1;

                completionHandler(null);

                UIApplication.SharedApplication.EndReceivingRemoteControlEvents();
            });
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
        }
    }

    public override nuint RetainCount { get; }

    public override void ContextUpdated(MPPlayableContentManager contentManager, MPPlayableContentManagerContext context)
    {
        try
        {
            //base.ContextUpdated(contentManager, context);
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
        }
    }

    public override NSDictionary GetDictionaryOfValuesFromKeys(NSString[] keys)
    {
        return base.GetDictionaryOfValuesFromKeys(keys);
    }
}

MPPlayableContentDataSource

public class AppDelegateDataSource : MPPlayableContentDataSource
{
    public override MPContentItem ContentItem(NSIndexPath indexPath)
    {
        if (indexPath.Length == 1)
        {
            var item = new MPContentItem("PlayList");
            item.Title = "PlayList";
            item.Subtitle = "Hello";
            item.Container = true;
            item.Playable = false;
            return item;
        }
        else
        {
            var play = CurrentPlayList[indexPath.Row];
            var item = new MPContentItem(play.PodcastId);
            item.Title = play.Title;
            item.Subtitle = play.Editor;
            item.Playable = true;
            return item;
        }
    }

    public override nint NumberOfChildItems(NSIndexPath indexPath)
    {
        if (indexPath.GetIndexes().Length == 0)
            return 1;
        else
            return CurrentPlayList.Count;
    }
}

So, the question is How should I respond to playable items now?

Anyone know what I'm missing or which mistake I have to correct? Any help would be appreciated, thanks.

1 Answers

To get the NowPlaying screen you have to set two things without fail.

  1. MPRemoteCommandCenter
var commandCenter = MPRemoteCommandCenter.Shared;
commandCenter.PlayCommand.Enabled = true;
commandCenter.StopCommand.Enabled = true;
  1. MPPlayableContentManager.NowPlayingIdentifiers
var urlId = "11111";
string[] identifier = new string[1];
identifier[0] = urlId;

contentManager = MPPlayableContentManager.Shared;
contentManager.NowPlayingIdentifiers = identifier;
Related