再生ロック画面通知バー表示#
背景#
音声を再生する際、通知画面に表示され、音声再生を制御できることを望んでいます。以前の要件では、バックグラウンドに入ると再生が一時停止するため、通知画面を開くたびに再生が一時停止し、音楽プレーヤーのような効果を見ることができませんでした。その後、バックグラウンドでの一時停止コードを削除すると、通知画面にプレーヤーが表示されるようになりましたが、制御できず、進行状況もありませんでした。
実装#
バックグラウンド再生のサポート#
まず、APP がバックグラウンド再生をサポートする必要があります。つまり、一方でバックグラウンドに入ると再生が一時停止するコードロジックを削除し、もう一方で Target -> Signing & Capabilities で Backgroud Modes を追加し、Audio, AirPlay, and Picture in Picture を有効にします。画像は以下の通りです:
AVAudioSession
を設定する際、再生前に実際のニーズに応じて設定し、再生後に閉じます。
AVAudioSessionCategory
タイプ
Category タイプ | "サイレント" またはロック画面時にサイレントになるか | 他のサポート混合アプリと混合再生できるか | バックグラウンドサポート | シーンの例 |
---|---|---|---|---|
AVAudioSessionCategoryAmbient | はい | はい | いいえ | アプリのバックグラウンド音に一般的に使用され、ゲームをプレイ中に音楽を聴くことができます |
AVAudioSessionCategorySoloAmbient | はい | いいえ | いいえ | 同様にバックグラウンド音ですが、ゲームをプレイ中に音楽を聴きたくないシーンに使用されます |
AVAudioSessionCategoryPlayback | いいえ | デフォルトではできませんが、サポート可能 | はい | 音楽再生中、ロック画面でも音楽を聴くことができます |
AVAudioSessionCategoryRecord | いいえ | いいえ、録音のみ | はい | 録音機、録音中は他の音楽は再生できません |
AVAudioSessionCategoryPlayAndRecord | いいえ | デフォルトでは可能、録音も再生もできます | はい | 再生しながら録音する、例えば VOIP のようなシーン |
AVAudioSessionCategoryAudioProcessing | いいえ | いいえ、ハードウェアデコード音声、再生および録音できません | はい | 音声フォーマット処理に使用されます |
AVAudioSessionCategoryMultiRoute | いいえ | はい、複数の入出力 | いいえ | ヘッドフォン、USB デバイスが同時に再生されます |
AVAudioSessionCategoryOption
タイプ
CategoryOption タイプ | 説明 | 適用カテゴリ |
---|---|---|
AVAudioSessionCategoryOptionMixWithOthers | 他のアプリと混合再生をサポート | AVAudioSessionCategoryPlayAndRecord、AVAudioSessionCategoryPlayback、AVAudioSessionCategoryMultiRoute |
AVAudioSessionCategoryOptionDuckOthers | 他のアプリの音声音量を下げ、本アプリの音量を強調 | AVAudioSessionCategoryPlayAndRecord、AVAudioSessionCategoryPlayback、AVAudioSessionCategoryMultiRoute |
AVAudioSessionCategoryOptionAllowBluetooth | Bluetooth 音声入力をサポート | AVAudioSessionCategoryRecord、AVAudioSessionCategoryPlayAndRecord |
AVAudioSessionCategoryOptionDefaultToSpeaker | デフォルトの出力音声をスピーカーに設定 | AVAudioSessionCategoryPlayAndRecord |
AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers | アプリが音声再生を使用することがあり、再生中に他のアプリの音声を停止 | AVAudioSessionCategoryPlayback、AVAudioSessionCategoryPlayAndRecord、AVAudioSessionCategoryMultiRoute |
AVAudioSessionCategoryOptionAllowBluetoothA2DP | ステレオ Bluetooth をサポート | AVAudioSessionCategoryPlayAndRecord |
AVAudioSessionCategoryOptionAllowAirPlay | AirPlay デバイスをサポート | AVAudioSessionCategoryPlayAndRecord |
func setupAudioSession() {
do {
// .notifyOthersOnDeactivationを設定し、Activeがfalseのときに有効になり、システムに本アプリの再生が終了したことを通知し、他のアプリの再生を続けることができます
try AVAudioSession.sharedInstance().setActive(true, options: AVAudioSession.SetActiveOptions.notifyOthersOnDeactivation)
// 実際のニーズに応じて異なるCategoryを切り替えます
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, options: AVAudioSession.CategoryOptions.duckOthers)
} catch {
print("set AudioSession error: %@", error)
}
}
ロック画面通知バー表示#
APP がバックグラウンド再生をサポートした後、通知バーに表示されるようになりますが、再生時には進行状況、タイトル、画像がなく、APP の名前と小アイコンのみが表示されます。これらの情報を変更するためのコードは以下の通りです:
#import <MediaPlayer/MPNowPlayingInfoCenter.h>
#import <MediaPlayer/MPRemoteCommandCenter.h>
#import <MediaPlayer/MPRemoteCommand.h>
#import <MediaPlayer/MPMediaItem.h>
// 通知バー表示を更新
- (void)updateNowPlaingInfo {
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
// 曲のタイトルを設定
[dict setValue:@"タイトル" forKey:MPMediaItemPropertyTitle];
// アーティスト名を設定
[dict setValue:@"アーティスト" forKey:MPMediaItemPropertyArtist];
// アルバム名を設定
[dict setValue:@"アルバムタイトル" forKey:MPMediaItemPropertyAlbumTitle];
// 表示する画像を設定
MPMediaItemArtwork *artwork = [[MPMediaItemArtwork alloc] initWithImage:ArtImage];
[dict setValue:artwork forKey:MPMediaItemPropertyArtwork];
// 曲の長さを設定
NSTimeInterval duration = self.player.duration;
[dict setValue:[NSNumber numberWithDouble:duration] forKey:MPMediaItemPropertyPlaybackDuration];
// すでに再生された長さを設定
NSTimeInterval currentTime = self.player.currentTime;
[dict setValue:[NSNumber numberWithDouble:currentTime] forKey:MPNowPlayingInfoPropertyElapsedPlaybackTime];
// 再生速度を設定
[dict setValue:@(1.0) forKey:MPNowPlayingInfoPropertyPlaybackRate];
// 更新
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:dict];
}
再生が完了した後、通知バーに表示しないようにするには、以下のように設定できます。
[[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:@{}];
通知バーで再生を制御するための一時停止、前の曲、次の曲を設定するには、MPRemoteCommandCenter
のプロパティを設定して対応する機能を有効にし、イベントの処理には 2 つの方法があります:
- 方法 1:
remoteControlReceivedWithEvent:
メソッドを使用して、対応するイベントに応答します - 方法 2:
MPRemoteCommandCenter
のCommand
を使用してaddTarget
で対応するイベントを処理します
通知バーの対応機能を有効にするためのコードは以下の通りです:
// AppDelegate内、または対応する再生のController内で、システム制御イベントの受信を開始します
// システム制御イベントを受信
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
[self becomeFirstResponder];
- (void)setupCommandCenter {
MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
[commandCenter.playCommand removeTarget:self];
[commandCenter.pauseCommand removeTarget:self];
// 前の曲、次の曲を無効にします
commandCenter.previousTrackCommand.enabled = NO;
commandCenter.nextTrackCommand.enabled = NO;
// 再生
commandCenter.playCommand.enabled = YES;
// 一時停止
commandCenter.pauseCommand.enabled = YES;
// 再生と一時停止(ヘッドフォン制御)
commandCenter.togglePlayPauseCommand.enabled = NO;
// 進行状況をドラッグ
commandCenter.changePlaybackPositionCommand.enable = YES;
}
イベント応答処理方法 1 のコードは以下の通りです:
// リモートイベントに応答
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
if (event.type == UIEventTypeRemoteControl) {
switch (event.subtype) {
case UIEventSubtypeRemoteControlPlay:
{
NSLog(@"RemoteControlEvents: 再生");
}
break;
case UIEventSubtypeRemoteControlPause:
{
NSLog(@"RemoteControlEvents: 一時停止");
}
break;
case UIEventSubtypeRemoteControlTogglePlayPause:
NSLog(@"ヘッドフォン制御:一時停止||再生");
break;
case UIEventSubtypeRemoteControlNextTrack:
{
NSLog(@"RemoteControlEvents: 次の曲");
}
break;
case UIEventSubtypeRemoteControlPreviousTrack:
{
NSLog(@"RemoteControlEvents: 前の曲");
}
break;
default:
break;
}
}
}
イベント応答処理方法 2 のコードは以下の通りです:
- (void)setupCommandCenter {
MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
// 再生
[commandCenter.playCommand addTargetWithHandler:^MPRemoteCommandHandlerStatus(MPRemoteCommandEvent * _Nonnull event) {
NSLog(@"再生");
return MPRemoteCommandHandlerStatusSuccess;
}];
// 一時停止
[commandCenter.pauseCommand addTarget:self action:@selector(handlePauseCommand:)];
// 進行状況をドラッグ
[commandCenter.changePlaybackPositionCommand addTarget:self action:@selector(handlePlaybackPositionCommand:)];
}
- (MPRemoteCommandHandlerStatus):(id)sender {
NSLog(@"一時停止");
return MPRemoteCommandHandlerStatusSuccess;
}
- (MPRemoteCommandHandlerStatus)handlePlaybackPositionCommand:
(MPChangePlaybackPositionCommandEvent *) event
{
[self.palyer seekToTime:CMTimeMakeWithSeconds(event.positionTime, 1)];
NSLog(@"changePlaybackPosition to %f", event.positionTime);
return MPRemoteCommandHandlerStatusSuccess;
}
問題#
#
beginReceivingRemoteControlEvents
を追加しない場合、通知バーは表示されますか? それは 2 つの方法の処理に影響しますか?
応答イベント処理方法 2 の応答が 2 回呼び出される
カスタム再生の進行状況と通知バーの進行状況が一致しない