简体   繁体   English

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

[英]How do I get my AVPlayer to play while app is in background?

I've done my homework... been reading here, the docs, googling, stackoverflowing... but still no luck in making my sound stick when the user makes the app go into the background.我已经完成了我的功课......一直在这里阅读,文档,谷歌搜索,stackoverflowing......但是当用户让应用程序进入后台时,我的声音仍然没有运气。

What I have done so far: Added the UIBackgroundModes, audio to the plist-file.到目前为止我所做的:将 UIBackgroundModes、音频添加到 plist 文件。

First this code:首先这段代码:

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

Then this:然后这个:

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

But as soon as the user hits the home-button, my sound dies.但是一旦用户按下主页按钮,我的声音就会消失。

I also found this, but not added yet cuase some stuff I've read says it is not needed;我也发现了这个,但还没有添加,因为我读过的一些东西说不需要;

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

Right now I have no idea where I should go to make my AVPlayer let the radio sing while the user does other stuff on the phone.现在我不知道我应该去哪里让我的 AVPlayer 让收音机唱歌,而用户在手机上做其他事情。 I am testing this on an iPhone 4 with 4.2.我正在 4.2 的 iPhone 4 上对此进行测试。 Building it for 4.0.为 4.0 构建它。

Anyone have any suggestions what I should do?有人对我应该做什么有任何建议吗?

UPDATE IOS 11.2 with Swift 4: 使用Swift 4更新IOS 11.2:

Now if you are using AVPlayer to play music files you should also configure MPNowPlayingInfoCenter.default() to show now playing info on the lock screen. 现在,如果您使用AVPlayer播放音乐文件,您还应该配置MPNowPlayingInfoCenter.default()以在锁定屏幕上显示正在播放的信息。

Below code will show now playing controls on the screen but it won't be able to respond any commands. 下面的代码将显示现在在屏幕上播放控件但它无法响应任何命令。

If you also want to controls to work you should check apple's sample project here: https://developer.apple.com/library/content/samplecode/MPRemoteCommandSample/Introduction/Intro.html#//apple_ref/doc/uid/TP40017322 如果你还想让控件工作,你应该在这里查看apple的示例项目: https//developer.apple.com/library/content/samplecode/MPRemoteCommandSample/Introduction/Intro.html#//apple_ref/doc/uid/TP40017322

Apple sample code covers all but i find it confusing. Apple示例代码涵盖了所有内容,但我发现它令人困惑。

If you want to play sound and show controls on the lock screen these steps will do just fine. 如果你想在锁定屏幕上播放声音并显示控件,这些步骤就可以了。

IMPORTANT NOTE: If you are NOT using AVPlayer to play sound. 重要说明:如果您使用AVPlayer播放声音。 If you are using some third party libraries to generate sound or playback a sound file you should read comments inside the code. 如果您使用某些第三方库来生成声音或播放声音文件,您应该阅读代码中的注释。 Also if you are using ios simulator 11.2 you won't be able to see any controls on lock screen. 此外,如果您使用ios模拟器11.2,您将无法在锁定屏幕上看到任何控件。 You should use a device to see it work. 您应该使用设备查看它是否有效。


1- Select project -> capabilites -> set background modes ON -> tick Audio, AirPlay and Picture in Picture 1-选择项目 - >功能 - >将背景模式设置为开 - >勾选音频,AirPlay和画中画

ios 11背景音频设置

2- AppDelegate.swift file should look like this : 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 should look like this: 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()
    }

OLD ANSWER IOS 8.2: OLD ANSWER IOS 8.2:

Patrick's answer is totally right. 帕特里克的回答是完全正确的。

But i'm gonna write what i do for ios 8.2 : 但是我要写我为ios 8.2做的事情:

I add my app's info.plist required background modes like below: 我添加了我的应用程序的info.plist所需的背景模式,如下所示:

在此输入图像描述

And in my AppDelegate.h i add these imports: 在我的AppDelegate.h中,我添加了这些导入:

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

Then in my AppDelegate.m i wrote application didFinishLaunchingWithOptionsthis exactly like below: 然后在我的AppDelegate.m中,我写了应用程序didFinishLaunchingWithOptionsthis,如下所示:

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

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

    return YES;
}

Now App keeps playing music even if screen is locked :) 现在App即使屏幕被锁定也会继续播放音乐:)

Had the same problem, but found a solution for this.. 有同样的问题,但找到了解决方案..

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

The content of the above link: 以上链接的内容:


Replace APPNAME with your own app name! 用您自己的应用名称替换APPNAME

Im on iOS 4.2.1 我在iOS 4.2.1上

EDIT: Working with iOS5 + 6 + 7 beta so far 编辑:到目前为止使用iOS5 + 6 + 7测试版

Add UIBackgroundModes in the APPNAME-Info.plist , with the selection App plays audio APPNAME-Info.plist添加UIBackgroundModes ,选择App播放音频

Then add the AudioToolBox framework to the folder frameworks. 然后将AudioToolBox框架添加到文件夹框架。

