MusicKit
(MusicKit의 구조는 별로 안 궁금하고 사용법만 알고 싶다면 다음 포스팅부터 보길 추천한다.)
이번에 음악 일기를 제작하게 되면서 음악 서비스를 어떻게 제공할 것인가를 가장 크게 고민했다.
디자인과 기획은 이미 나와있는 상태이지만, 음악을 제공할 수 없다면 결국 제작을 시작도 할 수 없으니 말이다.
그러던 중 apple music과 연동하여 음악을 검색 및 재생할 수 있는 MusicKit를 알게 되었고,
해당 프레임워크로 프로젝트를 제작하기로 결정했다.
여러 방면으로 검색을 해봤지만, 한국어로된 블로그 포스팅도 제한적이고 영어로 된 자료도 생각보다 많이 찾을 수 없었다.
그래서 공식 다큐먼트를 하나하나 뜯어보면서 해당 프레임워크를 사용하기로 했는데,
의외로 분량이 많지 않아 다 알아보는데 그렇게 오랜 시간이 걸리지는 않았다.
물론 하나하나 블로그로 옮기면 꽤 많은 분량이 되겠지만,
내가 주요하게 사용한 부분들에 대해서만 조금 상세하게 작성해보도록 하겠다.
전문적인 음악 플레이어 같은 서비스를 만들기에는 부족하지만, 단순히 음악을 검색, 저장, 실행만 하는 정도의
기능이 필요하다면 아마 이 포스팅 시리즈만으로 충분할거라 믿는다.
또한 MusicAPI와 관련된 내용은 이 포스팅 시리즈에는 포함하지 않을 예정이다.
애초에 MusicKit이 MusicAPI를 기반으로 Swift 개발자들이 액세스 토큰 관리나 엔드포인트를 좀 더 쉽게
관리할 수 있도록 만들어진 프레임워크이기에 MusicKit만 알아도 충분하다고 생각한다.
목차
- Software Requirements - 버전 요구사항
- Authorization Status - MusicKit 사용 권한
- MusicSubscription - 애플 뮤직 구독 상태
- MusicItem, PlayableMusicItem - 재생할 음악
- CatalogSearch - 음악 검색
- MusicPlayer - 음악 플레이어
System Requirements

MusicKit은 위와 같은 플랫폼 버전에서만 사용할 수 있다고 하니 참고하도록 하자.
Authorization Status
MusicKit은 사용자에게 사용권한을 요청해야한다. 사용권한을 설정하지 않고 액세스하게 될 경우,
카메라나 다른 권한 요청이 필요한 프레임워크와 마찬가지로 앱이 강제종료된다.

따라서 프로젝트를 생성했다면 info.plist에 접근하여 NSAppleMusicUsageDescription을 작성하고 시작하도록 하자.
info에 해당 권한에 대한 설명을 작성했다면 실제 UI상으로 사용자에게 권한을 요청해야한다.

static 변수인 currentStatus로 현재 MusicKit 사용 권한의 상태를 확인 할 수 있다.
권한 상태에 따라 request() 함수를 통해 간단하게 권한을 요청할 수 있다.
이 때 request는 비동기 함수이다.
앱의 도입부인 ContentView에서 처리해도 되고, 아니면 MusicKit이 필요한 코드에 도달했을 때 처리해도 되고 그건 자유
MusicSubscription
이 부분도 내용이 많지는 않지만 음악을 재생할 때 프리뷰를 재생할 지, 전체 곡을 재생할 지 정할 수 있기 때문에 알아둬야한다.
MusicSubscription 자체는 struct로 구조체 형태이며 현재 사용자가 애플 뮤직을 구독했고 음악을 재생할 권한이 있는지
확인할 수 있게 해준다.

위 두개의 변수로 판단을 할 수 있다. 사실 canPlayCatalogContent만 보더라도 알 수 있긴하다.
canPlayCatalogContent가 true일 경우 현재 사용자는
애플 뮤직을 구독한 상태이므로 MusicPlayer를 통해 전체 음악을 재생할 수 있다.
canBecomeSubscriber은 내 프로젝트에서 사용하고 있지는 않지만,
현재 사용자에게 애플 뮤직 구독을 권유하라고 개발자들에게 무언의 압박을 하는 것 같다.
또한, static 변수로 해당 구조체를 받아올 수 있다.
혹은 비동기적으로 구독 상태를 갱신하는 Updates라는 구조체에 접근할 수도 있다.

즉, MusicSubscription.current.canPlayCatalogContent를 통해
사용자의 구독여부를 판단하고 이에 맞게 음악을 재생하면 되겠다.
내 경우 그런 상황이 많지 않을거라 판단해 아직 프로토타입인 현재 프로젝트에
도입하지는 않았지만, 앱을 사용하는 도중 애플 뮤직을 구독해 상태가 변경되는걸 감지하고 싶다면
subscriptionUpdates를 계속 옵저빙하면서 변경사항이 생길때 마다 알아서 처리해주면 되겠다.
Music Item, Playable Music Item
이제 진짜 MusicKit을 사용하는 부분이다.
MusicItem, PlayableMusicItem모두 프로토콜 형태이며,
PlayableMusicItem은 MusicItem을 채택하는 하위 개념이다.


