Android 앱에서 알림이나 리마인더를 정확한 시각에 울리려면 AlarmManager로 정확한 알람(exact alarm)을 예약해야 합니다.

그런데 Android 12부터 정확한 알람을 사용하려면 별도의 권한이 필요해졌고, Android 13과 14를 거치면서 동작이 또 바뀌었습니다.

이 글에서는 SCHEDULE_EXACT_ALARMUSE_EXACT_ALARM이 어떤 차이가 있고, 어떤 상황에서 무엇을 써야 하는지 정리합니다.

왜 이 권한이 생겼나

Android는 배터리 절약을 위해 Doze 모드앱 대기 모드(App Standby)를 도입해 백그라운드 작업을 제한해왔습니다.

정확한 알람(exact alarm)은 이런 절전 상태에서도 지정된 시각에 정확하게 실행되기 때문에 배터리 사용량이 비교적 큰 작업입니다.

그래서 Google은 Android 12부터 정확한 알람 사용에 권한을 도입해서, 꼭 필요한 앱만 사용하도록 제한하기 시작했습니다.

두 권한의 차이

항목 SCHEDULE_EXACT_ALARM USE_EXACT_ALARM
도입 버전 Android 12 (API 31) Android 13 (API 33)
보호 등급 dangerous (appop) normal
자동 부여 ❌ 사용자가 명시적으로 허용 ✅ 설치 시 자동 부여
사용자 취소 ✅ 설정에서 취소 가능 ❌ 취소 불가
Play Store 정책 일반적인 정확한 알람 용도 핵심 기능이 알람·시계인 앱만 (별도 양식 제출)

핵심 차이는 두 가지입니다.

  • SCHEDULE_EXACT_ALARM은 사용자가 직접 허용해야 하지만 어떤 앱이든 요청할 수 있음
  • USE_EXACT_ALARM은 사용자 동의 없이 자동 허용되지만, 알람·시계가 핵심 기능인 앱만 사용 가능 (Google Play 검수 시 별도 양식 제출 필요)

API 버전별 동작 변화

정확한 알람의 동작은 API 레벨에 따라 단계적으로 엄격해져 왔습니다. 앱의 targetSdk와 단말기의 API 레벨이 모두 영향을 줍니다.

Android 11 (API 30) 이하

  • 권한 없이 누구나 정확한 알람 사용 가능
  • setExact(), setExactAndAllowWhileIdle() 자유롭게 호출
  • canScheduleExactAlarms() API 자체가 존재하지 않음 → 호출 시 컴파일 에러
// API 30 이하에서는 권한 체크 없이 바로 호출 가능
alarmManager.setExactAndAllowWhileIdle(
    AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent
)

Android 12 (API 31)

  • SCHEDULE_EXACT_ALARM 권한 신설
  • 매니페스트에 선언하면 설치 시 자동 부여되지만, 사용자가 설정 → 알람 및 리마인더에서 취소 가능
  • 권한 없이 setExact() 계열을 호출하면 SecurityException 발생
  • canScheduleExactAlarms() API가 추가되어 권한 상태 확인 가능
// API 31부터 canScheduleExactAlarms() 사용 가능
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
    if (!alarmManager.canScheduleExactAlarms()) {
        // 권한 없음
    }
}

Android 13 (API 33)

  • USE_EXACT_ALARM 권한이 추가됨 (취소 불가, 자동 부여)
  • SCHEDULE_EXACT_ALARM의 보호 등급이 normal에서 appop으로 변경
  • targetSdk = 33 이상으로 빌드한 앱부터 새 정책이 적용됨
  • targetSdk = 32 이하로 빌드된 앱은 기존처럼 자동 부여 상태 유지

Android 14 (API 34)

  • SCHEDULE_EXACT_ALARM이 기본 거부 상태로 변경 (가장 큰 변화)
  • targetSdk = 33 이상이면서 알람·시계가 핵심 기능이 아닌 앱은 매니페스트에 선언만 해도 자동 부여되지 않음
  • 사용자가 설정에서 직접 허용하거나, 앱이 ACTION_REQUEST_SCHEDULE_EXACT_ALARM 인텐트로 설정 화면을 띄워 사용자가 토글을 켜야 함
  • targetSdk = 32 이하 앱은 여전히 자동 부여
  • USE_EXACT_ALARM은 변화 없이 자동 부여 유지

API 레벨별 권한 부여 방식 정리

단말기 API targetSdk SCHEDULE_EXACT_ALARM 부여 방식
30 이하 무관 권한 자체가 무의미, 바로 사용 가능
31 ~ 32 무관 자동 부여 (사용자가 설정에서 취소 가능)
33 32 이하 자동 부여
33 33 이상 자동 부여 (취소 가능)
34 이상 32 이하 자동 부여
34 이상 33 이상 기본 거부 → 사용자 동의 필요

코드에서의 분기 처리

API 버전별 동작을 모두 안전하게 처리하려면 아래처럼 분기해야 합니다.

