web-dev-qa-db-ja.com

iOS 7SDKがバックグラウンドオーディオに準拠していない

私はGoogleとStackOverflowの両方で多くの調査を行いました。私が見つけたすべての答えはiOS7では機能しません。Xcode5を使用してiOS7SDKで新しいアプリを書き始めました。

私がやろうとしているのは、(ミュージックライブラリからではなく)アプリバンドルに保存されているファイルからアプリでオーディオを再生することだけです。 オーディオはバックグラウンドで再生され、画面がロックされているときに制御されます(コントロールセンターに加えて)が必要です。

APPNAME-Info.plistキーUIBackgroundModesaudioに設定しました。アプリデリゲートで処理を行っていません。すべてはViewController内で行われます

@interface ViewController : UIViewController <AVAudioPlayerDelegate>

実装の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];

私の実装のviewWillDisappear:メソッドには、次のコードがあります。

// End receiving events
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[self resignFirstResponder];

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];
        }
    }
}

私を混乱させているのは、これとまったく同じセットアップがiOS6で正常に機能していたことです。iOS7では機能しません。以前はiOS6ではとても簡単でした。iOS7SDKで根本的に何かが変更されました。何が足りないのですか?

24
codejunkie

私はなんとかこれを解決しました、そしてここに別の貧しい魂によって引っ張られる髪を救うために行きます:

まず、Info.plistがオーディオをバックグラウンドモードとして正しくリストしていることを確認します。

(私が何について話しているのかわからない場合は、YOURAPPNAME-Info.plistを選択してください。プラス記号をクリックし、UIBackgroundModesという名前の新しいキーを追加して展開します。audioという名前の値を追加します。)

オーディオを作成している再生オブジェクトへの参照が必要になります。私はオーディオのみを再生していて、AVplayerはバックグラウンドオーディオを順守していなかったので、ビューコントローラーのヘッダーでこれを使用します。

_@property (nonatomic, retain) MPMoviePlayerController *audioPlayer;
_

実装では、次のことを行います。

_ [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];
_

そして

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

    //End recieving events
    [[UIApplication sharedApplication] endReceivingRemoteControlEvents];
    [self resignFirstResponder];
_

2つのメソッドを追加します

_//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];
}
_

すべての重要なコード-これにより、アプリは「コントロールセンター」とロック画面からオーディオを制御できるようになります。

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

    if (receivedEvent.type == UIEventTypeRemoteControl) {

        switch (receivedEvent.subtype) {

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

            default:
                break;
        }
    }
}
_

ここに多くの種類のイベントタイプを追加して、任意のメソッドを呼び出すことができます。

典型的なイベントは次のとおりです。

_ 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,
_

ヘルプをデバッグするには、次を使用できます。

_ 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;
_

そしてそれはそれです-それがそこに誰かを助けることを願っています! -これは、ストーリーボードアプリを備えたiOS7とiOS6で完全に機能しているだけでなく、ヘッドフォンとすべての新しいコントロールセンターを使用した制御も可能です。

16
codejunkie

IOSアップデート7.0.3でこの問題が修正されたため、問題はApple側にあったようです。 AlexがUIEventSubtypeの変更について指摘したことに加えて、iOS6で機能していたコードがiOS7でも機能するようになりました。

完全を期すために、これがiOS6とiOS7の両方で機能している私の関連コードです-7.0.3への更新後。プロジェクトのビルドフェーズ->バイナリとライブラリのリンクにAVFoundation.frameworkとMediaPlayer.frameworkも含まれています。アプリデリゲートにはこのためのコードはありません。

Viewcontroller .hファイル:

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

@interface NewsDetailViewController : UIViewController <UIWebViewDelegate, AVAudioSessionDelegate>
@property (nonatomic) MPMoviePlayerController *audioPlayer;

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;
        }
    }
}
7
MikeFieldsNE

IPhoneとシミュレーターでもバックグラウンドでオーディオを再生する場合は、このコードをplistに記述する必要があります。まず、Info.plistがオーディオをバックグラウンドモードとして正しくリストしていることを確認します。

(私が何について話しているのかわからない場合は、YOURAPPNAME-Info.plistを選択してください。プラス記号をクリックしてキーUIBackgroundModesを入力し、入力してください。「アプリはオーディオを再生します」(シミュレーターの場合)または「アプリは再生します」という値を追加しますAirPlayを使用してオーディオまたはオーディオ/ビデオをストリーミングする」(iPhoneの場合)。

enter image description here

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;
    }];
}

これらの2つのフレームワークをプロジェクトに追加し、コードをViewController.hに追加します。

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

@interface ViewController : UIViewController <UIWebViewDelegate, AVAudioSessionDelegate>
@property (nonatomic) MPMoviePlayerController *audioPlayer;

これらのフレームワーク参照をプロジェクトに追加する必要があることに注意してください。

次に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];
}

IPhoneやシミュレーターでもバックグラウンドでオーディオを再生するのに役立つことを願っています。

6
chandan

リモートコントロールイベントを使用するiOS6とiOS7の違いの1つは、iOS6では再生/一時停止イベントが1つのUIEventSubtypeとして提供されたことです。
UIEventSubtypeRemoteControlTogglePlayPause
そしてiOS7では、それらは2つの別々のサブタイプとして提供されます。
UIEventSubtypeRemoteControlPause
UIEventSubtypeRemoteControlPlay

4
Alex Lindblad

私もこの解決策を見つけることに興味があるので、私は私の側からいくつかの情報を追加します。

同じ問題が発生していますが、それでもAppleドキュメントはリモートコントロールのイベント管理について変更されていません。

何かを動かしてみたところ、何か面白いことが起こりました。

私はもともと、TabBarコントローラーでリモートコントロールイベント管理を行っていました。プレーヤービューコントローラーですべてを移動したので、ヘッドセットで音楽の再生を再び制御できることがわかりますが、iOS7の新しいコントロールパネル(画面の下から来るもの)のボタンからは制御できません。

これはかなり奇妙です。

この問題を解決するために、テストでスレッドを充実させてみましょう。

0
super