[KMP] 진동 발생시키기

WonDDak·7일 전
0

KMP- Kotlin MultiPlatform

목록 보기
12/12

현재 보드게임 관련앱을 제작중인데.

타이머 기능이있고, 타이머가 끝나면 진동을 주게하고싶었다.

관련 라이브러를 찾아봤지만 구현되어있는게 없어서 직접 구현해보기로했다.

Android

안드로이드에서는 간단히 Vibrator를 통해 진동을 발생 시킬수있다.

S 부터 버전 분기가 되었으므로 나누어서 init 해준다.

private val vibrator: Vibrator

init {
    vibrator = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        val vibratorManager =
            context.getSystemService(Context.VIBRATOR_MANAGER_SERVICE) as android.os.VibratorManager
        vibratorManager.defaultVibrator
    } else {
        context.getSystemService(VIBRATOR_SERVICE) as Vibrator
    }
}

단일 진동

vibrate를 통해 발생시킬 수 있다.

O버전 부터는 시간외에 amplitude를 받아 진동세기를 조절할수 있는데 여기서는 단순히 발생이 목적이기 때문에 100으로 고정하였다.

fun vibrate(time: Long) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        vibrator.vibrate(VibrationEffect.createOneShot(time, 100))
    } else {
        vibrator.vibrate(time)
    }
}

패턴 진동

timings을 받아 발생시킬 수 있다.
예를 들어 timings가 [100,500,100,500] 이라면
0.1초 대기 0.5초 발생 0.1초 대기 0.5초 발생 이런식이다.

repeat으로 특정 index구간을 반복 할 수있는데 여기서는 무시한다.(1회만)

fun vibratePattern(timings: LongArray) {
    val repeat = -1
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        vibrator.vibrate(VibrationEffect.createWaveform(timings, repeat))
    } else {
        vibrator.vibrate(timings, repeat)
    }
}

iOS

iOS는 진동 발생 시켜본적이 처음이라 찾아보다가 corehaptics을 이용하여 커스텀 진동을 구현 할 수 있는 것을 확인 하였다.

초기화

CHHapticEngine을 통해 CHHapticEvent을 받아와서 원하는 진동을 구현 하도록 만들었다.

internal fun playHaptic(
    eventPattern: List<CHHapticEvent>
) {
    if (engine == null) {
        resetEngine()
    }
    engine?.let { engine ->
        engine?.stopWithCompletionHandler {
            try {
                val pattern = CHHapticPattern(
                    events = eventPattern,
                    parameters = emptyList<CHHapticDynamicParameter>(),
                    error = null
                )
                val player = engine.createPlayerWithPattern(pattern = pattern, error = null)
                engine.notifyWhenPlayersFinished {
                    CHHapticEngineFinishedActionStopEngine
                }
                engine.startWithCompletionHandler {
                    player?.startAtTime(0.0, error = null)
                }
            } catch (e: Exception) {
                println("playHaptic error")
                e.printStackTrace()
            }
        }
    }
}

단일 진동

가져온 시간을 CHHapticEvent 리스트로 변환하여 발생시킨다.

fun vibrate(time: Long) {
    try {
        customHaptic.playHaptic(
            listOf(
                CHHapticEvent(
                    eventType = CHHapticEventTypeHapticContinuous,
                    parameters = emptyList<CHHapticEventParameter>(),
                    relativeTime = 0.1,
                    duration = time.toIosDuration()
                )
            )
        )
    } catch (e: Exception) {
        println("vibrate error")
        e.printStackTrace()
    }
}

패턴 진동

가져온 패턴을 CHHapticEvent 리스트로 변환하여 발생시킨다.

안드로이드처럼 자동으로 off/on 타이밍이 아니라 손수 변환해주었다.

CHHapticEvent에는 relativeTime/duration이 있는데

  • relativeTime : 진동 발생 시점
  • duration : 진동 발생 시간 이라 보면된다.

즉 [100,500,100,500]의 값이 왔다면 아래와 같이 두개의 CHHapticEvent를 가진다.


  • relativeTime : 0.1
  • duration :0.5

  • relativeTime : 0.7
  • duration :0.5

fun vibratePattern(timings: LongArray) {
    try {
        val convertPattern = mutableListOf<CHHapticEvent>()
        var prevTime: Double? = null
        timings.forEachIndexed { index, time ->
            val convertDuration = time.toIosDuration()
            if (index % 2 == 0) {
                prevTime = if (prevTime == null) {
                    convertDuration
                } else {
                    prevTime!! + convertDuration
                }
            } else {
                CHHapticEvent(
                    eventType = CHHapticEventTypeHapticContinuous,
                    parameters = emptyList<CHHapticEventParameter>(),
                    relativeTime = prevTime!!,
                    duration = convertDuration
                ).also {
                    convertPattern.add(it)
                }
                prevTime = prevTime!! + convertDuration
            }
        }
        customHaptic.playHaptic(convertPattern)
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

코드는 여기에서 git

profile
안녕하세요. 원딱입니다.

0개의 댓글

관련 채용 정보