【问题标题】:How do I get my AVPlayer to play while app is in background?如何让我的 AVPlayer 在应用程序处于后台时播放?
【发布时间】:2011-06-13 20:30:43
【问题描述】:

我已经完成了我的功课...一直在这里阅读文档、谷歌搜索、stackoverflowing...但是当用户让应用程序进入后台时,我仍然无法让我的声音保持不变。

到目前为止我做了什么: 在 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 让收音机唱歌,而用户在手机上做其他事情。 我正在使用 4.2 的 iPhone 4 上对此进行测试。为 4.0 构建它。

有人对我应该怎么做有什么建议吗?

【问题讨论】:

标签: iphone ios background avplayer


【解决方案1】:

使用 Swift 4 更新 IOS 11.2:

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

下面的代码将在屏幕上显示正在播放的控件,但它无法响应任何命令。

如果你还想控制工作,你应该在这里查看苹果的示例项目:https://developer.apple.com/library/content/samplecode/MPRemoteCommandSample/Introduction/Intro.html#//apple_ref/doc/uid/TP40017322

Apple 示例代码涵盖了所有内容,但我觉得它令人困惑。

如果您想在锁定屏幕上播放声音并显示控件,这些步骤就可以了。

重要提示:如果您使用 AVPlayer 播放声音。如果您使用一些第三方库来生成声音或播放声音文件,您应该阅读代码中的 cmets。此外,如果您使用的是 ios 模拟器 11.2,您将无法在锁定屏幕上看到任何控件。您应该使用设备来查看它的工作情况。


1- 选择项目 -> 功能 -> 设置背景模式 -> 勾选音频、AirPlay 和画中画

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 所需的背景模式 如下:

在我的 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;
}

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

【讨论】:

  • 解决方案有效,但 Swift 和 ios 8.4 中的 jyfi 我不需要导入 AudioToolbox
  • 最简单。谢谢!
  • 谢谢。 iOS 11.2 的Info.plist 中要添加哪些键和值?
  • try AVAudioSession.sharedInstance().setActive(true) 在使用AVPlayer 时不需要。当您将它放在 AppDelegate 的 didFinishLaunching 函数中时,它只会在启动您的应用程序时停止其他音频,这并不总是需要......
  • 谢谢,这解决了我的问题
【解决方案2】:

遇到了同样的问题,但找到了解决方案..

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

以上链接内容:


APPNAME 替换为您自己的应用名称!

我在 iOS 4.2.1 上

编辑:目前使用 iOS5 + 6 + 7 测试版

APPNAME-Info.plist中添加UIBackgroundModes,选择App播放音频

然后将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];

构建你的项目,看看是否有错误,如果没有,尝试在模拟器的设备上调试,它可以在模拟器上出错。

希望这可以帮助其他有同样问题的人..

【讨论】:

  • 谢谢帕特里克 R!使我的背景音频工作完美! :)
  • 我收到一个错误““_AudioSessionSetProperty”,引用自:“我已经添加了所有框架。不知道为什么我会得到它。
  • 您可以尝试在 AudioSession 中设置更改设置的 Override。只是看看这是否应该有效。尽管如此,这不是一个很好的解决方法。你在 atm 上是什么 iOS 设备?
  • 嗨,我已经根据你更新了我的代码,但不幸的是,这不适用于 iOS 6.0+。有什么建议吗?
  • 如果你有兴趣,你甚至可以用AVPlayer播放视频的声音,详情here
【解决方案3】:

通过将以下内容添加到我的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 来检查应用程序的不同状态。我对他们的 atm 不做任何事情,只是读取不同的状态。
  • 我必须做的是,我没有在网上找到任何说明这一点的东西,就是将我的音频注册到 AVAudioSession 为活动状态,如下所示: [[AVAudioSession sharedInstance] setActive: YES 错误: 空];
  • 所以它适用于[[AVAudioSession sharedInstance] setActive: YES error: NULL];?很有趣,以后会记住的:)
  • 今天我的 AVPlayer 不再工作了,到目前为止我也不知道为什么。直到知道它一直在完美地工作。是时候开始挖掘了。
  • 我在 plist 文件中手动设置了 UIBackgroundModes,发现它不起作用,直到我转到项目设置 -> 功能 -> 背景模式并检查了列表模式中的第一项:音频、Airplay、和画中画。当您这样做时,它会在“步骤:”中向您显示一条消息,要求您也将其添加到 plist 文件中。
【解决方案4】:

iOS 9 斯威夫特

您只需将以下内容添加到您的 didFinishLaunchingWithOptions 中

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

【讨论】:

    【解决方案5】:

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

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

    在本例中,使用了 AudioToolbox。

    我自己做了一个测试,它可以工作:创建一个简单的项目来监控 GPS 后 (UIBackgroundModeslocation),并且每个 x 接收到的位置,使用播放声音

    AudioServicesPlaySystemSound(soundId);

    然后,如果您将audio 作为UIBackgroundModes 的一部分,即使应用程序不再处于前台,声音也会播放。

    我做了这样的测试,它工作正常!

    (我没有设法让它与 AVPlayer 一起工作,所以我回退到 AudioToolbox)

    【讨论】:

      【解决方案6】:

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

      问:当我的应用程序在后台使用 AV Foundation 时,如何确保我的媒体能够继续播放?

      答:您必须声明您的应用在后台播放可听内容,并为您的音频会话分配适当的类别。另见特殊Considerations for Video Media

      【讨论】:

        【解决方案7】:

        Swift 5

        工作

        以下是我为在 avPlayer 正在播放的视频中播放背景音乐所做的 4 件事。我关注了来自@AndriySavran 的answer 的Apple directions link 和这个Apple link 以及其他一些东西。

        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 的answer。在您的Signing &amp; Capabilties > Background Modes 中(如果没有后台模式,则从 Capabilites 中选择它)> 勾选 Audio, Airplay, and Picture in Picture

        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- 为选择器方法添加来自 Apple 链接的代码

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-11-12
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-05-24
          • 2018-10-26
          • 1970-01-01
          相关资源
          最近更新 更多