알림(2)

sumi Yoo·2022년 11월 22일
0

알림 만들기

Android 지원 라이브러리의 NotificationCompat API를 사용한다.
이 API를 사용하면 최신 Android 버전에서만 사용할 수 있는 기능을 추가하는 동시에 Android 4.0(API 수준 14)과의 호환성을 계속 유지할 수 있다. 하지만 일부 새로운 기능(예: 인라인 답장 작업)은 이전 버전에서 작동하지 않는다.

알림 콘텐츠 설정

NotificationCompat.Builder 객체를 사용하여 알림 콘텐츠와 채널을 설정한다.

    var builder = NotificationCompat.Builder(this, CHANNEL_ID)
            .setSmallIcon(R.drawable.notification_icon)
            .setContentTitle("My notification")
            .setContentText("Much longer text that cannot fit one line...")
            .setStyle(NotificationCompat.BigTextStyle()
                    .bigText("Much longer text that cannot fit one line..."))
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
    

기본적으로 알림의 텍스트 콘텐츠는 한 줄에 맞춰 잘린다.
setStyle()로 스타일 템플릿을 추가하여 확장 가능한 알림을 사용 설정하면 된다.

채널 만들기 및 중요도 설정

Android 8.0 이상에서 알림을 제공하려면 먼저 NotificationChannel 인스턴스를 createNotificationChannel()에 전달하여 앱의 알림 채널을 시스템에 등록해야 한다. 따라서 다음 코드는 SDK_INT 버전에서 조건에 의해 차단된다.

private fun createNotificationChannel() {
        // Create the NotificationChannel, but only on API 26+ because
        // the NotificationChannel class is new and not in the support library
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val name = getString(R.string.channel_name)
            val descriptionText = getString(R.string.channel_description)
            val importance = NotificationManager.IMPORTANCE_DEFAULT
            val channel = NotificationChannel(CHANNEL_ID, name, importance).apply {
                description = descriptionText
            }
            // Register the channel with the system
            val notificationManager: NotificationManager =
                getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.createNotificationChannel(channel)
        }
    }

버전 구분

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val builder = NotificationCompat.Builder(this, CHANNEL_ID)
                .setSmallIcon(R.drawable.ic_launcher_foreground)
                .setContentTitle("textTitle")
                .setContentText("textContent")
                .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                .setContentIntent(resultPendingIntent)
                .setAutoCancel(true) // 탭하면 알림 자동 삭제
                .build()
            return builder
        } else {
            val builder = NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_launcher_foreground)
                .setContentTitle("textTitle")
                .setContentText("textContent")
                .setPriority(NotificationCompat.PRIORITY_DEFAULT)
                .setContentIntent(resultPendingIntent)
                .setAutoCancel(true) // 탭하면 알림 자동 삭제
                .build()
            return builder
        }

기존 알림 채널을 만들면 아무 작업도 실행되지 않으므로 이 코드를 반복적으로 호출하는 것이 안전하다.

알림의 탭 작업 설정

    // Create an explicit intent for an Activity in your app
    val intent = Intent(this, AlertDetails::class.java).apply {
        flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
    }
    val pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent, 0)

    val builder = NotificationCompat.Builder(this, CHANNEL_ID)
            .setSmallIcon(R.drawable.notification_icon)
            .setContentTitle("My notification")
            .setContentText("Hello World!")
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            // Set the intent that will fire when the user taps the notification
            .setContentIntent(pendingIntent)
            .setAutoCancel(true)
    

알람 기능을 테스트하기 위해 API 레벨 31 에뮬레이터를 사용하고 있었는데, PendingIntent를 생성하는 코드에서 다음과 같은 오류가 발생했다.

s+(버전 31 이상)을 타겟팅하는 경우 FLAG_IMMUTABLE 또는 FLAG_MUTABLE 중 하나를 지정해야 한다는 오류 보고이다. Google 문서에서는 FLAG_IMMUTABLE 사용을 강력히 고려하고 일부 기능이 변경 가능한 PendingIntent에 의존하는 경우에만 FLAG_MUTABLE을 사용하라고 말한다.

API 레벨 30 이전까지, FLAG_IMMUTABLE이 설정되지 않는 한 PendingIntent는 기본적으로 변경 가능했다. 하지만 API 레벨 31 부터는 PendingIntent를 사용하면 FLAG 변수로 FLAG_IMMUTABLE 또는 FLAG_MUTABLE을 사용하여 PendingIntent 사용시 변경 가능성을 명시적으로 지정해야한다(꼭 필요한 경우가 아니라면 FLAG_IMMUTABLE을 사용하도록 개발자 문서에 명시되어있다).

https://velog.io/@jeongminji4490/Error-Targeting-S-version-31-and-above-requires-that-one-of-FLAGIMMUTABLE-or-FLAGMUTABLE-be-specified-when-creating-a-PendingIntent
https://ddolcat.tistory.com/2393

알림 표시

NotificationManagerCompat.notify()를 호출하여 알림의 고유 ID와 NotificationCompat.Builder.build()의 결과를 전달합니다.

    with(NotificationManagerCompat.from(this)) {
        // notificationId is a unique int for each notification that you must define
        notify(notificationId, builder.build())
    }
    

알림을 업데이트하거나 삭제하려면 ID가 필요함.

작업 버튼 추가

최대 세 개의 작업 버튼을 제공
하지만 이 작업 버튼은 사용자가 알림을 탭할 때 실행되는 작업과 중복되지 않아야 한다.

PendingIntent를 addAction() 메서드에 전달한다.

바로 답장 작업 추가


https://youngest-programming.tistory.com/491

시스템 전체 카테고리 설정

시스템에서 기기가 방해 금지 모드에 있을 때 알림을 표시할 것인지 결정하는 데 사용된다.
CATEGORY_ALARM, CATEGORY_REMINDER, CATEGORY_EVENT 또는 CATEGORY_CALL

잠금 화면 공개 상태 설정

setVisibility()를 호출

  • VISIBILITY_PUBLIC은 알림의 전체 콘텐츠를 표시합니다.
  • VISIBILITY_SECRET은 알림의 어느 부분도 잠금 화면에 표시하지 않습니다.
  • VISIBILITY_PRIVATE은 알림 아이콘과 콘텐츠 제목 등의 기본 정보는 표시하지만 알림의 전체 콘텐츠는 숨깁니다.

알림에서 활동 시작

노티 클릭 시 펜딩인텐트를 걸어서 백스택 만들기
https://nomg92.tistory.com/5

<activity
            android:name=".MainActivity2"
            android:parentActivityName=".MainActivity"
            android:exported="false">
            <intent-filter>
                <action android:name="start" />
            </intent-filter>
        </activity>
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
val intent = Intent(this, MainActivity2::class.java)
            /*.apply {
            flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
        }*/
        intent.setAction("start")

        val resultPendingIntent: PendingIntent? = TaskStackBuilder.create(this).run {
            // Add the intent, which inflates the back stack
            addNextIntentWithParentStack(intent)
            // Get the PendingIntent containing the entire back stack
            getPendingIntent(0, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
        }
        //val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)

        val builder = NotificationCompat.Builder(this, CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            .setContentTitle("textTitle")
            .setContentText("textContent")
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .setContentIntent(resultPendingIntent)
            .setAutoCancel(true) // 탭하면 알림 자동 삭제

0개의 댓글