見出し画像

【Tech Blog】iOS 向け音楽プレイヤーの実装について

みなさんこんにちは。
セガエックスディー 開発チームの齋藤です。

前回の記事では
Android での音楽プレイヤーの実装方法 についてご紹介しました。

今回は Objective-C で iOS の音楽プレイヤー実装も行ったため、そちらの紹介をしていきたいと思います。



■ 今回サンプルコードで実装できるもの

コードの説明に入る前に、音楽プレイヤーを実装するにあたって知っておきたい要素について紹介します。


AVAudioSession
アプリ上での音楽の利用方法を OS に伝えるもの
※参考:https://developer.apple.com/documentation/avfaudio/avaudiosession

 

MPRemoteCommandCenter
イヤホンやコントロールセンターなどからのリモートコントロールイベント(再生/停止など)を取得するもの
※参考:https://developer.apple.com/documentation/mediaplayer/mpremotecommandcenter

 

MPNowPlayingInfoCenter
アプリが再生する音楽の情報を設定するためのもの
※参考:https://developer.apple.com/documentation/mediaplayer/mpnowplayinginfocenter

 

AVAudioPlayer
音楽ファイルの再生を行うもの
※参考:https://developer.apple.com/documentation/avfaudio/avaudioplaye


■ サンプルコード

1.プロジェクト作成

まずは Xcode で新規プロジェクトを作成します。
今回は以下の環境にて実装を進めていきます。
Xcode 14.0.1
Interface : storyboard
Language : Objective-C

プロジェクトを作成できたら StoryBoard にボタンを 2 つ追加します。



2.プロジェクト設定

続けて、プロジェクトに適当な音楽ファイルを追加します。
サンプルでは examplebgm.wav という名前のファイルを追加しています。


また、アプリがバックグラウンドにいっても音楽が流れ続けるように設定します。
Capability に「 BackgroundModes 」を追加し、「 Audio, AirPlay, and Picture in Picture 」にチェックを入れてください。



3.音楽再生

Play / Stop ボタンのイベントと AVAudioSession 、AVAudioPlayer を使用して音声ファイルの再生/停止の制御を行っていきます。
まずは使用するメソッドを ViewController.h に記載していきます。

  

ViewController.h

```
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import <MediaPlayer/MediaPlayer.h>
@interface ViewController : UIViewController
@property AVAudioPlayer* player;
@property AVAudioSession  *audioSession;
-(void) setup;
-(void) audioPlay;
-(void) audioPause;
-(MPRemoteCommandHandlerStatus)doPlay:(MPRemoteCommandEvent*)event;
-(MPRemoteCommandHandlerStatus)doPause:(MPRemoteCommandEvent*)event;
-(IBAction)onStopButton:(id)sender;
-(IBAction)onPlayButton:(id)sender;
@end
```


ViewController.m

```
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self setup];
}
- (void) setup {
    // audio設定
    NSString *path = [[NSBundle mainBundle] pathForResource:@"examplebgm" ofType:@"wav"];
    NSURL *url = [NSURL fileURLWithPath: path];
    self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
    
    // audio再生の管理のためAVAudioSessionの設定
    self.audioSession = [AVAudioSession sharedInstance];
    NSError *error = nil;
    [self.audioSession setCategory:AVAudioSessionCategoryPlayback error:&error];  
}
// audio再生処理
- (void) audioPlay {
    [self.audioSession setActive:YES error:nil];
    [self.player play];
}
// audio一時低処理
- (void) audioPause {
    [self.audioSession setActive:NO error:nil];
    [self.player pause];
}
// UI上の再生ボタンが押された
- (IBAction)onPlayButton:(id)sender {
    [self audioPlay];
}
// UI上の一時停止ボタンが押された
- (IBAction)onStopButton:(id)sender {
    [self audioPause];
}
@end

```



4.リモートコントロールセンターでの制御

次に、リモートコントロールセンターでの再生/停止制御ができるようにしていきます。
具体的には、ViewController.m に MRRemoteCommandCenter の各種制御処理と、MPNowPlayingInfoCenter に情報設定などの実装をしていきます。

 

ViewController.m

