2022년 11월 1일 이후, 구글은 Android 앱이 Target SDK 31 (Android 12) 이상을 지원해야 Google Play에 업데이트가 가능하도록 정책을 변경했다. 이 정책은 앱 개발자에게 다양한 기술적 요구 사항을 도입하게 만들었으며, 그 중 하나는 정확한 알람(Exact Alarm) 권한입니다. 이번 글에서는 정확한 알람 권한에 대해 알아보고, 이를 어떻게 처리해야 하는지 자세히 살펴보겠습니다.
1. 정확한 알람(Exact Alarm) 권한이란?
Android 앱에서 정확한 알람은 특정 시간에 정확하게 트리거되는 알람을 의미합니다. 이러한 알람은 AlarmManager를 사용하여 다음 메서드를 통해 설정된다.
- setAlarmClock()
- setExact()
- setExactAndAllowWhileIdle()
이러한 기능들은 타이머, 캘린더 알람, 알림 기능 등 정확한 시간에 동작해야 하는 앱에서 중요한 역할을 합니다. 하지만, Android 12 (SDK 31) 이상부터는 SCHEDULE_EXACT_ALARM 권한이 필요하며, 이를 제대로 처리하지 않으면 앱이 알람 설정 중 크래시를 일으킬 수 있다.
2. AndroidManifest에서 정확한 알람 권한 설정
정확한 알람 권한을 사용하려면 AndroidManifest.xml 파일에 다음과 같이 권한을 추가해야 한다.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.your.package">
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<application>
...
</application>
</manifest>
이 설정을 추가함으로써 앱은 정확한 알람을 사용할 수 있는 권한을 요구하게 됩니다. 그러나 권한을 추가하는 것만으로는 충분하지 않을 수 있다. 만약 유저가 설정에서 권한을 거부하게 되면, 알람 설정 시 앱이 크래시할 수 있습니다.
3. 설정에서 정확한 알람 권한 확인 방법
유저가 정확한 알람 권한을 거부했는지 확인하려면, 아래와 같은 절차를 통해 확인할 수 있다.
- 기기 설정으로 이동: 홈 화면에서 설정(Settings) 앱을 엽니다.
- 앱 선택: 앱 및 알림(Apps & notifications) 메뉴에서 권한을 확인할 앱을 선택합니다.
- 특수 앱 액세스(Advanced): 앱 정보 화면에서 고급(Advanced) 옵션으로 스크롤합니다.
- 정확한 알람 설정: 정확한 알람(Exact Alarm) 항목이 표시되면, 해당 앱에 대한 정확한 알람 권한을 허용하거나 거부할 수 있습니다.
이 과정을 통해 유저가 앱에 정확한 알람 권한을 부여했는지 확인할 수 있다. 만약 유저가 이 권한을 거부했다면, 앱이 알람을 설정할 때 크래시가 발생할 수 있다.
4. 권한 상태 확인 및 요청
유저가 정확한 알람 권한을 거부했는지 확인하고, 거부된 경우 이를 허용하도록 요청하는 코드가 필요합니다. 이를 위해 AlarmManager의 canScheduleExactAlarms() 메서드를 사용하여 권한이 있는지 확인할 수 있다.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
if (!alarmManager.canScheduleExactAlarms()) {
val intent = Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM)
startActivity(intent)
}
}
이 코드는 Android 12 이상에서 정확한 알람을 설정하기 전에 유저가 해당 권한을 허용했는지 확인하며, 거부되어 있을 경우 권한 요청 화면으로 이동시킵니다.
5. 알람 권한 자동 부여에 대한 오해
많은 개발자들이 SCHEDULE_EXACT_ALARM 권한을 자동으로 부여받는 경우를 경험할 수 있습니다. 예를 들어, 일부 앱은 유저가 따로 권한을 허용하지 않아도 시스템적으로 자동 허용되는 경우가 있습니다. 이때 중요한 점은 다음과 같습니다:
- 시스템 앱이나 알람 관련 필수 기능을 수행하는 앱일 경우, 정확한 알람 권한이 자동으로 부여될 수 있다.
- 설정에서 이미 권한이 허용된 경우, 다시 권한을 요청하지 않습니다. 이는 앱이 정확한 알람 권한을 요구하지 않는 것으로 보일 수 있다.
따라서, 앱의 상황에 맞게 권한을 요청하거나 시스템적으로 자동 허용되는지 확인해야 합니다.
6. 권한 거부 시 발생할 수 있는 문제와 대응
유저가 정확한 알람 권한을 거부하면, 알람 설정 시 앱이 크래시할 수 있습니다. 이를 방지하기 위해 유저가 권한을 허용했는지 확인하고, 권한이 거부된 경우 적절한 안내 메시지를 제공하는 것이 좋다.
val dialog = AlertDialog.Builder(context)
.setTitle("정확한 알람 권한 필요")
.setMessage("이 기능을 사용하려면 정확한 알람 권한이 필요합니다. 허용하시겠습니까?")
.setPositiveButton("허용") { _, _ ->
val intent = Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM)
startActivity(intent)
}
.setNegativeButton("취소", null)
.show()
이와 같은 안내를 통해 유저가 권한을 쉽게 허용할 수 있게 유도할 수 있다.
----------------------------------------------------------------------------------------------------------------------
자료를 알아보기전에,
fun isExactAlarmPermissionGranted(context: Context): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
Log.d("Exact","확인")
context.getSystemService(AlarmManager::class.java).canScheduleExactAlarms()
} else {
Log.d("Exact","확인1")
true
}
}
val isExactAlarmAllowed = permissionViewModel.isExactAlarmPermissionGranted(this)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
Log.d("ExactAlarm", "권한 상태 --> $isExactAlarmAllowed")
// 권한이 자동으로 부여되면 별도의 처리 불필요
if (!isExactAlarmAllowed) {
val intent = Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM)
startActivity(intent)
} else {
Log.d("ExactAlarm", "정확한 알람 권한이 이미 자동으로 부여되었습니다.")
}
}
// 안드로이드 자체에서 권한을 부여하는 듯 isExactAlarmAllowed 초기값 true 임,
//혹여 기기마다 다를 수 있으므로 코드 유지
위와 같은 코드를 작성하고, 왜 사용자에게 권한을 받는 시스템 화면이 뜨지 않는지 궁금했다.
그래서 내가 설정한 isExactAlarmAllowed 의 초기값을 검사해봤고, true로 설정되어 있었다.
알고보니 AlarmManager의 setExactAndAllowWhileIdle() 또는 setExact() 같은 메서드를 사용하는 경우, Android 시스템은 해당 앱이 정확한 알람을 필요로 한다는 것을 알게 되고, 자동으로 권한을 부여한다는 점을 알게 되었다.
시스템에서 자동으로 권한을 부여하는 경우
- 시스템에 따라 정확한 알람 권한이 자동으로 부여될 수 있습니다. 예를 들어, 시계나 알람 관련 앱은 기본적으로 이 권한이 자동으로 부여될 수 있다.
'안드로이드 프로그래밍 > 트러블슈팅' 카테고리의 다른 글
[트러블 슈팅] AlarmManager (1) | 2024.09.19 |
---|---|
[트러블슈팅] ScrollView와 RecyclerView의 충돌 -> NestedScrollView (0) | 2024.08.27 |
[Android / 트러블슈팅] 동적으로 크기가 변하는 뷰 대응하기 (0) | 2024.07.30 |