본문 바로가기
안드로이드(kotlin)

안드로이드13에서 Notification 권한 허가 받기 방법 및 변경점

by 기계공학 주인장 2023. 1. 14.
반응형

안드로이드13에서 Notification에 대해 바뀐점

  • POST_NOTIFICATIONS (Notification Permission) 은 Target SDK API 33 이상부터 추가 가능
  • Target SDK API 32 이하의 앱이 Android 13 디바이스에 설치되면 Notification Channel을 등록할 때 자동으로 Notification 권한 요청 팝업이 나옴
  • Target SDK API 33 이상의 앱이 Android 13 디바이스에 설치되면 Notification 권한요청을 개발자가 원하는 타이밍에 노출 가능
  • Target SDK API 33 이상의 앱이 Android 12 이하 디바이스에 설치되면 기존과 동일하게 Notification 권한 요청 없이 사용 가능
  • Target SDK API 32 앱을 33으로 업데이트 시 기존 알림 권한 동의 상태라면 업데이트 이후 기본으로 허용이지만 예외 있음
    • 기기에따라 자동으로 허용되지 않고 다시 한 번 권한을 얻어야하는 경우가 있음
    • 그렇기 때문에 Notification 권한이 허가되어 있는지 한 번 확인하는 작업을 넣기를 권장함

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."


Notification 권한 허용 팝업에 대한 주의 사항

  • API 32 이하 앱의 경우, 시스템이 자동으로 퍼미션 팝업을 띄웠을 때, 사용자가 Don't allow 버튼을 한번 누르면, 앱이 재시작해도 팝업이 발생하지 않습니다.
  • API 33 이상 앱의 경우, 앱이 퍼미션 팝업을 띄웠을 때, 사용자가 Don't allow 버튼을 두 번 누르기 전까지 퍼미션 팝업을 계속 띄울 수 있습니다.
  • 사용자가 Don't allow 버튼을 눌러서 더 이상 팝업을 띄울 수 없다면 사용자가 직접 앱 설정에 들어가서 권한을 허가해줘야합니다.

Notification 권한 요청이 필요한 앱이라고 등록하기

AndroidManifest.xml
<manifest ...>
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
    <application ...>
        ...
    </application>
</manifest>
  1. AndroidManifest.xml에 위 권한을 추가한다.
  2. Sync proejct with gradle files를 실시한다

compileSdk 33 로 변경하기

  • 앱 단위의 build.gradle의 compileSdk을 33으로 변경해야한다
    • 똑같이 targetSdk도 33으로 변경이 필요하다
android {
    compileSdk 33

    defaultConfig {
        applicationId "com.example.selftest"
        minSdk 23
        targetSdk 33
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

Notification 정의 하기

  • Notification의 Channel 정의 및 Builder 정의하기
    • SDK 26 이상 버전부터는 Channel을 정의해야만 Notification을 사용할 수 있다
    • Builder를 통해 Notification을 보낸다
fun makeAlarmNotification(context: Context, messageBody: String) {
    Timber.d("make notification")
    // notification 클릭 시 MainActivity를 열게 한다
    val intent = Intent(context, MainActivity::class.java)
    intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK
    val pendingIntent = PendingIntent.getActivity(
        context, 0, intent,
        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
    )

    // notification의 channel id를 정의한다
    val channelId = "channel1"
    val channelName = "channel name"

    // notification를 정의한다
    val notificationBuilder = NotificationCompat.Builder(context, channelId)
        .setSmallIcon(R.drawable.ic_bottom_menu_search)
        .setContentTitle("notification title")
        .setContentText(messageBody)
        .setAutoCancel(false)   // 전체 삭제해도 안되게하기
        .setSound(null)
        .setContentIntent(pendingIntent)
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setOngoing(true)   // 알람이 계속 뜬 상태로 있게하기

    // 정의한 내용과 channel을 사용하여 notification을 생성한다
    val notificationManager =
        context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    
    // Android SDK 26 이상에서는 notification을 만들 때 channel을 지정해줘야 한다
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val channel = NotificationChannel(
            channelId,
            channelName,
            NotificationManager.IMPORTANCE_DEFAULT
        )
        notificationManager.createNotificationChannel(channel)
    }
    
    // notification 띄우기
    notificationManager.notify(100, notificationBuilder.build())
}

Notification 권한 얻기

안드로이드13 이상에서 Notification을 출력하기 위해서는 권한을 요구하고

 

권한을 얻어야만 출력할 수 있다

 

Notification의 권한은 다음과 같은 방법으로 얻을 수 있다.

 

FirstFragment.kt

 

버튼을 눌렀을 때 Notification 권한 요청이 나오게 한다

class FirstFragment : Fragment() {
    companion object {
        const val DENIED = "denied"
        const val EXPLAINED = "explained"
    }

    private var binding: FragmentFirstBinding by autoCleared()
    // 권한 요청용 Activity Callback 객체 만들기
    private val registerForActivityResult = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
        val deniedPermissionList = permissions.filter { !it.value }.map { it.key }
        when {
            deniedPermissionList.isNotEmpty() -> {
                val map = deniedPermissionList.groupBy { permission ->
                    if (shouldShowRequestPermissionRationale(permission)) DENIED else EXPLAINED
                }
                map[DENIED]?.let {
                    // 단순히 권한이 거부 되었을 때
                }
                map[EXPLAINED]?.let {
                    // 권한 요청이 완전히 막혔을 때(주로 앱 상세 창 열기)
                }
            }
            else -> {
                // 모든 권한이 허가 되었을 때
            }
        }
    }

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentFirstBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.button.setOnClickListener {
            val action = FirstFragmentDirections.actionFirstFragmentToThirdFragment()
            findNavController().navigate(action)
        }

        // 버튼을 클릭했을 때 Notification 권한 요청하기
        binding.freeButton.setOnSingleClickListener {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                registerForActivityResult.launch(
                    arrayOf(Manifest.permission.POST_NOTIFICATIONS)
                )
            }
            makeAlarmNotification(requireContext(), "notification")
        }
    }
}

 

위 방법은 Fragment 뿐 아니라 Activity에서도 똑같이 사용할 수 있다


요약

  • 기존의 앱의 경우에는 Notification Channel을 등록할 때 자동으로 권한을 요구하는 창이 뜬다
    • 단, 이 단계에서 허락하지 않을 경우 두 번 다시 권한을 요구하지 못한다
  • 새롭게 SDK 33 이상을 Target으로 지정했다면 반드시 권한을 요구하는 기능을 넣어야한다
반응형


"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."


댓글