이번 학기의 '모바일 프로그래밍' 강의에서 '공유 캘린더' 앱을 개발하게 되었다. 공유 캘린더란 말 그대로 여러 명의 사용자가 일정을 공유할 수 있는 캘린더이다. 그동안 시간이 없다는 핑계를 대며 개발 과정에 있던 내용들을 정리하지 못했지만 어느정도 시간적 여유가 생긴 지금이나마 관련 내용들을 정리해보고자 한다.
캘린더에 포함되는 여러 기능 중 알림 기능은 내가 아닌 다른 팀원이 담당한 부분이다. 따라서 나는 이 부분에 대해 깊이는 공부하지 않았다. 원래는 알림 기능에는 하나도 손을 대지 않으려 했으나 다른 팀원이 알림 권한을 허용받는 기능만 구현을 해달라 하였기에 구현을 마치고 그 내용을 정리해보려 한다.
구현을 위해 구글링을 진행할 때 구현 결과가 최상단에 있으면 좋겠다 생각했으므로 구현한 결과를 먼저 살펴보도록 하겠다.
◎ 알림 권한 : POST_NOTIFICATIONS
캘린더 앱의 필수 기능 중 하나는 알림 기능이라고 생각한다. 등록한 일정의 시작 시간을 기준으로 몇 분 전에 알림을 울리게 할 지 설정할 수 있어야 해당 일정이 시작되는 것을 까먹지 않을 수 있기 때문이다.
1. Android 13부터 바뀐 점
몇년 전에 안드로이드 프로젝트를 진행했을 때를 생각해보면 특정 권한을 위해서는 그냥 AndroidManifest.xml 파일에 코드를 적기만 하면 됐던 것 같은데 지금은 사용자로부터 권한을 허용받아야 되게끔 바뀌었다고 한다.
① 옵트인(Opt-in), 옵트아웃(Opt-out)
옵트인이란 사용자가 권한을 허용하기 전까지는 기본적으로 권한이 '거부' 상태인 것을 말한다. 옵트인의 반대인 옵트아웃은 기본적으로 앱을 설치할 때부터 권한이 '허용' 상태인 것을 말한다. 기존의 안드로이드 12(targetSdk 32)까지는 옵트아웃 방식이었기에 권한 요청을 하지 않아도 되었지만 안드로이드 13(targetSdk 33)부터는 옵트인 방식이기에 특정 권한을 위해서는 사용자로부터 허용을 받아야 하게끔 변경이 되었다고 한다.
A) targetSdk 32 / Android 13 : 권한 허용 받아야 함
B) targetSdk 32 / Android 12 : 권한 기본 허용 상태
C) targetSdk 33 / Android 13 : 권한 허용 받아야 함(필요할 때 권한을 요청하는 방식 or 실행 초기에 요청하는 방식)
현재 개발 중인 프로젝트의 targetSdk는 34이고 Android는 13이므로 사용자로부터 권한을 허용받도록 구현해보겠다. 기억을 더듬어보면 안드로이드도 어느 순간부터 위치, 카메라 등의 권한을 요청하는 팝업이 뜨기 시작했던 것 같다. 권한은 필요할 때 요청받는 방식도 있지만 어차피 지금 필요한 권한은 알림 권한 하나이므로 초기 실행 시 권한을 요청하는 방식으로 구현해보도록 하겠다.
2. 알림 채널(Notification Channel)
안드로이드 8(Oreo)부터는 알림 채널이 도입되었다고 한다. 이는 기존의 앱들이 사용자들에게 무분별한 알림을 보내는 것을 예방하고자 도입되었다고 한다. 앱의 설정을 확인해보면 다음과 같이 특징별 알림이 구분되어 있는데 이로써 알림을 유형별로 구분할 수 있게 되었다고 한다. 유튜브를 예로 들면 댓글 알림, 새 영상 등록 알림 등으로 나눠서 알림이 오고 있는 것을 확인할 수 있다.
프로젝트에서는 알림 채널을 구분하지 않고 모든 채널의 알림을 허용받는 방식으로 구현해보도록 하겠다.
3. 구현
앞서 말한 것처럼 앱 초기에 실행 시 권한을 요청하도록 하고 요청하는 권한은 모든 채널의 알림으로 구현해보도록 하겠다.
① AndroidManifest.xml 파일에 권한 추가
권한 사용을 위해선 우선 매니패스트 파일에 다음과 같이 권한을 적어주어야 한다. 아래 코드는 매니패스트 파일의 상위 일부분만을 추출한 코드이다. 알림 기능을 위해 맨 아래의 POST_NOTIFICATIONS 권한을 적어주었다.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
② 첫 화면 파일에 코드 추가
이 캘린더 앱의 첫 화면은 LoginActivity.kt이다. 아래 코드는 파일에서 권한 요청을 위한 부분만을 발췌한 코드이다. 코드 자체는 생각보다 간결하고 크게 어려운 부분은 없다.
- private val REQUEST_CODE_NOTIFICATION_PERMISSION = 1 : 사용할 변수의 값을 초기화
- onCreate() 함수 내부에 알림 권한이 허용되었는지 확인하는 부분 추가
- android.Manifest.permission.POST_NOTIFICATIONS : 구글링을 하다 보면 이 부분의 맨 앞에 있는 "android." 코드가 누락된 글이 몇몇 보였는데 위 형식처럼 제대로 작성해주어야 함
- 권한이 허용된 상태일 경우 그냥 넘어가고 권한이 허용되지 않았을 경우 권한 요청 팝업을 띄움
- onRequestPermissionResult() : 권한 요청 팝업의 결과에 따라 실행되는 부분
class LoginActivity : AppCompatActivity() {
...
중략
...
// 알림 권한 위한 변수 선언
private val REQUEST_CODE_NOTIFICATION_PERMISSION = 1
...
중략
...
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
// 알림 권한을 확인
if (ContextCompat.checkSelfPermission(this, android.Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
// [아직 권한이 허용되지 않은 경우] : 권한 요청 팝업 띄움
ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.POST_NOTIFICATIONS), REQUEST_CODE_NOTIFICATION_PERMISSION)
} else {
// [알림 권한이 이미 허용된 경우]
}
...
중략
...
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == REQUEST_CODE_NOTIFICATION_PERMISSION) {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 알림 권한이 허용된 경우
Snackbar.make(
binding.root,
"알림 권한이 허용되었습니다.",
Snackbar.LENGTH_LONG
).show()
} else {
// 알림 권한이 거부된 경우
Snackbar.make(
binding.root,
"알림 권한이 거부되었습니다. 알림을 받으려면 설정에서 알림 권한을 허용하세요.",
Snackbar.LENGTH_LONG
).show()
}
}
}
...
중략
...
}
이상으로 앱을 처음 실행할 때 권한을 요청받는 기능에 대한 정리를 마쳤다. 다른 권한도 필요할 경우 위 방법을 참고하면 될 것 같다. 안드로이드는 뭐가 자꾸 자잘하게 바뀌는 것 같다... 이상.