iOS 7 SDK不遵守背景音频

cod*_*kie 24 objective-c core-audio avaudioplayer avplayer ios7

我在Google和StackOverflow上做了很多研究.我发现的所有答案在iOS 7中都不起作用.我开始在iOS 7 SDK中使用Xcode 5编写新的应用程序.

我所要做的就是从应用程序包中存储的文件(而不是音乐库)中播放应用程序中的音频.我希望在后台播放音频并在屏幕锁定时控制(除控制中心外).

我将APPNAME-Info.plist密钥设置UIBackgroundModes音频.它不处理app委托中的内容; 一切都在ViewController中完成

@interface ViewController : UIViewController <AVAudioPlayerDelegate>
Run Code Online (Sandbox Code Playgroud)

在实现的viewDidAppear:方法中,我调用super,然后是以下代码:

// Once the view has loaded then we can register to begin receiving controls and we can become the first responder
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
Run Code Online (Sandbox Code Playgroud)

在我的实现viewWillDisappear:方法中,我有以下代码:

// End receiving events
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[self resignFirstResponder];
Run Code Online (Sandbox Code Playgroud)

我还实现了canBecomeFirstResponder方法,返回YES.接下来,我实现了该remoteControlReceivedWithEvent:方法:

- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
    // If it is a remote control event handle it correctly
    if (event.type == UIEventTypeRemoteControl) {
        if (event.subtype == UIEventSubtypeRemoteControlPlay) {
            [self playPauseAudio:self];
        } else if (event.subtype == UIEventSubtypeRemoteControlPause) {
            [self playPauseAudio:self];
        } else if (event.subtype == UIEventSubtypeRemoteControlTogglePlayPause) {
            [self playPauseAudio:self];
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

让我感到困惑的是,这个完全相同的设置在iOS 6上运行良好.在iOS 7上,它不起作用.它曾经在iOS 6中如此简单.在iOS 7 SDK中有些根本改变了.我错过了什么?

cod*_*kie 16

我设法解决了这个问题,并且为了挽救另一个可怜的灵魂的头发而去:

首先确保您的Info.plist正确地将音频列为后台模式.

(如果你不知道我在说什么,请选择YOURAPPNAME-Info.plist选择它.单击加号并添加一个新的密钥UIBackgroundModes并展开它.添加一个名为audio.的值.)

您需要引用任何正在创建音频的播放对象.由于我只播放音频并且AV播放器不遵守背景音频,请在视图控制器的标题中使用它:

@property (nonatomic, retain) MPMoviePlayerController *audioPlayer;
Run Code Online (Sandbox Code Playgroud)

在实施中,执行以下操作:

 [super viewDidAppear:animated];

    //Once the view has loaded then we can register to begin recieving controls and we can become the first responder
    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
    [self becomeFirstResponder];
Run Code Online (Sandbox Code Playgroud)

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];

    //End recieving events
    [[UIApplication sharedApplication] endReceivingRemoteControlEvents];
    [self resignFirstResponder];
Run Code Online (Sandbox Code Playgroud)

添加两个方法

//Make sure we can recieve remote control events
- (BOOL)canBecomeFirstResponder {
    return YES;
}

- (void) registerForAudioObjectNotifications {

    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];

    [notificationCenter addObserver: self
                           selector: @selector (handlePlaybackStateChanged:)
                               name: MixerHostAudioObjectPlaybackStateDidChangeNotification
                             object: audioObject];
}
Run Code Online (Sandbox Code Playgroud)

现在所有重要代码 - 这使您的应用程序可以控制来自"控制中心"和锁定屏幕的音频:

