如果应用程序处于后台模式,如何播放声音
how to play sound if app is in background mode
我在 Xamarin.Forms 中开发了 iOS 应用程序。如何在应用程序处于最小化模式时播放声音?
有人可以给出任何提示或示例吗?
提前致谢。
维维克
class musicPlayer {
public static var instance = musicPlayer()
var player = AVPlayer()
func initPlayer(url : String) {
guard let url = URL.init(string: url) else { return }
let playerItem = AVPlayerItem.init(url: url)
player = AVPlayer.init(playerItem: playerItem)
playAudioBackground()
}
func playAudioBackground() {
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, mode: AVAudioSessionModeDefault, options: [.mixWithOthers, .allowAirPlay])
print("Playback OK")
try AVAudioSession.sharedInstance().setActive(true)
print("Session is Active")
} catch {
print(error)
}
}
func pause(){
player.pause()
}
func play() {
player.play()
}
}
在Xamarin iOS中需要先在项目的Capabilities中设置开启info.plist
后台模式
然后你需要在AppDelegate.cs
中添加以下代码:
public bool FinishedLaunching (UIApplication application, NSDictionary launchOptions)
{
// Override point for customization after application launch.
// If not required for your application you can safely delete this method
AVAudioSession session = AVAudioSession.SharedInstance();
session.SetCategory(AVAudioSessionCategory.Playback);
session.SetActive(true);
return true;
}
然后你可以通过AVPlayer创建一个示例音频播放器:
public partial class ViewController : UIViewController
{
public AVAudioPlayer player;
public float MusicVolume
{
get;
set;
} = 0.5f;
public bool MusicOn
{
get;
set;
} = true;
public ViewController (IntPtr handle) : base (handle)
{
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// Perform any additional setup after loading the view, typically from a nib.
}
public override void DidReceiveMemoryWarning ()
{
base.DidReceiveMemoryWarning ();
// Release any cached data, images, etc that aren't in use.
}
partial void UIButtonPlay_TouchUpInside(UIButton sender)
{
//throw new NotImplementedException();
Console.WriteLine("play");
PlayMusic();
}
public void PlayMusic()
{
NSUrl songURL;
if (!MusicOn) return;
//Song url from your local Resource
songURL = new NSUrl("Sounds/Alan_Walker.mp3");
NSError err;
player = new AVAudioPlayer(songURL, "Song", out err);
player.Volume = MusicVolume;
player.FinishedPlaying += delegate {
// backgroundMusic.Dispose();
player = null;
};
//Background Music play
player.Play();
}
partial void UIButtonStop_TouchUpInside(UIButton sender)
{
//throw new NotImplementedException();
Console.WriteLine("stop");
player.Stop();
}
public override void RemoteControlReceived(UIEvent theEvent)
{
base.RemoteControlReceived(theEvent);
Console.WriteLine("RemoteControlReceived");
switch (theEvent.Subtype)
{
case UIEventSubtype.RemoteControlPlay:
//play the music
Console.WriteLine("Remote Play"); player.Play();
break;
case UIEventSubtype.RemoteControlPause:
//pause the music
Console.WriteLine("Remote Stop"); player.Stop();
break;
case UIEventSubtype.RemoteControlNextTrack:
//play next one
break;
case UIEventSubtype.RemoteControlPreviousTrack:
//play last one
break;
dafault:
break;
}
}
}
最后,可以在DidEnterBackground
和DidBecomeActive
时添加背景控件。从 iOS 13 开始,这些生命周期方法已从 AppDelegate
移至 SceneDelegate
.
public class SceneDelegate : UIResponder, IUIWindowSceneDelegate
{
[Export("window")]
public UIWindow Window { get; set; }
[Export("scene:willConnectToSession:options:")]
public void WillConnect(UIScene scene, UISceneSession session, UISceneConnectionOptions connectionOptions)
{
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see UIApplicationDelegate `GetConfiguration` instead).
}
[Export("sceneDidDisconnect:")]
public void DidDisconnect(UIScene scene)
{
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not neccessarily discarded (see UIApplicationDelegate `DidDiscardSceneSessions` instead).
}
[Export("sceneDidBecomeActive:")]
public void DidBecomeActive(UIScene scene)
{
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
UIApplication.SharedApplication.EndReceivingRemoteControlEvents();
}
[Export("sceneWillResignActive:")]
public void WillResignActive(UIScene scene)
{
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
[Export("sceneWillEnterForeground:")]
public void WillEnterForeground(UIScene scene)
{
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
[Export("sceneDidEnterBackground:")]
public void DidEnterBackground(UIScene scene)
{
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
UIApplication.SharedApplication.BeginReceivingRemoteControlEvents();
SetLockInfo();
}
public void SetLockInfo()
{
//NSMutableDictionary songInfo = new NSMutableDictionary();
MPNowPlayingInfo playInfo = new MPNowPlayingInfo();
//image
MPMediaItemArtwork albumArt = new MPMediaItemArtwork(new UIImage());
playInfo.Artwork = albumArt;
//title
playInfo.Title = "your song name";
//singer
playInfo.Artist = "singer name";
//rate
playInfo.PlaybackRate = 1.0;
//current time
playInfo.ElapsedPlaybackTime = 0;
//durtaion
playInfo.PlaybackDuration = 2.35; // the durtaion of the song
MPNowPlayingInfoCenter.DefaultCenter.NowPlaying = playInfo;
}
}
进入后台时,需要将当前音频信息传递给MPNowPlayingInfoCenter。
我在 Xamarin.Forms 中开发了 iOS 应用程序。如何在应用程序处于最小化模式时播放声音?
有人可以给出任何提示或示例吗?
提前致谢。
维维克
class musicPlayer {
public static var instance = musicPlayer()
var player = AVPlayer()
func initPlayer(url : String) {
guard let url = URL.init(string: url) else { return }
let playerItem = AVPlayerItem.init(url: url)
player = AVPlayer.init(playerItem: playerItem)
playAudioBackground()
}
func playAudioBackground() {
do {
try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, mode: AVAudioSessionModeDefault, options: [.mixWithOthers, .allowAirPlay])
print("Playback OK")
try AVAudioSession.sharedInstance().setActive(true)
print("Session is Active")
} catch {
print(error)
}
}
func pause(){
player.pause()
}
func play() {
player.play()
}
}
在Xamarin iOS中需要先在项目的Capabilities中设置开启info.plist
后台模式
然后你需要在AppDelegate.cs
中添加以下代码:
public bool FinishedLaunching (UIApplication application, NSDictionary launchOptions)
{
// Override point for customization after application launch.
// If not required for your application you can safely delete this method
AVAudioSession session = AVAudioSession.SharedInstance();
session.SetCategory(AVAudioSessionCategory.Playback);
session.SetActive(true);
return true;
}
然后你可以通过AVPlayer创建一个示例音频播放器:
public partial class ViewController : UIViewController
{
public AVAudioPlayer player;
public float MusicVolume
{
get;
set;
} = 0.5f;
public bool MusicOn
{
get;
set;
} = true;
public ViewController (IntPtr handle) : base (handle)
{
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// Perform any additional setup after loading the view, typically from a nib.
}
public override void DidReceiveMemoryWarning ()
{
base.DidReceiveMemoryWarning ();
// Release any cached data, images, etc that aren't in use.
}
partial void UIButtonPlay_TouchUpInside(UIButton sender)
{
//throw new NotImplementedException();
Console.WriteLine("play");
PlayMusic();
}
public void PlayMusic()
{
NSUrl songURL;
if (!MusicOn) return;
//Song url from your local Resource
songURL = new NSUrl("Sounds/Alan_Walker.mp3");
NSError err;
player = new AVAudioPlayer(songURL, "Song", out err);
player.Volume = MusicVolume;
player.FinishedPlaying += delegate {
// backgroundMusic.Dispose();
player = null;
};
//Background Music play
player.Play();
}
partial void UIButtonStop_TouchUpInside(UIButton sender)
{
//throw new NotImplementedException();
Console.WriteLine("stop");
player.Stop();
}
public override void RemoteControlReceived(UIEvent theEvent)
{
base.RemoteControlReceived(theEvent);
Console.WriteLine("RemoteControlReceived");
switch (theEvent.Subtype)
{
case UIEventSubtype.RemoteControlPlay:
//play the music
Console.WriteLine("Remote Play"); player.Play();
break;
case UIEventSubtype.RemoteControlPause:
//pause the music
Console.WriteLine("Remote Stop"); player.Stop();
break;
case UIEventSubtype.RemoteControlNextTrack:
//play next one
break;
case UIEventSubtype.RemoteControlPreviousTrack:
//play last one
break;
dafault:
break;
}
}
}
最后,可以在DidEnterBackground
和DidBecomeActive
时添加背景控件。从 iOS 13 开始,这些生命周期方法已从 AppDelegate
移至 SceneDelegate
.
public class SceneDelegate : UIResponder, IUIWindowSceneDelegate
{
[Export("window")]
public UIWindow Window { get; set; }
[Export("scene:willConnectToSession:options:")]
public void WillConnect(UIScene scene, UISceneSession session, UISceneConnectionOptions connectionOptions)
{
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see UIApplicationDelegate `GetConfiguration` instead).
}
[Export("sceneDidDisconnect:")]
public void DidDisconnect(UIScene scene)
{
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not neccessarily discarded (see UIApplicationDelegate `DidDiscardSceneSessions` instead).
}
[Export("sceneDidBecomeActive:")]
public void DidBecomeActive(UIScene scene)
{
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
UIApplication.SharedApplication.EndReceivingRemoteControlEvents();
}
[Export("sceneWillResignActive:")]
public void WillResignActive(UIScene scene)
{
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
[Export("sceneWillEnterForeground:")]
public void WillEnterForeground(UIScene scene)
{
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
[Export("sceneDidEnterBackground:")]
public void DidEnterBackground(UIScene scene)
{
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
UIApplication.SharedApplication.BeginReceivingRemoteControlEvents();
SetLockInfo();
}
public void SetLockInfo()
{
//NSMutableDictionary songInfo = new NSMutableDictionary();
MPNowPlayingInfo playInfo = new MPNowPlayingInfo();
//image
MPMediaItemArtwork albumArt = new MPMediaItemArtwork(new UIImage());
playInfo.Artwork = albumArt;
//title
playInfo.Title = "your song name";
//singer
playInfo.Artist = "singer name";
//rate
playInfo.PlaybackRate = 1.0;
//current time
playInfo.ElapsedPlaybackTime = 0;
//durtaion
playInfo.PlaybackDuration = 2.35; // the durtaion of the song
MPNowPlayingInfoCenter.DefaultCenter.NowPlaying = playInfo;
}
}
进入后台时,需要将当前音频信息传递给MPNowPlayingInfoCenter。