Xamarin 在依赖注入中覆盖 RemoteControlReceived

时间:2021-01-10 04:30:25

标签: c# ios xamarin dependency-injection

我试图覆盖 UIApplication 的 RemoteControlRecieved 方法并收到以下错误:

NSInternalInconsistencyException 原因:只能有一个 UIApplication 实例。

我明白这个问题,但不知道如何解决它。我有一个 StreamingService 类,它实现了 UIApplication 和 IStreaming 接口。我所有的 AVPlayer 功能都在这个类中。 StreamingViewModel 类调用

DependencyService.Get<IStreaming>().Play().

调用此行时,出现上述错误。我不确定如何从 StreamingService 或 StreamingViewModel 类覆盖 RemoteControlRecieved。

非常感谢您对代码示例的任何帮助。

以下课程

public class StreamingViewModel : INotifyPropertyChanged
{
    public bool DisplayPlay { get => !isPlaying; }
    public bool DisplayPauseStop { get => isPlaying; }

    // INotifyPropertyChanged implementation
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    bool isPlaying;
    bool IsPlaying
    {
        get => isPlaying;
        set
        {
            isPlaying = value;
            // Notify the property has changed
            OnPropertyChanged("DisplayPlay");
            OnPropertyChanged("DisplayPauseStop");
        }
    }

    public void Play()
    {
        DependencyService.Get<IStreaming>().Play();
        IsPlaying = true;
    }

    public void Pause()
    {
        DependencyService.Get<IStreaming>().Pause();
        IsPlaying = false;
    }

    public void Stop()
    {
        DependencyService.Get<IStreaming>().Stop();
        IsPlaying = false;
    }

}

流媒体服务类

[assembly: Xamarin.Forms.ExportRenderer(typeof(MainPage), typeof(StreamingService))]
[assembly: Dependency(typeof(StreamingService))]

namespace test.iOS
{
    public class StreamingService : PageRenderer, IStreaming
    {
        AVPlayer player;
        bool isPrepared;
        string dataSource = "https://stream.voxx.pro/radio/8260/radio.mp3";


        public override void ViewDidLoad()
        {
            Console.WriteLine("StreamService ViewDidLoad");
            base.ViewDidLoad();


        }

            public StreamingService()
        {
            Console.WriteLine("StreamService Default Constructor");

        }


        public void Play()
        {


            Console.WriteLine("Play");

            if (!isPrepared || player == null)
                player = AVPlayer.FromUrl(NSUrl.FromString(dataSource));


            //Audio player Notification in lock screen  
            MPNowPlayingInfo nowPlayingInfo;
            nowPlayingInfo = new MPNowPlayingInfo();
            nowPlayingInfo.Artist = "Radio Caravan";
            nowPlayingInfo.Title = "Join The Caravan";

            // Register for receiving controls from lock screen and controlscreen  
            MPNowPlayingInfoCenter.DefaultCenter.NowPlaying = nowPlayingInfo;

            //var command = MPRemoteCommandCenter.Shared;
            //command.PlayCommand.Enabled = true;
            //command.PauseCommand.Enabled = true;


            //command.NextTrackCommand.Enabled = false;
            //command.PreviousTrackCommand.Enabled = false;


            isPrepared = true;
            player.Play();

            base.BecomeFirstResponder();

            //To listen changes in lock screen  
            UIApplication.SharedApplication.BeginReceivingRemoteControlEvents();

        }

        public void Pause()
        {
            player.Pause();
        }

        public void Stop()
        {
            player.Dispose();
            isPrepared = false;
        }


        public override void RemoteControlReceived(UIEvent theEvent)
        {
            Console.WriteLine("Remote Control Received");
            base.RemoteControlReceived(theEvent);

            if (theEvent.Subtype == UIEventSubtype.RemoteControlPause)
            {
                Console.WriteLine("Remote Pause");
                player.Pause();
            }
            else if (theEvent.Subtype == UIEventSubtype.RemoteControlPlay)
            {
                Console.WriteLine("Remote Play");
                player.Play();
            }
        }

    }
}

