現在、iOS 4用に開発しているアプリのバックグラウンドオーディオを設定しようとしています。ただし、Pandoraなどの他のバックグラウンドオーディオアプリとは異なり、アプリには専用の音楽プレーヤーviewController
がありません。タスクが少し混乱します。
適切なInfo.plist
設定を正しく設定し、アプリデリゲートにAVAudioPlayer
オブジェクトがあり、どこからでもアクセスできます。ユーザーが曲を再生するとき、私はAVAudioPlayer
をその曲で初期化された新しいものに置き換えて、それを再生します。これはすべてうまく機能しますが、リモートコントロールイベントをサポートする方法がわかりません。
Appleのドキュメントに基づいて、私はこれを持っています:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[UIApplication sharedApplication] endReceivingRemoteControlEvents];
[self resignFirstResponder];
}
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
switch(event.subtype) {
case UIEventSubtypeRemoteControlTogglePlayPause:
if([iPhoneAppDelegate backgroundAudioPlayer].playing)
[iPhoneAppDelegate pauseBackgroundAudioPlayer];
else
[iPhoneAppDelegate playBackgroundAudioPlayer];
break;
}
}
問題は、これをどこに置くかということです。 Appleのドキュメントは、これがどこかのView Controllerに含まれるべきだと示唆しているようですが、私のアプリには多くのViewControllerとNavigationControllerがあります。これをどこに置いても、何らかの理由でマルチタスクトレイのリモコンの[再生/一時停止の切り替え]ボタンをタップすると、曲が一時停止してから一時停止が解除されるか、何らかの理由で曲が2回再生されます。
少し検索した後、Apple開発者フォーラムでグローバルリモートコントロールイベントを受信するためのいくつかの解決策を見つけました。
1つの方法は、UIWindow
をサブクラス化し、そのremoteControlReceivedWithEvent:
をオーバーライドすることです。
2番目の、おそらくより良い方法は、UIApplication
をサブクラス化し、sendEvent:
をオーバーライドすることです。このようにして、すべてのリモートコントロールイベントをインターセプトしてグローバルに処理し、レスポンダーチェーンの後半で他のレスポンダーに処理させることはできません。
- (void)sendEvent:(UIEvent *)event {
if (event.type == UIEventTypeRemoteControl) {
// Handle event
}
else
[super sendEvent:event];
}
ドキュメントの例は少し誤解を招く可能性がありますが、どこにもサブクラス化する必要はありません。 remoteControlReceivedWithEvent:を配置する正しい場所は、アプリがフォアグラウンドにあるかどうかに関係なく、レスポンダーチェーンに残るため、アプリケーションデリゲートにあります。また、リモートコントロールイベントの受信の開始/終了は、ランダムビューの可視性ではなく、実際にイベントが必要かどうかに基づいて行う必要があります。
2番目のメソッドは機能しませんでした。sendEvent
は呼び出されませんでした。ただし、最初の方法はうまく機能しました(UIWindow
をサブクラス化)。
私はしばらくこれに苦労しました、そして上記の答えのどれもうまくいきませんでした。私のコードのバグ、そしてそれが誰かがこれを読むのに役立つことを願っていますが、AudioSessionを他の人とミックスするように設定したことでした。リモートコントロールイベントを取得するには、フォアグラウンドオーディオプレーヤーになりたいと考えています。次のような誤ったコードがあるかどうかを確認してください。
[[AVAudioSession sharedInstance] setDelegate: self];
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryPlayback error: nil];
UInt32 doSetProperty = 0;
AudioSessionSetProperty (
kAudioSessionProperty_OverrideCategoryMixWithOthers,
sizeof (doSetProperty),
&doSetProperty
);
NSError *activationError = nil;
[[AVAudioSession sharedInstance] setActive: YES error: &activationError];
そして、AudioSessionSetPropertyを削除するか、doSetPropertyを1に変更します。
この動作に影響を与えると思われるものの1つは、setCategory:error:の代わりにsetCategory:withOptions:error:を使用してAVAudioSessionに設定したカテゴリオプションです。特に、試行錯誤の結果、AVAudioSessionCategoryOptionMixWithOthersを設定した場合、リモートコントロールイベントは取得されないようです。現在再生中のコントロールは引き続きiPodアプリを制御します。 AVAudioSessionCategoryOptionDuckOthersを設定すると、リモートコントロールイベントが発生しますが、どのアプリが制御されているかに関してあいまいさがあるようです。 categoryOptionsを0に設定するか、setCategory:error:を呼び出すだけが最適です。
Windowをサブクラス化したり、イベントを転送したりする必要はありません。メインのViewControllerから処理するだけです。詳細については、オーディオミキサー(MixerHost)の例を参照してください。