iOS9.3からApple Musicの曲の再生とプレイリストの作成ができるようになりましたが、下記のように何かと不便なことが多いと感じていました
- 再生する曲の順番が指定しにくい
- ローカルにDLしていないアートワーク(
MPMediaItemArtwork
)が表示されない - 再生中の曲のStore ID(Apple Musicを再生するための曲ごとのID)が拾えない
- プレイリストを取得した後にすぐ曲の追加ができない(前にそのことについて発表したスライド)
- プレイリストの削除や変更ができない
今回のアップデートでは 1. が解決されました👏 iOS10.1 APIDiffs - MediaPlayer
- Xcode Version 8.1 beta
- iOS Version 10.1 beta
MPMusicPlayerController.setQueueWith(_: MPMusicPlayerQueueDescriptor)
今まで使っていたのは下記のメソッドで、ただ単にMPMusicPlayerController
にApple Music用のStore IDの配列を渡すだけものでした
player.setQueueWithStoreIDs(storeIds)
今までのメソッドでは何が問題かというと、複数の曲を最初から再生するには問題がないのですが、2曲目とか3曲目などの途中から再生する場合は自前で実装するしかありませんでした
ちなみに私のアプリではこのような酷い実装をしていました😌(スライシングでもできます)
// collectionView(_:didSelectItemAt:)
let selectedStoreIds = trackIds.enumerated().filter { $0.offset >= indexPath.row }.map { $0.element }
+ trackIds.enumerated().filter { $0.offset < indexPath.row }.map { $0.element }
player.repeatMode = .all
player.setQueueWithStoreIDs(selectedStoreIds)
何をやっているかというと、タップした曲から前の曲を後ろにつなげて再生モードをリピートにすることで選択した曲の前の曲も戻るボタンなどで聴けるようにしていた感じです…
しかし今回のメソッドではMPMusicPlayerQueueDescriptor
という再生する曲を管理するクラスが渡せるようになりました👏
上記のクラスは直接使用せずにサブクラスのMPMusicPlayerMediaItemQueueDescriptor
(ローカル用)かMPMusicPlayerStoreQueueDescriptor
(Apple Music用)を使います
MPMusicPlayerStoreQueueDescriptor
使い方は簡単で初期化をStore IDの配列で行い、その後に再生したいStore IDを指定するだけです
// collectionView(_:didSelectItemAt:)
let descriptor = MPMusicPlayerStoreQueueDescriptor(storeIDs: trackIds)
descriptor.startItemID = trackIds[indexPath.row]
player.setQueueWith(descriptor)
他にも再生や終了位置も指定できるみたいです(どんな時に使うのかわからないですが…)
descriptor.setStartTime(10.0, forItemWithStoreID: storeId)
descriptor.setEndTime(30.0, forItemWithStoreID: storeId)
MPMusicPlayerController.prepareToPlay(completionHandler: (Error?) -> Swift.Void)
次は再生が可能になるまで曲データの準備(ダウンロード)を行ってくれるメソッドです
今までのprepareToPlay()
はもともと(たぶん)ローカルの曲の再生準備をするために用意されたメソッドで、そこまで時間のかかる処理ではないからかそのまま使うと同期処理で行われてしまいます
しかしApple Musicはオンライン再生なのでDLに時間がかかり、その前にnowPlayingItem
のアートワークを取り出したりすると表示されなかったり、なぜ再生されないのか原因が分からなかったりとっても不便でしたが、今回から非同期かつエラーもハンドリングできるようになりました👏
playerViewController.player.prepareToPlay(completionHandler: { error in
if error == nil {
player.play()
} else {
print(error?.localizedDescription)
}
})
MPError
ちゃんとメディアプレイヤー用のエラーが定義されているようです
struct MPError {
init(_nsError _nsError: NSError)
static var _nsErrorDomain: String { get }
enum Code : Int {
typealias _ErrorType = MPError
case unknown
case permissionDenied
case cloudServiceCapabilityMissing
case networkConnectionFailed
case notFound
case notSupported
}
static var unknown: MPError.Code { get }
static var permissionDenied: MPError.Code { get }
static var cloudServiceCapabilityMissing: MPError.Code { get }
static var networkConnectionFailed: MPError.Code { get }
static var notFound: MPError.Code { get }
static var notSupported: MPError.Code { get }
}
ということで、まだまだ課題はたくさんありますがみなさんでApple Musicを使った音楽アプリをどんどん広めていきましょう👋😎