MainPage.cs

    namespace test
{
    public partial class MainPage : ContentPage
    {
        private StreamingViewModel ViewModel { get { return (StreamingViewModel)this.BindingContext; } }

        public MainPage()
        {
            InitializeComponent();
            On<Xamarin.Forms.PlatformConfiguration.iOS>().SetUseSafeArea(true);

            BindingContext = new StreamingViewModel();
        }

        // Callbacks to images tapped
        private void Play_tapped(object sender, EventArgs e)
        {
            ViewModel.Play();
        }

        private void Pause_tapped(object sender, EventArgs e)
        {
            ViewModel.Pause();
        }

        private void Stop_tapped(object sender, EventArgs e)
        {
            ViewModel.Stop();
        }
    }

}

接口:IStreaming

    public interface IStreaming
{
    void Play();
    void Pause();
    void Stop();
    
}

1 个答案:

答案 0 :(得分:0)

<块引用>

NSInternalInconsistencyException 原因:只能有一个 UIApplication 实例。

您可以自定义 PageRenderer 来覆盖 RemoteControlReceived 方法以检查它是否有效。因为这将使用现有的 UIApplication

关于 isPlaying 属性,您可以使用 Bindable Properties 在 CustomPage 中定义。

关于 Play/Pause/Stop 方法,您可以使用 MessagingCenter 将消息从表单发送到 CustomPageRenderer

例如CustomPage的部分代码如下:

public partial class CustomPage: ContentPage
{
    public CustomPage()
    {
        InitializeComponent();
    }

    public static readonly BindableProperty IsPlayingProperty = BindableProperty.Create("IsPlaying", typeof(bool), typeof(CustomPage), null);

    public bool IsPlaying
    {
        get { return (bool)GetValue(IsPlayingProperty); }
        set { SetValue(IsPlayingProperty, value); }
    }

    public void Play()
    {
        MessagingCenter.Send<object, string>(this, "PlayControl", "Play");
        IsPlaying = true;
    }

    public void Pause()
    {
        MessagingCenter.Send<object, string>(this, "PlayControl", "Pause");
        IsPlaying = false;
    }

    public void Stop()
    {
        MessagingCenter.Send<object, string>(this, "PlayControl", "Stop");
        IsPlaying = false;
    }

}

CustomPageRenderer的部分代码如下:

[assembly: Xamarin.Forms.ExportRenderer(typeof(CustomPage), typeof(CustomPageRenderer))]
namespace XamarinForms20.iOS
{
    public class CustomPageRenderer : PageRenderer
    {
         
        public override void ViewDidLoad()
        {
            base.ViewDidLoad();

            //...

            MessagingCenter.Subscribe<object, string>(this, "PlayControl",  (sender, arg) =>
            {
                if(arg == "Play")
                {
                    //...
                }else if (arg == "Pause")
                {
                    //...
                }else if (arg == "Stop")
                {
                    //...
                }
            });
        }

        public override void RemoteControlReceived(UIEvent theEvent)
        {
            base.RemoteControlReceived(theEvent);

            if (theEvent.Subtype == UIEventSubtype.RemoteControlPlay)
                player.Play();
            else if (theEvent.Subtype == UIEventSubtype.RemoteControlPause)
                player.Pause();
        }
    }
}

====================================更新========== ======================

您可以尝试在 AVAudioSession.InterruptionNotificationNSNotificationCenter 方法中添加 ViewDidload

public override void ViewDidLoad()
...
NSObject _notificationHandle = NSNotificationCenter.DefaultCenter.AddObserver(AVAudioSession.InterruptionNotification, HandleNotification);
...

private void HandleNotification(NSNotification notification)
{
    // Do something
    NSDictionary userinfo = notification.UserInfo;
    NSNumber number = (NSNumber)userinfo.ValueForKey(new NSString("AVAudioSessionInterruptionTypeKey"));
    int value = (int)number.NIntValue;

    if(value == 1)
    {
        // pause
    }else if(value == 0)
    {
        // countinue to play
        AVAudioSession.SharedInstance().SetActive(true);
    }
}