Android 13의 변경사항으로, 알림 런타임 권한이 도입되었습니다.
앱 동작에 어떤 영향을 미치는지 자세히 알아보겠습니다.
1. Android 13의 Notification 런타임 권한
Android 12까지는 앱을 설치하면 기본적으로 Notification을 띄울 수 있었습니다. 사용자는 App Info 화면에서 Notification을 비활성화해야 앱의 Notification 발송을 막을 수 있었습니다.
Android 13에서 Notification 런타임 권한이 추가되었고, 이제 이 권한으로 앱의 Notification 발송 권한을 제어할 수 있도록 변경되었습니다. 또한, 기본적으로 Runtime permission은 OFF이기 때문에, 앱은 사용자에게 이 권한을 받기 전까지 노티피케이션을 발송할 수 없습니다.
2. 권한 선언 및 권한 요청 (Target SDK API 33 이상)
Target API 33 이상인 App은 다음과 같이 AndroidManifest에 POST_NOTIFICATIONS 권한을 선언할 수 있습니다.
<manifest ...>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<application ...>
...
</application>
</manifest>
앱에서 사용자에게 POST_NOTIFICATIONS 권한을 요청할 때 다음과 같이 구현할 수 있습니다. 기본적인 Runtime permission 요청 방법과 동일합니다.
requestPermissions(arrayOf(Manifest.permission.POST_NOTIFICATIONS), REQUEST_CODE)
사용자에게 Runtime permission을 요청하는 방법은 Android developer의 앱 권한 요청을 참고하시면 됩니다.
3. 권한 선언 및 권한 요청 (Target SDK API 32 이하)
POST_NOTIFICATIONS 권한은 Android 13(API 33)에서 추가되었기 때문에, Android 12L(API 32) 이하로 컴파일된 앱은 퍼미션이 추가되어있지 않습니다. 그렇기 때문에 시스템이 자동으로 앱에 권한을 추가하고, 퍼미션 요청 팝업도 띄워줍니다.
Target API 32 이하의 앱이 Android 13 디바이스에 설치되면, 기본적으로 POST_NOTIFICATIONS 권한은 앱이 사용한다고 자동으로 선언되어있습니다.
자동으로 퍼미션은 선언은 되어있지만, 퍼미션이 자동으로 부여되는 것은 아닙니다. 퍼미션을 부여받으려면 권한 요청 팝업을 통해 사용자에게 권한을 받아야 합니다.
퍼미션 선언과 마찬가지로, API 32 이하 앱은 POST_NOTIFICATIONS에 대해서 퍼미션을 요청하는 코드가 없습니다. 그렇기 때문에, 시스템은 아래와 같은 경우에 자동으로 퍼미션 팝업을 띄워서 사용자로부터 권한을 부여받을 수 있도록 합니다.
- Notification Channel이 등록된 상태에서 App이 Launcher에서 실행될 때 권한 요청 팝업 발생
- App이 Launcher에서 실행된 이후에, Notification Channel을 등록할 때 권한 요청 팝업 발생
즉, API 32 이하 앱은 아래와 같은 코드로 Notification Channel이 생성될 때, 또는 Notification 생성 후 앱이 실행될 때 퍼미션 요청 팝업이 자동으로 발생됩니다.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val btn : TextView = findViewById(R.id.myBtn)
btn.setOnClickListener {
createNotificationChannel(this)
}
}
private fun createNotificationChannel(context: Context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val name = "my-notification-channel"
val importance = NotificationManager.IMPORTANCE_DEFAULT
val channelId = "${context.packageName}-$name"
val channel = NotificationChannel(channelId, name, importance)
channel.description = "my notification channel description"
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
}
}
위의 예제 앱에서 버튼을 누르면 채널이 생성되며, 이 때 시스템이 자동으로 퍼미션 요청 팝업을 띄웁니다.
API 32 이하 앱의 경우, 시스템이 자동으로 퍼미션 팝업을 띄웠을 때, 사용자가
Don't allow
버튼을 한번 누르면, 앱이 재시작해도 팝업이 발생하지 않습니다.
API 33 이상 앱의 경우, 앱이 퍼미션 팝업을 띄웠을 때, 사용자가
Don't allow
버튼을 두번 누르기 전까지 퍼미션 팝업을 계속 띄울 수 있습니다. 기본적인 Runtime permission 정책을 따릅니다.
Sample app은 GitHub - create notification channel에 있습니다.
4. 앱 업데이트에 미치는 영향
Android 12에 Target API 32 이하 앱이 설치되었고, 디바이스가 Android 13으로 업그레이드 되었다고 가정해보세요. 앱의 동작에 어떤 차이가 있을까요?
4.1 App의 Notification 설정이 비활성화된 상태에서 Android 13으로 업그레이드
사용자가 Android 12에서 Notification을 사용하지 않겠다고 설정을 변경하였기 때문에, Android 13으로 업그레이드될 때 기본적으로 POST_NOTIFICATIONS
권한은 off가 됩니다.
4.2 App의 Notification 설정이 활성화된 상태에서 Android 13으로 업그레이드
Android 12에서 Notification 설정이 활성화이기 때문에, Android 13으로 업그레이드될 때 기본적으로 POST_NOTIFICATIONS
권한은 on이 됩니다. 따라서, 추가 권한 요청 없이 Notification을 띄울 수 있습니다.
5. 정리
앱을 설치할 때 사용자 동의 없이 Notificaiton을 띄우는 동작 때문에, 일부 사용자는 피로감을 느꼈습니다. Android 13의 Notification 퍼미션 도입은 이런 사용자의 경험을 반영했다고 생각합니다.
지금까지 앱은 기본적으로 Notificaiton을 띄울 수 있었고, 이것이 불편한 사용자들이 설정에서 off로 변경했었다면, 이제는 기본적으로 Notificaiton을 띄울 수 없고, 띄우고 싶은 앱이 사용자에게 허락을 맡도록 UX가 변경되었습니다.
앱 동작 측면에서,
- API 32 이하로 컴파일된 앱은 Android 13에서 플랫폼이 자동으로 권한을 추가하고 요청 팝업을 띄워줍니다. 하지만 자유도가 떨어지기 때문에 가급적 API 33으로 변경하여 앱이 스스로 원하는 타이밍에 권한 팝업을 띄우는 것이 좋을 것 같습니다.
- API 33 이상의 앱은 스스로 권한 팝업을 띄울 수 있고, 사용자가 권한을 2번 이상 거부를 하는 경우, 세팅에서 직접 설정하도록 가이드할 수 있습니다.
- 디바이스가 Android 12에서 13으로 업그레이드 될 때, Android 12의 Notification 설정을 따라서 POST_NOTIFICATIONS의 퍼미션을 기본으로 허용 또는 거부로 변경합니다.
Related Posts
- Android 14 - 사진/동영상 파일, 일부 접근 권한 소개
- Android - adb push, pull로 파일 복사, 다운로드
- Android 14 - 암시적 인텐트 변경사항 및 문제 해결
- Jetpack Compose - Row와 Column
- Android 13, AOSP 오픈소스 다운로드 및 빌드
- Android 13 - 세분화된 미디어 파일 권한
- Android 13에서 Notification 권한 요청, 알림 띄우기
- Android 13에서 'Access blocked: ComponentInfo' 에러 해결
- 에러 해결: android gradle plugin requires java 11 to run. you are currently using java 1.8.
- 안드로이드 - 코루틴과 Retrofit으로 비동기 통신 예제
- 안드로이드 - 코루틴으로 URL 이미지 불러오기
- Android - 진동, Vibrator, VibrationEffect 예제
- Some problems were found with the configuration of task 에러 수정
- Query method parameters should either be a type that can be converted into a database column or a List
- 우분투에서 Android 12 오픈소스 다운로드 및 빌드
- Android - ViewModel을 생성하는 방법
- Android - Transformations.map(), switchMap() 차이점
- Android - Transformations.distinctUntilChanged() 소개
- Android - TabLayout 구현 방법 (+ ViewPager2)
- Android - 휴대폰 전화번호 가져오는 방법
- Android 12 - Splash Screens 알아보기
- Android 12 - Incremental Install (Play as you Download) 소개
- Android - adb 명령어로 bugreport 로그 파일 추출
- Android - adb 명령어로 App 데이터 삭제
- Android - adb 명령어로 앱 비활성화, 활성화
- Android - adb 명령어로 특정 패키지의 PID 찾기
- Android - adb 명령어로 퍼미션 Grant 또는 Revoke
- Android - adb 명령어로 apk 설치, 삭제
- Android - adb 명령어로 특정 패키지의 프로세스 종료
- Android - adb 명령어로 screen capture 저장
- Android - adb 명령어로 System 앱 삭제, 설치
- Android - adb 명령어로 settings value 확인, 변경
- Android 12 - IntentFilter의 exported 명시적 선언
- Android - adb 명령어로 공장초기화(Factory reset)
- Android - adb logcat 명령어로 로그 출력