티스토리 뷰

반응형

안녕하세요 Pingu입니다.

 

iOS에서 이 부분 다들 아시나요?

음악이나 동영상 같은 콘텐츠들을 해당 콘텐츠를 제공하는 앱에서 제어하는 것이 아닌 다른 곳에서 제어할 수 있도록 하는 리모컨 같은 역할을 하는 기능인데 iOS를 사용하신다면 한 번쯤 써보셨을 거예요. 즉 앱이 백그라운드에 있을 때 제어할 수 있도록 하는 것이죠.

 

이번 글에서는 iOS 개발을 할 때 이러한 기능을 추가하기 위한 방법을 알아보기 전에 음악이나 동영상을 백그라운드에서 재생가능하도록 하는 작업부터 해보려고 합니다.

 

바로 제어하는 기능을 추가하는 방법을 보려면 여기를 보시면 됩니다!

 

사용할 음악 파일은 아래 링크에서 받을 수 있어요! 

 

file-examples.com/index.php/sample-audio-files/sample-mp3-download/

 

Sample .mp3 download | File Examples Download

MP3 (MPEG-1 Audio Layer-3) is a standard technology and format for compressing a sound sequence into a very small file while preserving the original level of sound quality when it is played. MP3 provides near CD quality audio. It is one of the most common

file-examples.com

 

일단 Xcode로 프로젝트를 하나 만들고 아까 받은 sample.mp3도 프로젝트에 포함합니다. 그런 뒤 아래와 같이 화면을 하나 만들어볼게요. 아래에서 보이는 컨트롤러의 이름은 AudioViewController라고 정했습니다.

play 버튼, pause 버튼, 그리고 나중에 사용할 video 버튼을 만들었습니다. 일단 play, pause 버튼으로 sample.mp3를 재생, 일시정지 할 수 있도록 액션을 추가해볼게요~ 위의 화면의 뷰 컨트롤러에 가서 아래와 같이 만들어 줍니다.

import UIKit
import AVFoundation

class ViewController: UIViewController, AVAudioPlayerDelegate {
    
    var player: AVAudioPlayer!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.initPlayer()
        
    }

    @IBAction func touchUpPlayButton(_ sender: UIButton) {
        // 재생 합니다.
        self.player.play()
    }
    
    @IBAction func touchUpPauseButton(_ sender: UIButton) {
        // 재생을 멈춥니다.
        self.player.pause()
    }
    
    func initPlayer() {
        // 음악 파일 가져오기
        guard let soundAsset: NSDataAsset = NSDataAsset(name: "sample") else {
            print("음악 파일이 없습니다.")
            return
        }
        
        // audio player를 초기화합니다.
        do {
            try self.player = AVAudioPlayer(data: soundAsset.data)
            self.player.delegate = self
            self.player.play()
        } catch let error as NSError {
            print("플레이어 초기화 오류 발생 : \(error.localizedDescription)")
        }
    }
    
    @IBAction func touchUpVideoButton(_ sender: UIButton) {
        
    }
    
}

위의 코드는 그냥 audio player를 초기화 하고 재생하며 play, pause 버튼을 눌렀을 때 각자의 이벤트를 액션으로 만들어준 코드입니다. 이번 글에서는 MPRemoteController에 대한 글이니 위의 코드에 대한 자세한 설명은 넘어가겠습니다.

 

일단 이렇게 하셨으면 앱을 실행하면 재생도 되고 play, pause 버튼도 잘 작동될 거예요.

그런데 글의 도입부에서 본 화면들은 보통 음악 앱을 백그라운드로 보냈을 때 즉, 음악 앱으로 음악은 듣지만 다른 앱도 함께 사용할 때 주로 사용하지 않나요?

지금의 앱은 홈 화면으로 이동하면 노래가 꺼질 거예요. 따라서 앱이 백그라운드로 가더라도 음악이 재생되도록 만들어줘야 합니다!

 

이에 대한 설명을 애플에서 알려줍니다.

 

일단 app target으로 가서 capability 탭으로 이동해줍니다.

그런 뒤 위의 그림에 동그라미 된 부분을 눌러서

얘를 추가해줍니다.

그리고 앱에서 허용할 백그라운드 작업을 선택해주시면 되는데요, 지금은 음악이나 비디오 같은걸 백그라운드에서 재생하고 싶으니 위와 같이 체크해주시면 됩니다.

 

이렇게 하면 음악이 홈 화면으로 가면 재생이 되느냐? 하면 안 됩니다.ㅎㅎ

애플 문서에서 developer.apple.com/documentation/avfoundation/avaudiosession 여기를 참고하면 방법이 나오게 되는데, 한 번 해보겠습니다.

 

AudioSession에 대한 설명이 위와 같이 나오는데 해석해보면 앱에서 오디오를 사용할 방식을 시스템에 전달하는 객체라고 합니다.

즉 오디오를 사용할 때 백그라운드에서도 사용하겠다!라고 시스템에 알려주는 역할을 한다고 보면 될 것 같아요.

또한 얘는 싱글 톤 객체이며 sharedInstance라는 인스턴스가 존재하니 얘를 사용하라고 하네요.

그리고 초기화를 앱 시작 시 하는 게 좋다고 합니다.

그렇지만 저는 플레이어를 초기화하는 곳에서 얘를 사용해보겠습니다!

아까 코드에서 initPlayer() 부분을 조금 수정하면 됩니다.