```
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self setup];
}
- (void) setup {
    // audio設定
    NSString *path = [[NSBundle mainBundle] pathForResource:@"examplebgm" ofType:@"wav"];
    NSURL *url = [NSURL fileURLWithPath: path];
    self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
    
    // audio再生の管理のためAVAudioSessionの設定
    self.audioSession = [AVAudioSession sharedInstance];
    NSError *error = nil;
    [self.audioSession setCategory:AVAudioSessionCategoryPlayback error:&error];
    
    // リモートイベント
    MPRemoteCommandCenter *commandCenter = [MPRemoteCommandCenter sharedCommandCenter];
    // 再生
    [commandCenter.playCommand setEnabled:YES];
    [commandCenter.playCommand addTarget:self action:@selector(doPlay:)];
    // 一時停止
    [commandCenter.pauseCommand setEnabled:YES];
    [commandCenter.pauseCommand addTarget:self action:@selector(doPause:)];
    
    NSDictionary *info = @{
        MPMediaItemPropertyTitle:  @"音楽プレイヤーサンプル",
        MPMediaItemPropertyAlbumTitle: @"サンプル"
    };
    [[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:info];
}
// audio再生処理
- (void) audioPlay {
    [self.audioSession setActive:YES error:nil];
    [self.player play];
}
// audio一時低処理
- (void) audioPause {
    [self.audioSession setActive:NO error:nil];
    [self.player pause];
}
// RemoteCommandEventで再生イベントを取得した (イヤホンやリモートコントロールセンターで再生ボタンが押された)
- (MPRemoteCommandHandlerStatus)doPlay:(MPRemoteCommandEvent*)event{
    [self audioPlay];
    return MPRemoteCommandHandlerStatusSuccess;
}
// RemoteCommandEventで一時停止イベントを取得した (イヤホンやリモートコントロールセンターで停止ボタンが押された)
- (MPRemoteCommandHandlerStatus)doPause:(MPRemoteCommandEvent*)event{
    [self audioPause];
    return MPRemoteCommandHandlerStatusSuccess;
}
// UI上の再生ボタンが押された
- (IBAction)onPlayButton:(id)sender {
    [self audioPlay];
}
// UI上の一時停止ボタンが押された
- (IBAction)onStopButton:(id)sender {
    [self audioPause];
}
@end

```



■ 動作確認

コードが実装できたら実際に実行してみます。
アプリが起動したら Play ボタンを押すことで音声の再生されること、Pause ボタンで音声が停止されることを確認してみてください。



また、リモートコントロールセンターを開くと「音楽プレイヤーサンプル」と表示され、リモートコントロールセンターから再生 / 一時停止を制御できることを確認してください。

ここまでできたら今回は完了となります。


■ まとめ

いかがでしたでしょうか。

今回は iOS 版を紹介しましたが、前回の Android 版と比べるとかなり少ないコードで実装できる印象を受けたのではないでしょうか。
実際、Android よりは自由度が少し落ちるものの、かなり楽に実装が可能になっています。
このブログでは Objective-C による実装を紹介しましたが、基本的な考え方は Swift でも同様ですので、興味がある方はぜひお好きな言語で実装してみてください。

また、今回のサンプルコードでは、前回の Android 版の記事と同じく、音楽アプリにとって最低限の機能を実装しています。
実際の音楽アプリを作ろうと思うと、まだオーディオフォーカスの制御であったり、イヤホンの接続が外れた際の処理なども考慮していかなければなりません。ただし、マスターすれば音声を扱うアプリは色々と実装の幅が広がるのではないでしょうか。

ぜひオリジナルのオーディオプレイヤーアプリの実装を試してみてください。


執筆:齋藤 夕貴|株式会社セガ エックスディー

セガ エックスディーで、Unity をメインに様々なシステムの開発を行なっています。最近はインフラや web 周りも勉強中です。xR 系コンテンツ開発が好きです。


■ SEGA XD HP:https://segaxd.co.jp/
■ SEGA XD 公式 X(旧Twitter):https://twitter.com/SEGAXD_PR
■ SEGA XD 公式 Facebook:https://www.facebook.com/segaxd.fb/
■ CX School 公式 Youtube:https://www.youtube.com/@cxschool
■ SEGA XD 公式 TikTok:https://www.tiktok.com/@segaxd_official