- (void) remoteControlReceivedWithEvent: (UIEvent *) receivedEvent {

    if (receivedEvent.type == UIEventTypeRemoteControl) {

        switch (receivedEvent.subtype) {

            case UIEventSubtypeRemoteControlTogglePlayPause:
                [self playOrStop: nil];
                break;

            default:
                break;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以在此处添加许多类型的事件类型并调用任何方法.

典型事件是:

 UIEventSubtypeRemoteControlPlay                 = 100,  //Parent EVENT

// All below are sub events and you can catch them using switch or If /else.
    UIEventSubtypeRemoteControlPause                = 101,
    UIEventSubtypeRemoteControlStop                 = 102,
    UIEventSubtypeRemoteControlTogglePlayPause      = 103,
    UIEventSubtypeRemoteControlNextTrack            = 104,
    UIEventSubtypeRemoteControlPreviousTrack        = 105,
    UIEventSubtypeRemoteControlBeginSeekingBackward = 106,
    UIEventSubtypeRemoteControlEndSeekingBackward   = 107,
    UIEventSubtypeRemoteControlBeginSeekingForward  = 108,
    UIEventSubtypeRemoteControlEndSeekingForward    = 109,
Run Code Online (Sandbox Code Playgroud)

要调试帮助,您可以使用:

 MPMoviePlayerController *mp1= (MPMoviePlayerController *)[notification object];
    NSLog(@"Movie State is: %d",[mp1 playbackState]);

    switch ([mp1 playbackState]) {
        case 0:
            NSLog(@"******* video has stopped");
            break;
        case 1:
            NSLog(@"******* video is playing after being paused or moved.");
                       break;
        case 2:
            NSLog(@"******* video is paused");
                break;
        case 3:
            NSLog(@"******* video was interrupted");
            break;
        case 4:
            NSLog(@"******* video is seeking forward");
                     break;
        case 5:
            NSLog(@"******* video is seeking Backwards");
            break;
        default:
            break;
Run Code Online (Sandbox Code Playgroud)

这就是它 - 希望它有助于那里的一些人! - 这在带有Storyboard应用程序的iOS 7和iOS 6以及使用耳机和所有新控制中心的控制方面都非常完美.


小智 7

显然问题出在Apple的一边,因为iOS更新7.0.3解决了这个问题.除了Alex关于UIEventSubtype更改的内容之外,iOS6上运行的代码现在可以在iOS7上运行.

为了完整起见,这是我在iOS6和iOS7中使用的相关代码 - 在udpate到7.0.3之后.还包括项目构建阶段中的AVFoundation.framework和MediaPlayer.framework - >使用库链接二进制文件.在app delegate中没有此代码.

在viewcontroller .h文件中:

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

@interface NewsDetailViewController : UIViewController <UIWebViewDelegate, AVAudioSessionDelegate>
@property (nonatomic) MPMoviePlayerController *audioPlayer;
Run Code Online (Sandbox Code Playgroud)

在viewcontroller .m文件中:

- (void)viewDidLoad
{
    [super viewDidLoad];

    self.audioPlayer = [[MPMoviePlayerController alloc] initWithContentURL:audioUrl];
    [self.audioPlayer prepareToPlay];
    [self.audioPlayer.view setFrame:CGRectMake(0, 0, self.audioView.frame.size.width,     42)];
    self.audioPlayer.view.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    [self.audioView addSubview:self.audioPlayer.view];
    [self.audioPlayer play];

    NSError *setCategoryError = nil;
    NSError *activationError = nil;
    [[AVAudioSession sharedInstance] setActive:YES error:&activationError];
    [[AVAudioSession sharedInstance] setDelegate:self];
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&setCategoryError];
}

- (BOOL)canBecomeFirstResponder {
    return YES;
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
    [self becomeFirstResponder];
}

- (void)viewWillDisappear:(BOOL)animated {
    [self.audioPlayer stop];
    [[UIApplication sharedApplication] endReceivingRemoteControlEvents];
    [self resignFirstResponder];

    [super viewWillDisappear:animated];
}

- (void)remoteControlReceivedWithEvent:(UIEvent *)receivedEvent {

    if (receivedEvent.type == UIEventTypeRemoteControl) {
        switch (receivedEvent.subtype) {
            case UIEventSubtypeRemoteControlPlay:
                [self.audioPlayer play];
                break;
            case UIEventSubtypeRemoteControlPause:
                [self.audioPlayer pause];
                break;
            case UIEventSubtypeRemoteControlTogglePlayPause:
                if (self.audioPlayer.playbackState == MPMoviePlaybackStatePlaying) {
                    [self.audioPlayer pause];
                }
                else {
                    [self.audioPlayer play];
                }
                break;
            default:
                break;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


cha*_*dan 6

如果你想在iphone和模拟器中播放背景音频,那么你需要在plist中编写这段代码.首先确保你的Info.plist正确地将音频列为背景模式.

(如果你不知道我在说什么,请选择YOURAPPNAME-Info.plist选择它.点击加号并键入一个键UIBackgroundModes并输入.添加一个名为"App播放音频"的值(用于模拟器)或"应用程序播放"音频或流音频/视频使用AirPlay"(适用于iPhone).)

在此输入图像描述

AppDelegate.m中

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    __block UIBackgroundTaskIdentifier task = 0;
    task=[application beginBackgroundTaskWithExpirationHandler:^{
    NSLog(@"Expiration handler called %f",[application backgroundTimeRemaining]);
    [application endBackgroundTask:task];
    task=UIBackgroundTaskInvalid;
    }];
}
Run Code Online (Sandbox Code Playgroud)

在项目中添加这两个框架,在ViewController.h中添加一些代码

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

@interface ViewController : UIViewController <UIWebViewDelegate, AVAudioSessionDelegate>
@property (nonatomic) MPMoviePlayerController *audioPlayer;
Run Code Online (Sandbox Code Playgroud)

提醒您应该在项目中添加这些框架引用.

然后在Viewcontrller.m中

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    [[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
    [self becomeFirstResponder];
}

- (void)viewWillDisappear:(BOOL)animated {
    [self.audioPlayer stop];
    [[UIApplication sharedApplication] endReceivingRemoteControlEvents];
    [self resignFirstResponder];

    [super viewWillDisappear:animated];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    NSURL *audioUrl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"songName" ofType:@"mp3"]];
    self.audioPlayer = [[MPMoviePlayerController alloc] initWithContentURL:audioUrl];
    [self.audioPlayer prepareToPlay];
    [self.audioPlayer.view setFrame:CGRectMake(0, 0, self.view.frame.size.width-100,     42)];
    self.audioPlayer.view.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    [self.view addSubview:self.audioPlayer.view];
    [self.audioPlayer play];


    // for run application in background
    NSError *setCategoryError = nil;
    NSError *activationError = nil;
    [[AVAudioSession sharedInstance] setActive:YES error:&activationError];
    [[AVAudioSession sharedInstance] setDelegate:self];
    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&setCategoryError];
}
Run Code Online (Sandbox Code Playgroud)

我希望它能帮助你在iphone和模拟器中播放背景音频.