如何让我的AVPlayer在应用程序在后台时播放?

34

我已经完成了我的作业...在这里阅读了文档,搜索了谷歌和Stack Overflow,但是当用户将应用程序置于后台时,仍然无法使我的声音保持。

到目前为止,我所做的事情是: 在plist文件中添加UIBackgroundModes和音频。

首先是这段代码:

radioAudio = [[AVAudioSession alloc] init];
[radioAudio setCategory:AVAudioSessionCategoryPlayback error:nil];
[radioAudio setActive:YES error:nil];

然后是这个:

NSString *radioURL = @"http://xxx.xxx.xxx/radio.m3u";
radioPlayer = [[AVPlayer playerWithURL:[NSURL URLWithString:radioURL]] retain];

但是一旦用户点击主页按钮,我的声音就会消失。

我也发现了这个,但是还没有添加,因为我读到的一些东西说它是不必要的。

newTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:NULL];
     if (newTaskId != UIBackgroundTaskInvalid && bgTaskId != UIBackgroundTaskInvalid)
        [[UIApplication sharedApplication] endBackgroundTask: bgTaskId];
bgTaskId = newTaskId;

目前我不知道该如何使AVPlayer在用户进行其他操作时继续播放音频。我正在iPhone 4上测试,版本是4.2,但编译为4.0。

有人有什么建议吗?


查看我的答案,你会找到你的解决方案 [点击此处查看答案] - Vishal Khatri
7个回答

53

使用Swift 4更新IOS 11.2:

如果您正在使用AVPlayer播放音频文件,则还应配置MPNowPlayingInfoCenter.default()以在锁定屏幕上显示当前播放信息。

以下代码将在屏幕上显示当前播放控件,但无法响应任何命令。

如果您还希望控件起作用,您应该查看苹果的示例项目:https://developer.apple.com/library/content/samplecode/MPRemoteCommandSample/Introduction/Intro.html#//apple_ref/doc/uid/TP40017322

苹果的示例代码涵盖了所有内容,但我觉得有些混乱。

如果您想播放声音并在锁屏界面上显示控件,这些步骤就足够了。

重要提示:如果您使用AVPlayer播放声音。如果您使用一些第三方库生成声音或播放声音文件,则应阅读代码内的注释。此外,如果您使用iOS模拟器11.2,则无法在锁屏界面上看到任何控件。您应该使用设备来查看其工作情况。


1- 选择项目 ->功能 ->打开后台模式 ->选中音频、AirPlay和画中画

ios 11 background audio setting

2- AppDelegate.swift文件应如下所示:

import UIKit

import AVFoundation

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate
{

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
    {
        // Override point for customization after application launch.

        do
        {
            try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
            try AVAudioSession.sharedInstance().setActive(true)

         //!! IMPORTANT !!
         /*
         If you're using 3rd party libraries to play sound or generate sound you should
         set sample rate manually here.
         Otherwise you wont be able to hear any sound when you lock screen
         */
            //try AVAudioSession.sharedInstance().setPreferredSampleRate(4096)
        }
        catch
        {
            print(error)
        }
        // This will enable to show nowplaying controls on lock screen
        application.beginReceivingRemoteControlEvents()

        return true
    }
}

3- ViewController.swift 应该如下所示:

import UIKit

import AVFoundation
import MediaPlayer

class ViewController: UIViewController
{

    var player : AVPlayer = AVPlayer()

    override func viewDidLoad()
    {
        super.viewDidLoad()


        let path = Bundle.main.path(forResource: "music", ofType: "mp3")
        let url = URL(fileURLWithPath: path!)

        // !! IMPORTANT !!
        /*
            If you are using 3rd party libraries to play sound 
            or generate sound you should always setNowPlayingInfo 
            before you create your player object.

            right:
            self.setNowPlayingInfo()
            let notAVPlayer = SomePlayer()

            wrong(You won't be able to see any controls on lock screen.):
            let notAVPlayer = SomePlayer()
            self.setNowPlayingInfo()
         */

        self.setNowPlayingInfo()
        self.player = AVPlayer(url: url)

    }


    func setNowPlayingInfo()
    {
        let nowPlayingInfoCenter = MPNowPlayingInfoCenter.default()
        var nowPlayingInfo = nowPlayingInfoCenter.nowPlayingInfo ?? [String: Any]()

        let title = "title"
        let album = "album"
        let artworkData = Data()
        let image = UIImage(data: artworkData) ?? UIImage()
        let artwork = MPMediaItemArtwork(boundsSize: image.size, requestHandler: {  (_) -> UIImage in
            return image
        })

        nowPlayingInfo[MPMediaItemPropertyTitle] = title
        nowPlayingInfo[MPMediaItemPropertyAlbumTitle] = album
        nowPlayingInfo[MPMediaItemPropertyArtwork] = artwork

        nowPlayingInfoCenter.nowPlayingInfo = nowPlayingInfo
    }

    @IBAction func startPlayingButtonPressed(_ sender: Any)
    {
        self.player.play()
    }

旧版IOS 8.2答案:

Patrick的回答是完全正确的。

但是我要写一下我在ios 8.2中的做法:

我在我的应用程序信息属性列表(info.plist)中添加了所需的后台模式,如下所示:

enter image description here

并且在我的AppDelegate.h文件中添加了以下导入:

#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>

然后在我的AppDelegate.m文件中,我按照以下方式精确地编写了application didFinishLaunchingWithOptionsthis

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.

    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];

    return YES;
}

现在应用程序即使屏幕锁定也可以继续播放音乐 :)

1
解决方案可行,但在Swift和iOS 8.4中,我不需要导入AudioToolbox。 - longbow
iOS 11.2版本的Info.plist需要添加哪些键和值?谢谢。 - user4886069
当使用AVPlayer时,不需要尝试AVAudioSession.sharedInstance().setActive(true)。它只会在启动应用程序时停止其他音频,并将其放置在您的AppDelegate的didFinishLaunching函数中,这并不总是需要的... - heyfrank

42

我曾遇到过同样的问题,但找到了解决方法...

请看这里:https://devforums.apple.com/message/395049#395049

上述链接的内容:


用您自己的应用程序名称替换APPNAME

我使用的是iOS 4.2.1。

编辑:目前可与iOS5 + 6 + 7 beta配合使用

APPNAME-Info.plist中添加UIBackgroundModes,并选择 App plays audio。

然后将AudioToolBox框架添加到文件夹frameworks中。

APPNAMEAppDelegate.h 中添加:

#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>

所以它看起来像这样:

...
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <AudioToolbox/AudioToolbox.h>
...

APPNAMEAppDelegate.m中添加以下内容:

// Set AudioSession
NSError *sessionError = nil;
[[AVAudioSession sharedInstance] setDelegate:self];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:&sessionError];

/* Pick any one of them */
// 1. Overriding the output audio route
//UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_Speaker;
//AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute, sizeof(audioRouteOverride), &audioRouteOverride);

// 2. Changing the default output audio route
UInt32 doChangeDefaultRoute = 1;
AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryDefaultToSpeaker, sizeof(doChangeDefaultRoute), &doChangeDefaultRoute);

进入到

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

但在这两行代码之前:

[self.window addSubview:viewController.view];
[self.window makeKeyAndVisible];

构建您的项目并查看是否有任何错误。如果没有,请尝试在设备上调试而不是模拟器上,因为模拟器上可能会出现错误。

希望这可以帮助其他遇到同样问题的人。


2
谢谢Patrick R!让我的背景音频完美工作! :) - swe_mattias
如果你有兴趣,甚至可以使用AVPlayer播放视频声音,详情见这里 - MacTeo
这个问题的唯一问题是当电话通话进行时,AVPlayer仍然会继续播放。我们该如何解决这个问题? - TijuanaKez
当我将代理设置为 self 时,会出现以下错误:AppDelegate.m:18:50: 将 'AppDelegate *const __strong' 发送到不兼容类型的参数 'id<AVAudioPlayerDelegate>'。 - 4GetFullOf
另外,请参见https://dev59.com/rW_Xa4cB1Zd3GeqP368S。 - Anconia
显示剩余4条评论

10

我已经成功地让音频在后台运行,方法是将以下内容添加到我的applicationDidFinishLaunching中:

// Registers this class as the delegate of the audio session.
[[AVAudioSession sharedInstance] setDelegate: self];    
// Allow the app sound to continue to play when the screen is locked.
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];

那对我没用,我肯定在代码的其他地方搞砸了背景设置。我唯一能想到的就是我正在运行NSNotificationCenter以检查应用程序的不同状态。目前我什么也没做,只是读取不同的状态。 - swe_mattias
1
我所需要做的,而在网络上没有找到任何说明的是,将我的音频注册为AVAudioSession的活动状态,像这样:[[AVAudioSession sharedInstance] setActive: YES error: NULL]; - swe_mattias
1
那么它可以与[[AVAudioSession sharedInstance] setActive: YES error: NULL];一起使用吗?很有趣的知识,我会记住这个的 :) - atomoil
你成功让这个工作了吗?因为我也在尝试做同样的事情,但是它就是不起作用 :-( - Patrice Cote
1
我手动在plist文件中设置了UIBackgroundModes,但发现它不起作用,直到我进入项目设置->功能->后台模式并勾选列表模式中的第一项:音频、Airplay和画中画。当你这样做时,它会在“步骤”中给你一个消息,要求你也将其添加到plist文件中。 - xdeleon
显示剩余2条评论

6

iOS 9 Swift

您只需要将以下内容添加到 didFinishLaunchingWithOptions 中即可:

do  {
    try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
} catch {
    //TODO
}

1

正在为Swift 5工作

以下是我为了让我的音乐在avPlayer播放的视频背景中播放而做的4件事。我遵循了苹果公司指示链接,这是来自@AndriySavran的答案和这个苹果链接以及其他一些事情。

1- 在AppDelegate的didFinishLaunching中,我添加了:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        do {
            try AVAudioSession.sharedInstance().setCategory( .playback, mode: .moviePlayback, options: [.mixWithOthers, .allowAirPlay])
            print("Playback OK")
            try AVAudioSession.sharedInstance().setActive(true)
            print("Session is Active")
        } catch {
            print(error)
        }

    // whatever other code that you use ...

    return true
}

2- 跟随 @LeoDabus 的 答案。在您的 签名和能力 > 后台模式(如果没有后台模式,则从 Capabilites 中选择)> 选中 音频、Airplay 和画中画

3- 在拥有您的 AVPlayer 的视图控制器中,添加 .didEnterBackgroundNotification.willEnterForegroundNotification 通知。

override func viewDidLoad() {
    super.viewDidLoad()

    NotificationCenter.default.addObserver(self,
                                           selector: #selector(appDidEnterBackground),
                                           name: UIApplication.didEnterBackgroundNotification, object: nil)
    
    NotificationCenter.default.addObserver(self,
                                           selector: #selector(appWillEnterForeground),
                                           name: UIApplication.willEnterForegroundNotification, object: nil)

}

4- 对于选择器方法,请添加来自苹果链接的代码

@objc func appDidEnterBackground() {

    playerLayer?.player = nil
}

@objc func appWillEnterForeground() {
    
    playerLayer?.player = self.player
}

1

你有一个很好的GPS后台应用程序示例,即使在后台也可以播放声音:

http://www.informit.com/articles/article.aspx?p=1646438&seqNum=5

在这个例子中,使用了AudioToolbox。
我自己测试过它可以工作:创建一个简单的项目来监测GPS位置(UIBackgroundModes位置),每收到x个位置时,使用AudioServicesPlaySystemSound(soundId)播放声音。
然后,如果将audio作为UIBackgroundModes的一部分,并且即使应用程序不再处于前台,声音也会被播放。
我做了这样的测试,它可以正常工作!
(我无法让它与AVPlayer一起工作,所以我回退到了AudioToolbox)

1

我有同样的问题,我在苹果文档中找到了解决方案:https://developer.apple.com/library/ios/qa/qa1668/_index.html

问:当我的应用程序在后台运行时,如何确保我的媒体继续播放?

答:您必须声明您的应用程序在后台播放可听内容,并为您的音频会话分配适当的类别。另请参阅视频媒体的特殊注意事项


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接