fun scheduleExactAlarm(context: Context, triggerAtMillis: Long, pendingIntent: PendingIntent) {
    val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager

    when {
        // API 31 이상: canScheduleExactAlarms() 체크 필요
        Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
            if (alarmManager.canScheduleExactAlarms()) {
                alarmManager.setExactAndAllowWhileIdle(
                    AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent
                )
            } else {
                // 권한 요청 화면으로 이동
                val intent = Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM).apply {
                    data = Uri.parse("package:${context.packageName}")
                }
                context.startActivity(intent)
            }
        }
        // API 23 이상 ~ 30: Doze 대응 메서드 사용
        Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> {
            alarmManager.setExactAndAllowWhileIdle(
                AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent
            )
        }
        // API 22 이하: 일반 setExact
        else -> {
            alarmManager.setExact(
                AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent
            )
        }
    }
}

setExactAndAllowWhileIdle()은 API 23(Android 6.0)부터 사용 가능하고, canScheduleExactAlarms()ACTION_REQUEST_SCHEDULE_EXACT_ALARM은 API 31부터만 존재하므로 버전 체크가 필수입니다.

어떤 권한을 써야 하나

캘린더 / 알람 시계 앱

앱의 핵심 기능 자체가 알람·시계라면 USE_EXACT_ALARM이 적합합니다.

<uses-permission android:name="android.permission.USE_EXACT_ALARM" />

단, Google Play에 앱을 올릴 때 사용 정당성을 양식으로 제출해야 하며, 승인되지 않으면 앱 등록이 거부될 수 있습니다.

리마인더 / 일반 앱

알람·시계가 메인 기능이 아닌 일반 앱(할 일 알림, 운동 타이머, 약 복용 알림 등)은 SCHEDULE_EXACT_ALARM을 사용해야 합니다.

<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />

이 경우 Android 14 이상에서는 사용자 동의를 받아야 동작합니다.

권한 상태 확인

AlarmManager.canScheduleExactAlarms()로 현재 정확한 알람을 예약할 수 있는 상태인지 확인할 수 있습니다.

val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager

if (alarmManager.canScheduleExactAlarms()) {
    // 정확한 알람 예약 가능
    alarmManager.setExactAndAllowWhileIdle(
        AlarmManager.RTC_WAKEUP,
        triggerAtMillis,
        pendingIntent
    )
} else {
    // 권한이 없으면 사용자에게 요청
    val intent = Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM).apply {
        data = Uri.parse("package:${context.packageName}")
    }
    context.startActivity(intent)
}

ACTION_REQUEST_SCHEDULE_EXACT_ALARM은 시스템 설정 화면을 직접 띄우는 인텐트로, 사용자가 거기서 토글을 켜야 권한이 부여됩니다. 런타임 권한 다이얼로그와 달리 Activity로 이동하는 방식이라는 점에 주의하세요.

권한 변경 감지

사용자가 설정에서 권한을 켜거나 끄면 시스템이 ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED 브로드캐스트를 보냅니다.

class ExactAlarmPermissionReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        if (intent.action == AlarmManager.ACTION_SCHEDULE_EXACT_ALARM_PERMISSION_STATE_CHANGED) {
            val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
            if (alarmManager.canScheduleExactAlarms()) {
                // 권한이 다시 허용됨 → 알람 재예약
            } else {
                // 권한이 취소됨 → 알람 정리
            }
        }
    }
}

권한이 취소되면 이미 예약된 알람도 동작하지 않으므로, 이 브로드캐스트를 받아서 알람을 다시 예약하거나 정리하는 처리가 필요합니다.

정확한 알람을 피하는 대안

정확한 알람은 배터리 사용량이 크고 권한 관리도 까다로우므로, 실제로 정확성이 필요하지 않은 경우 다른 방법을 검토하는 게 좋습니다.

setAndAllowWhileIdle / setExactAndAllowWhileIdle

set()이나 setExact()는 Doze 모드에서 실행이 미뤄질 수 있지만, setAndAllowWhileIdle() 계열은 Doze 모드에서도 동작합니다.

// 부정확하지만 Doze 모드에서도 동작 (배터리 부담 적음)
alarmManager.setAndAllowWhileIdle(
    AlarmManager.RTC_WAKEUP,
    triggerAtMillis,
    pendingIntent
)

수 분 단위 오차가 허용되는 리마인더라면 이 방법이 적합합니다.

WorkManager

특정 시각이 아니라 “언젠가는 실행되어야 하는” 백그라운드 작업이라면 WorkManager가 더 적합합니다.

  • 배터리 최적화 정책을 자동으로 따름
  • 네트워크, 충전 상태 등 다양한 조건 지정 가능
  • 앱 종료 후에도 작업 보장

다만 정확한 시각 트리거에는 적합하지 않으므로, “정해진 시간에 알림” 용도라면 AlarmManager가 맞습니다.

정리

상황 권장 방식
알람 시계 / 캘린더가 핵심 기능 USE_EXACT_ALARM (Play 양식 제출 필수)
리마인더 / 일반 앱의 정확한 알림 SCHEDULE_EXACT_ALARM + 사용자 권한 요청
수 분 오차 허용 가능한 알림 setAndAllowWhileIdle() (권한 불필요)
백그라운드 작업 WorkManager

Android 14부터는 일반 앱이 정확한 알람을 쓰려면 반드시 사용자 동의 절차를 거쳐야 한다는 점이 가장 중요합니다.

권한을 매니페스트에 선언만 해두고 canScheduleExactAlarms() 체크 없이 호출하면 SecurityException이 발생하므로, 항상 권한 상태를 먼저 확인하는 흐름으로 구현해야 합니다.

참고한 공식 문서

Updated: