Xamarin.Forms:如何实现锁定屏幕播放器控件,以便视频播放器在屏幕锁定时播放音频

nbnkbykc  于 2022-12-07  发布在  其他
关注(0)|答案(1)|浏览(151)

我有一个Xamarin.Forms应用程序,它有一个视频播放器,我需要在两个平台上为音频播放器实现锁屏播放器控件(用户可以在屏幕锁定时收听音频,也可以在锁屏时播放/暂停)。
我已经实现了这是Xamarin.ios

var audioSession = AVAudioSession.SharedInstance();
audioSession.SetCategory(AVAudioSessionCategory.Playback);
audioSession.SetActive(true);

我在android中实现这个有点困难。我是初级的,需要一点跳跃式的开始。
感谢您抽出时间,非常感谢。祝您愉快!
下面是我的视频播放器渲染器

public class VideoPlayerRenderer : ViewRenderer<VideoPlayer, ARelativeLayout>
    {
        public static VideoView VideoView;
        private MediaController mediaController;    // Used to display transport controls
        private bool IsPrepared;
        private readonly Context Context;
        private Android.Widget.ProgressBar ProgressBar;
        private bool HasScrollView = false;
        private ImageView ImageView;
        private ARelativeLayout.LayoutParams LayoutParam;
        public event EventHandler<bool> FullScreenStatusChanged;
        public static DeviceTimer deviceTimer;
        private string uri;
        private readonly TVVideoTVService TVVideoTvLoggingUpdate = new TVVideoTVService();
        public static bool IsUserclickedFullscreen;
        public static int SeekTimeBack = 0;
        public static bool IsUserSeekedPrgressedBar = true;
        public TVVideoTVLoggingRequest TVVideoTVLoggingRequest;
        public System.Threading.Timer timer;

        public VideoPlayerRenderer(Context context) : base(context)
        {
            Context = context;
            MessagingCenter.Subscribe<string>("TVVideoTV", "StopAndoridTimer", (sender) =>
            {
                if (deviceTimer != null)
                    deviceTimer.Stop();
            });
        }

        private void InitProgressBar()
        {
            try
            {
                ProgressBar = new Android.Widget.ProgressBar(Context)
                {
                    Indeterminate = false,
                    Visibility = Android.Views.ViewStates.Invisible
                };
                var lparams = new ARelativeLayout.LayoutParams(5, 5);
                lparams.AddRule(LayoutRules.EndOf);
                Control.AddView(ProgressBar, lparams);
            }
            catch (Exception ex)
            {
                var properties = new Dictionary<string, string>
                {
                    { "Location", "Method - InitProgressBar , class - VideoPlayerRenderer" },
                    { "Error", ex.ToString() },
                };
                Crashes.TrackError(new Exception(), properties);

                throw;
            }
        }

        protected override void OnElementChanged(ElementChangedEventArgs<VideoPlayer> args)
        {
            var extraInfo = new TVVideoTVLoggingRequest();

            try
            {
                base.OnElementChanged(args);

                if (args.NewElement != null)
                {
                    if (Control == null)
                    {

                        // Save the VideoView for future reference
                        VideoView = new VideoView(Context);

                        // Put the VideoView in a RelativeLayout
                        var relativeLayout = new ARelativeLayout(Context);
                        relativeLayout.AddView(VideoView);

                        // Center the VideoView in the RelativeLayout
                        LayoutParam = new ARelativeLayout.LayoutParams(LayoutParams.MatchParent, LayoutParams.MatchParent);
                        LayoutParam.AddRule(LayoutRules.CenterInParent);
                        VideoView.LayoutParameters = LayoutParam;

                        // Handle a VideoView event
                        VideoView.Prepared += OnVideoViewPrepared;

                        SetNativeControl(relativeLayout);
                    }

                    //initialize the Uri to video player 
                    SetAreTransportControlsEnabled();
                    InitProgressBar();
                    SetSource();

                    args.NewElement.UpdateStatus += OnUpdateStatus;
                    args.NewElement.PlayRequested += OnPlayRequested;
                    args.NewElement.PauseRequested += OnPauseRequested;
                    args.NewElement.StopRequested += OnStopRequested;
                }

                if (args.OldElement != null)
                {
                    args.OldElement.UpdateStatus -= OnUpdateStatus;
                    args.OldElement.PlayRequested -= OnPlayRequested;
                    args.OldElement.PauseRequested -= OnPauseRequested;
                    args.OldElement.StopRequested -= OnStopRequested;
                }

                // seek event for android
                VideoView.SetOnPreparedListener(new PreparedListener(mediaController));
                //Loging end of video
                VideoView.Completion += async delegate
                {
                    deviceTimer.Stop();
                    extraInfo = await LoggingTVVideoTVActivity((int)CPDLoggingType.VideoEnd);
                };
                //Loging Errors of video
                VideoView.Error += async (Error_obj, Error_args) =>
                {
                    var extraInfo = await LoggingTVVideoTVActivity((int)CPDLoggingType.VideoError, Newtonsoft.Json.JsonConvert.SerializeObject(Error_args));
                    var properties = new Dictionary<string, string>
                    {
                        { "Location", "Method - OnElementChanged , Class - VideoPlayerRender" },
                        { "MoreInfo",Newtonsoft.Json.JsonConvert.SerializeObject(extraInfo)}
                    };
                    Crashes.TrackError(new Exception(), properties);
                };

                InitializeFullScreenCapability();
            }
            catch (Exception ex)
            {
                var properties = new Dictionary<string, string>
                {
                    { "Location", "Method - OnPlayRequested , class - VideoPlayerRenderer" },
                    { "Error", ex.ToString() },
                    { "MoreInfo",Newtonsoft.Json.JsonConvert.SerializeObject(extraInfo)}
                };
                Crashes.TrackError(new Exception(), properties);
                throw;
            }
        }

        private void OnPauseRequested(object sender, EventArgs e)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// initalize the fullscreen
        /// </summary>
        private void InitializeFullScreenCapability()
        {
            try
            {
                Xamarin.Forms.Element view = Element;
                while (view.Parent != null)
                {
                    view = view.Parent;
                    if (view is Xamarin.Forms.ScrollView)
                    {
                        HasScrollView = true;
                        break;
                    }
                }
                //initialize fullscreen button
                ImageView = new ImageView(Context) { };
                ImageView.SetImageResource(App.Droid.Resource.Drawable.fullscreen);
                ImageView.SetPadding(0, 30, 30, 0);
                var lv = new ARelativeLayout.LayoutParams(80, 80);
                lv.AddRule(LayoutRules.AlignParentRight);
                ImageView.LayoutParameters = lv;
                Control.AddView(ImageView);

                //creating the click event for full screen
                ImageView.Click += delegate
                {
                    FullScreen(HasScrollView);
                };
            }
            catch (Exception ex)
            {
                var properties = new Dictionary<string, string>
                {
                    { "Location", "Method - InitializeFullScreenCapability , class - VideoPlayerRenderer" },
                    { "Error", ex.ToString() },
                };
                Crashes.TrackError(new Exception(), properties);
                throw;
            }
        }

        /// <summary>
        /// move to full screen view 
        /// </summary>
        /// <param name="resizeLayout"></param>
        private void FullScreen(bool resizeLayout = false)
        {
            try
            {
                LoggingTVVideoTVActivity((int)CPDLoggingType.VideoFullscreen);
                VideoView.Pause();
                deviceTimer.Stop();
                IsUserclickedFullscreen = true;
                var intent = new Intent(MainActivity.Instance, typeof(FullScreen));
                intent.PutExtra("uri", uri);
                intent.PutExtra("seek", VideoView.CurrentPosition);
                MainActivity.Instance.StartActivity(intent);
            }
            catch (Exception ex)
            {
                var properties = new Dictionary<string, string>
                {
                    { "Location", "Method - FullScreen , class - VideoPlayerRenderer" },
                    { "Error", ex.ToString() },
                };
                Crashes.TrackError(new Exception(), properties);
                throw;
            }
        }

        // this mathod Handle that wraps your unmanaged resource
        protected override void Dispose(bool disposing)
        {
            if (Control != null && VideoView != null)
            {
                VideoView.Prepared -= OnVideoViewPrepared;
            }
            if (Element != null)
            {
                Element.UpdateStatus -= OnUpdateStatus;
            }

            base.Dispose(disposing);
        }

        /// <summary>
        /// seekbar setup for video
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        public void OnVideoViewPrepared(object sender, EventArgs args)
        {
            try
            {
                ProgressBar.Visibility = Android.Views.ViewStates.Invisible;
                IsPrepared = true;
                if (SeekTimeBack != 0)
                {
                    IsUserSeekedPrgressedBar = false;
                    VideoView.SeekTo(SeekTimeBack);
                    VideoView.Start();
                }

                var seekbarId = mediaController.Resources.GetIdentifier("mediacontroller_progress", "id", "android");
                var seekBar = mediaController.FindViewById<SeekBar>(seekbarId);
                ((IVideoPlayerController)Element).Duration = TimeSpan.FromMilliseconds(VideoView.Duration);
            }
            catch (Exception ex)
            {
                var properties = new Dictionary<string, string>
                {
                    { "Location", "Method - OnVideoViewPrepared , class - VideoPlayerRenderer" },
                    { "Error", ex.ToString() },
                };
                Crashes.TrackError(new Exception(), properties);

                throw;
            }
        }

        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs args)
        {
            try
            {
                base.OnElementPropertyChanged(sender, args);

                if (args.PropertyName == VideoPlayer.AreTransportControlsEnabledProperty.PropertyName)
                {
                    SetAreTransportControlsEnabled();
                }
                else if (args.PropertyName == VideoPlayer.SourceProperty.PropertyName)
                {
                    SetSource();
                }
                else if (args.PropertyName == VideoPlayer.PositionProperty.PropertyName)
                {
                    //this mathod  move the seek button over the seek bar
                    if (Math.Abs(VideoView.CurrentPosition - Element.Position.TotalMilliseconds) > 1000)
                    {
                        VideoView.SeekTo((int)Element.Position.TotalMilliseconds);
                    }
                }
            }
            catch (Exception ex)
            {
                var properties = new Dictionary<string, string>
                {
                    { "Location", "Method - OnElementPropertyChanged , class - VideoPlayerRenderer" },
                    { "Error", ex.ToString() },
                };
                Crashes.TrackError(new Exception(), properties);

                throw;
            }
        }

        /// <summary>
        /// initialize the all controllers example playbutton and progres bar
        /// </summary>
        public void SetAreTransportControlsEnabled()
        {
            try
            {
                if (Element.AreTransportControlsEnabled)
                {
                    mediaController = new MediaController(Context);
                    mediaController.SetMediaPlayer(VideoView);
                    VideoView.SetMediaController(mediaController);
                }
                else
                {
                    VideoView.SetMediaController(null);

                    if (mediaController != null)
                    {
                        mediaController.SetMediaPlayer(null);
                        mediaController = null;
                    }
                }
            }
            catch (Exception ex)
            {
                var properties = new Dictionary<string, string>
                {
                    { "Location", "Method - SetAreTransportControlsEnabled , class - VideoPlayerRenderer" },
                    { "Error", ex.ToString() },
                };
                Crashes.TrackError(new Exception(), properties);

                throw;
            }
        }

        /// <summary>
        /// bindig source for TVVideoTV
        /// </summary>
        public void SetSource()
        {
            try
            {
                IsPrepared = false;
                var hasSetSource = false;

                // currenty we use this  --- 
                if (Element.Source is UriVideoSource)
                {
                    uri = (Element.Source as UriVideoSource).Uri;

                    if (!string.IsNullOrWhiteSpace(uri))
                    {
                        VideoView.SetVideoURI(Android.Net.Uri.Parse(uri));
                        hasSetSource = true;
                    }
                }
                else if (Element.Source is FileVideoSource)
                {
                    var filename = (Element.Source as FileVideoSource).File;

                    if (!string.IsNullOrWhiteSpace(filename))
                    {
                        VideoView.SetVideoPath(filename);
                        hasSetSource = true;
                    }
                }

                if (hasSetSource && Element.AutoPlay)
                {
                    VideoView.Start();
                }
            }
            catch (Exception ex)
            {
                var properties = new Dictionary<string, string>
                {
                    { "Location", "Method - SetSource , class - VideoPlayerRenderer" },
                    { "Error", ex.ToString() },
                };
                Crashes.TrackError(new Exception(), properties);

                throw;
            }
        }

        /// <summary>
        /// Event handler to update status
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        public void OnUpdateStatus(object sender, EventArgs args)
        {
            try
            {
                var status = VideoStatus.NotReady;
                if (IsPrepared)
                {
                    status = VideoView.IsPlaying ? VideoStatus.Playing : VideoStatus.Paused;
                }

                ((IVideoPlayerController)Element).Status = status;

                // Set Position property
                var timeSpan = TimeSpan.FromMilliseconds(VideoView.CurrentPosition);
                ((IElementController)Element).SetValueFromRenderer(VideoPlayer.PositionProperty, timeSpan);
            }
            catch (Exception ex)
            {
                var properties = new Dictionary<string, string>
                {
                    { "Location", "Method - OnUpdateStatus , class - VideoPlayerRenderer" },
                    { "Error", ex.ToString() },
                };
                Crashes.TrackError(new Exception(), properties);

                throw;
            }
        }

        /// <summary>
        /// logging the play and pause activities
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        public async void OnPlayRequested(object sender, EventArgs args)
        {
            var extraInfo = new TVVideoTVLoggingRequest();
            try
            {
                if (VideoView.IsPlaying)
                {
                    VideoView.Pause();
                    extraInfo = await LoggingTVVideoTVActivity((int)CPDLoggingType.VideoPause);
                    deviceTimer.Stop();
                }
                else
                {
                    VideoView.Start();
                    deviceTimer = new DeviceTimer(TimeSpan.FromSeconds(300), () => LoggingTVVideoTVActivity((int)CPDLoggingType.VideoPlay));
                    deviceTimer.Start();
                    extraInfo = await LoggingTVVideoTVActivity((int)CPDLoggingType.VideoPlay);
                }
            }
            catch (Exception ex)
            {
                var properties = new Dictionary<string, string>
                {
                    { "Location", "Method - OnPlayRequested , class - VideoPlayerRenderer" },
                    { "Error", ex.ToString() },
                    { "MoreInfo",Newtonsoft.Json.JsonConvert.SerializeObject(extraInfo)}
                };
                Crashes.TrackError(new Exception(), properties);

                throw;
            }
        }

        /// <summary>
        /// detect onstop and loging
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        public async void OnStopRequested(object sender, EventArgs args)
        {
            var extraInfo = new TVVideoTVLoggingRequest();
            try
            {
                VideoView.StopPlayback();
                extraInfo = await LoggingTVVideoTVActivity((int)CPDLoggingType.VideoStop);
            }
            catch (Exception ex)
            {
                var properties = new Dictionary<string, string>
                {
                    { "Location", "Method - OnStopRequested , class - VideoPlayerRenderer" },
                    { "Error", ex.ToString() },
                    { "MoreInfo",Newtonsoft.Json.JsonConvert.SerializeObject(extraInfo)}
                };
                Crashes.TrackError(new Exception(), properties);

                throw;
            }
        }
        /// <summary>
        /// Logging TVVideoTV activity in by loggingTypeID
        /// </summary>
        /// <param name="loggingTypeID"></param>
        public async Task<TVVideoTVLoggingRequest> LoggingTVVideoTVActivity(int loggingTypeID, string extraInfo = "")
        {
            var itemTime = VideoView.CurrentPosition;

            //Prevents CPD video play logging current position as 0.0 in full screen view. 
            //This check "itemTime == 0.0" added when video is in full screen view, normal video view is returning current position as 0.0
            if (itemTime == 0.0 && CustomVideoView.mListener != null)
            {
                itemTime = CustomVideoView.mListener.CurrentPosition; //Helps to get the current position from Full screen video view.
            }

            var request = new TVVideoTVLoggingRequest()
            {
                CPDLoggingTypeID = loggingTypeID,
                ItemID = TVVideoTVModalViewModel.TVVideoTV.EventID,
                ItemTitle = TVVideoTVModalViewModel.TVVideoTV.Title,
                ItemTime = itemTime * 0.001f, //convert time to seconds from ms 
                Extra = "Video ID -> " + TVVideoTVModalViewModel.TVVideoTV.VideoPlayerCode + " Extra info -> " + extraInfo
            };

            _ = await TVVideoTvLoggingUpdate.TVVideoTVLoggingUpdate(request);

            return request; // only returns for send logs to app center
        }

    }

感谢您抽出时间,非常感谢。祝您愉快!

hivapdat

hivapdat1#

你可以检查这个link。这是一个由Xamarin官方编写的MediaManager插件。
另外,你也可以引用this,这是在Xamarin Forms内调用Locker.Activate()的一种方法,就是使用Dependency Service

相关问题