iOS 응용 (swift)

[iOS - swift] CoreHaptics (진동 주는 방법, 진동 효과)

jake-kim 2024. 10. 9. 01:51

진동 효과 (CoreHaptics)

  • 햅틱을 0.5초 주기로 1초 진동을 3번 순차적으로 주고 싶은 경우? -> CoreHaptics를 사용
  • CoreHapcits는 iOS 13부터 제공하며 햅틱의 패턴들을 정교하게 만들어 낼 수 있는 기능

https://developer.apple.com/documentation/corehaptics/

사용 방법

  • import
import CoreHaptics
  • enum을 사용하여 햅틱의 종류 설정
enum HapticCategory {
    case a
    case b
}
  • a진동은 여러번 주는 진동으로하고, b는 굴직하게 긴 시간 하나의 진동을 주도록 구현
    • CHHapticEvent라는 것으로 배열로 반환하는데, 여기서 중요한 파라미터는 eventType, relativeTime, duration 세 가지
    • eventType: 대표적으로 duration을 설정할 수 있는 hapticContinous와 단발적으로 진동해시키는 hapticTransient 2개가 존재
    • relativeTime: 시작시간 (초) 이며 주의사항은 1초를 기준으로한 상대시간이 아닌 말그대로 시작 초를 의미함
    • duration: eventType에서 hapticContinous을 사용했을때 지속시간 (초)
enum HapticCategory {
    case a
    case b
    
    var hapticEvents: [CHHapticEvent] {
        switch self {
        case .a:
            [
                CHHapticEvent(eventType: .hapticContinuous, parameters: [], relativeTime: 0.3, duration: 0.5),
                CHHapticEvent(eventType: .hapticContinuous, parameters: [], relativeTime: 0.9, duration: 0.5),
                CHHapticEvent(eventType: .hapticContinuous, parameters: [], relativeTime: 1.5, duration: 0.5),
            ]
        case .b:
            [CHHapticEvent(eventType: .hapticContinuous, parameters: [], relativeTime: 0.1, duration: 3)]
        }
    }
}
  • CustomHaptic이라는 클래스 생성
    • CHHapticEngine이라는 프로퍼티를 가지고 있게끔 구현
    • 이 프로퍼티는 위에서 정의한 hapticEvents들을 가지고 진동효과를 줄 수 있는 API
class CustomHaptic {
    private var engine: CHHapticEngine?
}
  • 여기에 햅틱을 실행시키는 함수 구현
    • resetEngine()이라는 함수는 밑에서 알아볼 예정이며 단순히 engine 프로퍼티를 초기화하고 handler를 등록하는 함수
    • guard문으로 햅틱을 지원하는 하드웨어인지 체크 (iOS는 햅틱 지원함)
    • CHHapticPattern에 위에서 정의한 hapticEvents들을 넘기고 player로 실행
    • 주의할 점) hapticEvents들을 구성할 때 relativeTime이 음수 값이거나 배열에서 relativeTime이 순차적으로 되어 있지 않으면 catch문으로 예외가 발생함
    func playHaptic(category: HapticCategory) {
        resetEngine() // 밑에서 구현 예정
        
        guard CHHapticEngine.capabilitiesForHardware().supportsHaptics else { return }
        do {
            let pattern = try CHHapticPattern(events: category.hapticEvents, parameters: [])
            let player = try engine?.makePlayer(with: pattern)
            try player?.start(atTime: 0)
        } catch {
            print("CHHapticEvent 구조가 이상하여 에러 발생 \(error.localizedDescription).")
        }
    }
  • resetEngine() 구현
    • engine 초기화 - play할때마다 resetEngine()을 매번 호출하는데, 매번 초기화시켜주지 않으면 간헐적으로 햅틱이 동작 안하는 경우가 존재하기 때문
    • 헨들러 등록
private extension CustomHaptic {
    func resetEngine() {
        engine = try? CHHapticEngine()
        try? engine?.start()
        
        setStopHandler()
        setResetHandler()
    }
    
    func setStopHandler() {
        engine?.stoppedHandler = { reason in
            print("엔진이 멈춤 \(reason)")
        }
    }
    
    func setResetHandler() {
        engine?.resetHandler = { [weak self] in
            do {
                try self?.engine?.start()
            } catch {
                print("restart 실패 \(error)")
            }
        }
    }
}

사용하는쪽)

class ViewController: UIViewController {
    let haptic = CustomHaptic()
    
    @objc func didTapButton() {
        haptic.playHaptic(category: .a)
    }
}

 

* 전체 코드: https://github.com/JK0369/ExCoreHaptics
* 참고

- https://developer.apple.com/documentation/corehaptics/