이 둘은 나누는 이유는 간단한데, MusicItem은 단순히 음악 하나만을 의미하는 것이 아니라
플레이리스트, 가수, 앨범등을 아우르는 개념이다.
하지만 가수는 MusicItem이지만 재생할 수 있는 형태는 아니기 때문에 PlayableMusicItem을 채택하지는 않을 것이다.
따라서 PlayableMusicItem을 채택한 MusicItem 타입만이 재생 가능하다고 할 수 있다.

music item의 종류는 위와 같이 존재한다.
이 중 PlayableMusicItem을 채택하는 타입은
Album, Playlist, Song, Station, Track으로 5가지이니 참고하면 되겠다.
Catalog Search
음악을 재생하기 위해서는 먼저 재생할 음악을 화면에 표시해야하고
가장 직관적인 방법은 역시 검색이다.
일반적인 api 요청을 보내듯이 request를 생성하고 해당 request에서 response를 받는 형태이다.


굉장히 심플하게 만들어져있다. 또 페이지네이션까지 제공하니 필요에 따라 페이징도 손쉽게 구현할 수 있다.
검색 쿼리(term)과 어떤 타입의 MusicItem을 검색할 것인지
types를 배열에 담아서 생성자에 넘겨 request 구조체를 생성할 수 있다.
includeTopResults는 명시적으로 제공한 타입이 아니더라도 검색어와
연관성이 높은 검색 결과를 받아볼건지 물어보는거다.
필요한 데이터를 모두 저장했다면 이제 response를 받아볼 수 있다.

아주 친절하게도 response는 타입 변환을 할 필요없이 원하는 아이템들만 쏙쏙 뽑아올 수 있다.

모든 검색 결과는 MusicItemCollection 형태로 저장되어있고,
map reduce forEach등을 사용할 수 있어
배열과 동일한 형태로 다룰 수 있으니 알아두면 된다.
MusicPlayer
이제 음악을 검색하고 선택하는 부분을 알아봤으며 선택한 음악을 재생할 수 있는 MusicPlayer를 알아보겠다.
MusicPlayer는 그 자체로 사용할 수 없는 protocol이며
ApplicationMusicPlayer, SystemMusicPlayer 두개의 플레이어가
MusicPlayer를 채택하는 방식이다.


문서에 적혀있기로 두개의 결정적인 차이점은 AppleMusic 앱에 영향을 주느냐 주지 않느냐라고 한다.
하지만 아직 두 플레이어를 모두 심도있게 사용하지 않아서 인지는 몰라도
굳이 나눌 필요가 있나 싶은 느낌이 들긴한다.
어쨋든 나는 애플 뮤직 앱으로 부터 독립적으로 사용할 수 있는 ApplicationMusicPlayer를 사용하기로 결정했다.
그리고 이 두개의 플레이어가 작동하게 하기 위해서는 앞서 작성한 구독 여부를 확인해야한다.
구독을 하지 않은 상태라면 아무리 뭘 넣고 코드를 수정해봐도
노래는 절대 재생되지 않는다는 걸 알게 될 것이다.
이제 어떻게 MusicPlayer를 사용하는지 알아보자.
먼저 노래를 재생하기 위해서는 선택한 노래를 플레이어에
cd를 넣듯 넣어야 할 것이다.
그 과정은 PlayableMusicItem을 queue에 넣는 방식으로 진행된다.

이 queue는 어째서인지 양 플레이어 모두 가지고 있음에도
프로토콜에 추가되지 않고 각자 독립적으로 사용하고 있다.
이 이유는 모르겠으나 어쨋든 우리는 PlayableMusicItem들을
배열 형태로 만들어서 직접 queue에 할당하거나
Queue 생성자를 통해 할당해줄 수 있다.
queue에 재생할 목록을 추가했다면 이제 재생을 관리해야하는데,
그와 관련된 함수 및 변수는 모두 프로토콜에 선언되어있다.


playbackTime은 set을 지원하기 때문에 이 값을 조정하여 음악의 특정 시간대로 재생 시간을 옮길 수 있다.
또 하나 알아둘 것이 있다면 prepareToPlay함수가 실행되면 앱이 아닌
디바이스 전체에서 재생중인 모든 형태의 미디어는 일시정지 상태가 된다.
'iOS' 카테고리의 다른 글
| [Swift] MusicPlayer로 음악 플레이어를 만들어보자 - 3 (0) | 2025.06.30 |
|---|---|
| [Swift] MusicKit으로 음악 검색기능 구현하기 - 2 (0) | 2025.06.29 |
| [Swift] Supabase에서 받아온 created_at이 디코딩 되지 않을 때 (0) | 2024.10.17 |
| [Swift] 1인 앱 개발로 사용할 기술 스택 및 서비스 (4) | 2024.10.02 |
| [SwiftUI] onAppear는 화면이 그려진 뒤에 불리는 함수가 아니다? (0) | 2024.09.25 |