func initPlayer() {
    // Audio Session 설정
    let audioSession = AVAudioSession.sharedInstance()
    do {
        try audioSession.setCategory(.playback, mode: .default, options: [])
    } catch let error as NSError {
        print("audioSession 설정 오류 : \(error.localizedDescription)")
    }
    
    // 음악 파일 가져오기
    guard let soundAsset: NSDataAsset = NSDataAsset(name: "sample") else {
        print("음악 파일이 없습니다.")
        return
    }
    
    // audio player를 초기화합니다.
    do {
        try self.player = AVAudioPlayer(data: soundAsset.data)
        self.player.delegate = self
        self.player.play()
    } catch let error as NSError {
        print("플레이어 초기화 오류 발생 : \(error.localizedDescription)")
    }
}

다양한 옵션들이 있지만 지금은 위와 같이만 사용하면 홈 화면에 가더라도 음악이 재생됩니다.

바로 앱을 실행해서 확인하면 아마 음악이 잘 재생될 거예요!

 

음악은 잘 재생되니 동영상도 한 번 백그라운드에서 동작시켜 보겠습니다.

아까 만든 video 버튼을 누르면 동영상이 재생되도록 만들 거예요!

그러기 위해서는 뷰 컨트롤러를 하나 더 만들어서 재생하도록 해볼게요.

이름은 VideoViewController로 하고 stroyboard id는 videoView로 만들었습니다!

뷰는 위와 같이 구성해주었고요~

그리고 AudioViewController를 아래와 같이 touchUpVideoButton을 수정해줍니다.

@IBAction func touchUpVideoButton(_ sender: UIButton) {
    // VideoViewController를 modal로 present 합니다.
    guard let videoVC = self.storyboard?.instantiateViewController(identifier: "videoView") as? VideoViewController else { return }
    videoVC.modalPresentationStyle = .fullScreen
    self.present(videoVC, animated: true, completion: nil)
}

그러고 난 뒤 VideoViewController를 아래와 같이 코딩합니다.

import UIKit
import AVFoundation
import AVKit

class VideoViewController: UIViewController {

    @IBOutlet var videoView: UIView!
    var videoPlayer: AVPlayer!
    var videoPlayerViewController: AVPlayerViewController!
    
    override func viewDidLoad() {
        super.viewDidLoad()

        makeVideoView()
    }

    func makeVideoView() {
        
        guard let url = URL(string: "https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-mp4-file.mp4") else {
            print("url 오류")
            return
        }
        // video 플레이어를 초기화 합니다.
        self.videoPlayer = AVPlayer(url: url)
        
        // AVPlayerViewController를 초기화합니다.
        self.videoPlayerViewController = AVPlayerViewController()
        // playerViewController의 플레이어를 아까 만든 videoPlayer로 설정합니다.
        self.videoPlayerViewController.player = self.videoPlayer
        // playerViewController의 view를 알맞게 만듭니다.
        self.videoPlayerViewController.view.frame = CGRect(x: 0, y: 0, width: 300, height: 300)
        
        self.videoView.addSubview(self.videoPlayerViewController.view)
        self.videoPlayerViewController.player?.play()
        
    }
    
    @IBAction func touchUpBackButton(_ sender: UIButton) {
        self.dismiss(animated: true, completion: nil)
    }
    
}

이렇게 하면 AudioViewController에서 video 버튼을 누르면 VideoViewController가 나오고 비디오가 재생됩니다. 잘 되는지 한 번 보겠습니다.

그런데 직접 해 보시면 아마 음악이 계속 재생돼서 비디오 소리랑 같이 들리는 문제가 발생할 거예요.

아까 AudioSession을 백그라운드에서도 재생 가능하도록 만들었기 때문에 생기는 문제입니다.

따라서 이를 일시 정지하는 코드를 작성해야 합니다.

 

저는 AudioViewController에 viewWillDisappear에 작성해줬습니다.

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    self.player.pause()
}

하지만 audio를 일시정지하는 코드를 작성하면 소리가 겹치는 문제는 해결되는데, 비디오는 앱이 백그라운드로 가는 순간 정지됩니다.

저는 이게 제가 잘못한 건 줄 알았는데 공식 문서를 찾아보니 AVPlayer에서 동영상을 재생하는 경우엔 원래 백그라운드로 가면 재생이 정지된다더라고요!

음... 동영상을 백그라운드에서 재생하려고 할 때마다 멈춘다면 매우 불편할 것 같아 이 문제를 해결하고 싶었지만 아직은 해결을 못한 상태입니다. 물론 이 글을 처음 시작한 이유가 MPRemoteCommandCenter로 콘텐츠를 제어하려는 걸 알아보려고 쓴 글인데, 비디오도 백그라운드에서 RemoteCommandCenter로 제어를 하면 재생은 됩니다. 근데 백그라운드로 갈 때마다 일시정지가 된다는 게 마음에 안 들어요.

 

일단 이건.. 아직은 해결을 못해서 알아본 뒤 수정하도록 하겠습니다.ㅠㅠ

혹시 아시는 분 계시면 알려주세요..

공부를 해서 제가 방법을 알아냈습니다.

간단히 말하면 CALayer를 사용하는 방법이었어요.

이건 나중에 따로 다시 정리를 하도록 하겠습니다.

 

전체 코드는 여기 있습니다!

 

감사합니다.

반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함