In the APPNAMEAppDelegate.h add: APPNAMEAppDelegate.h添加:

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

so it look like this: 所以它看起来像这样:

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

In the APPNAMEAppDelegate.m add the following: 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);

into the 进入

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

but before the two lines: 但在两行之前:

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

Build your project and see if theres any error, If not, try debug on Device insted of the Simulator, it CAN bug on simulator. 构建你的项目,看看是否有任何错误,如果没有,尝试在模拟器的设备上调试,它可以在模拟器上出错。

Hope this helps others with same problem.. 希望这有助于其他同样的问题..

I have successfully made audio run in the background by adding the following to my applicationDidFinishLaunching 我通过在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];

iOS 9 Swift iOS 9 Swift

All you should need is add the following to your didFinishLaunchingWithOptions 您应该只需要将以下内容添加到didFinishLaunchingWithOptions中

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

You have a good example of a GPS background app that plays sounds even when in background : 你有一个很好的GPS背景应用程序示例,即使在后台播放声音:

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

In this example, AudioToolbox is used. 在此示例中,使用了AudioToolbox。

I did a test myself and it works : create a simple project that monitors the GPS post ( UIBackgroundModes location ) , and every x received position, play a sound using 我自己做了一个测试并且它有效:创建一个监视GPS帖子( UIBackgroundModes location )的简单项目,以及每个x接收位置,播放声音使用

AudioServicesPlaySystemSound(soundId);

Then if you put audio as part of your UIBackgroundModes and the sounds will be played, even if the application isn't in foreground anymore. 然后,如果您将audio作为UIBackgroundModes一部分并且将播放声音,即使应用程序不再处于前台。

I've made such a test and it works ok ! 我做了这样的测试,它运作正常!

(I didn't manage to get it working with AVPlayer so I fallbacked to AudioToolbox) (我没有设法让它与AVPlayer一起使用,所以我退回到AudioToolbox)

I've the same problem and I found solution in Apple Docs: https://developer.apple.com/library/ios/qa/qa1668/_index.html 我遇到了同样的问题,我在Apple Docs中找到了解决方案: https//developer.apple.com/library/ios/qa/qa1668/_index.html

Q: How do I ensure my media will continue playing when using AV Foundation while my application is in the background? 问:在应用程序处于后台时,如何确保在使用AV Foundation时我的媒体将继续播放?

A: You must declare your app plays audible content while in the background, and assign an appropriate category to your audio session. 答:您必须声明您的应用程序在后台播放可听内容,并为您的音频会话分配适当的类别。 See also Special Considerations for Video Media . 另请参阅视频媒体的特殊注意事项

Working for Swift 5Swift 5工作

Here are the 4 things that I did for my music to play in the background from a video that the avPlayer was playing.以下是我为让 avPlayer 正在播放的视频在后台播放音乐而做的 4 件事。 I followed the Apple directions link from @AndriySavran's answer plus a few other things.我按照@AndriySavran 的回答中的 Apple 方向链接以及其他一些内容进行操作。

1- In AppDelegate's didFinishLaunching I put: 1- 在 AppDelegate 的didFinishLaunching我放了:

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

        do {
            try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, mode: AVAudioSession.Mode.default, 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- Follow this answer from @LeoDabus. 2- 按照@LeoDabus 的回答进行操作。 In your Signing & Capabilties > Background Modes (if background modes isn't there then select it from Capabilites then) > tick Audio, Airplay, and Picture in Picture在您的Signing & Capabilties > Background Modes (如果背景模式不存在,然后从功能中选择它)> 勾选Audio, Airplay, and Picture in Picture

3- In the view controller that has your AVPlayer , add the .didEnterBackgroundNotification and .willEnterForegroundNotification notifications 3- 在具有AVPlayer的视图控制器中,添加.didEnterBackgroundNotification.willEnterForegroundNotification通知

var player: AVPlayer?
var playerItem: AVPlayerItem? // your AVPlayer should be initialized with this

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- for the selector method add the code from the Apple link 4- 为选择器方法添加来自 Apple 链接的代码

@objc func appDidEnterBackground() {

    if let player = player {
        if !player.isPlaying { // if the player isn't playing no need to disable the playerItemTrack
            return
        }
    }

    guard let tracks = playerItem?.tracks else { return } // this is assuming your AVPlayer is initialized with a class property AVPlayerItem like from step 3

    for playerItemTrack in tracks {
        
        guard let assetTrack = playerItemTrack.assetTrack else { continue }
        
        // Find the video tracks.
        if assetTrack.hasMediaCharacteristic(AVMediaCharacteristic.visual) {
     
            // Disable the track.
            playerItemTrack.isEnabled = false
        }
    }
}

@objc func appWillEnterForeground() {
    
    guard let tracks = playerItem?.tracks else { return }

    for playerItemTrack in tracks {
        
        guard let assetTrack = playerItemTrack.assetTrack else { continue }
        
        // Find the video tracks.
        if assetTrack.hasMediaCharacteristic(AVMediaCharacteristic.visual) {
     
            // Enable the track.
            playerItemTrack.isEnabled = true
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM