알림

낄낄몬스터·2024년 7월 19일
0

앱 개발 숙련

목록 보기
7/9

알림 (Notification)

  • 앱의 UI와 별도로 사용자에게 앱과 관련한 정보를 보여주는 기능

  • 알림을 터치하여 해당 앱을 열 수 있다

    • 바로 간단한 작업(예 : 문자 답하기)을 할 수 있음(Android 7.0부터)
  • 보통 단말기 상단 부분에 표시되고, 앱 아이콘의 배지로도 표시(Android 8.0부터)

알림 채널(Android 8.0이상)

  • Android 8.0이상의 경우는 알림을 만들기 전에 알림 채널을 먼저 만들어야함

  • 알림 채널은 알림을 그룹하여 알림 활성화나 방식을 변경 할 수 있음

  • 현재 앱이 실행 중인 안드로이드 버전을 확인하여 8.0이상인 경우만 채널 생성

private val myNotificationID = 1
private val channelID = "default"

private fun createNotificationChannel() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // Android 8.0
        val channel = NotificationChannel(channelID, "default channel",
            NotificationManager.IMPORTANCE_DEFAULT)
        channel.description = "description text of this channel."
        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.createNotificationChannel(channel)
    }
}

알림 생성

NotificationCompat.Builder 객체에서 알림에 대한 UI정보와 작업을 지정

  • setSmallIcon() : 작은 아이콘

  • setContentTitle() : 제목

  • setContentText() : 세부텍스트

NotificationCompat.Builder.build()호출

Notification객체를 반환

NotificationManagerCompat.notify()를 호출해서 시스템에 Notification객체를 전달

private val myNotificationID = 1

private fun showNotification() {
    val builder = NotificationCompat.Builder(this, channelID)
        .setSmallIcon(R.mipmap.ic_launcher)
        .setContentTitle("title")
        .setContentText("notification text")
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
    NotificationManagerCompat.from(this).notify(myNotificationID, builder.build())
}

알림 중요도

채널 중요도(Android 8.0이상)

  • NotificationChannel

    • channelID, "defaultchannel", NotificationManager.IMPORTANCE_DEFAULT

알림 우선순위(Android 7.1이하)

NotificationCompat.Builder(this,channelID).setPriority(NotificationCompat.PRIORITY_DEFAULT)

중요도 순위

알림 확장뷰 - 긴 텍스트

긴 텍스트은 어떻게 들어갈까?

알림 확장뷰 - 이미지

그림 넣으면?

알림 확장뷰 - 버튼 추가

버튼 시작

알림에 액티비티 연결

알림 생성과 등록

알림을 터치하면 어떻게 될까?

  1. 알림은 사라지고, SecondActivity가 실행됨

  2. SecondActivity가 실행 된 상태에서 Back이나 Up을 누르면 MainActivity가 나옴

  • 사실 MainActivity가 이미 백스택에 있기 때문에 TaskStackBuilder로 백스택을 조작하지 않아도 동일하게 동작

  • 백스택에 없는 다른 액티비티를 SecondActivity의 parentActivity로 하면 달라짐

알림(Notification) 예제

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/notificationButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="알림 보내기"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

두번째 Activity생성

  • File > New > Activity > Empty Activity

  • Activity Name : SecondActivity

  • activity_second.xml 에 “두번째 액티비티” 문구의 TextView 추가

MainActivity.kt

class MainActivity : AppCompatActivity() {
    private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(binding.root)
        binding.notificationButton.setOnClickListener{
            notification()
        }
    }

    fun notification(){
        val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager

        val builder: NotificationCompat.Builder
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
            // 26 버전 이상
            val channelId="one-channel"
            val channelName="My Channel One"
            val channel = NotificationChannel(
                channelId,
                channelName,
                NotificationManager.IMPORTANCE_DEFAULT
            ).apply {
                // 채널에 다양한 정보 설정
                description = "My Channel One Description"
                setShowBadge(true)
                val uri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
                val audioAttributes = AudioAttributes.Builder()
                    .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                    .setUsage(AudioAttributes.USAGE_ALARM)
                    .build()
                setSound(uri, audioAttributes)
                enableVibration(true)
            }
            // 채널을 NotificationManager에 등록
            manager.createNotificationChannel(channel)

            // 채널을 이용하여 builder 생성
            builder = NotificationCompat.Builder(this, channelId)

        }else {
            // 26 버전 이하
            builder = NotificationCompat.Builder(this)
        }

				val bitmap = BitmapFactory.decodeResource(resources, R.drawable.flower)
        val intent = Intent(this, SecondActivity::class.java)
        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
        val pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
        // 알림의 기본 정보
        builder.run {
            setSmallIcon(R.mipmap.ic_launcher)
            setWhen(System.currentTimeMillis())
            setContentTitle("새로운 알림입니다.")
            setContentText("알림이 잘 보이시나요.")
            setStyle(NotificationCompat.BigTextStyle()
                .bigText("이것은 긴텍스트 샘플입니다. 아주 긴 텍스트를 쓸때는 여기다 하면 됩니다.이것은 긴텍스트 샘플입니다. 
아주 긴 텍스트를 쓸때는 여기다 하면 됩니다.이것은 긴텍스트 샘플입니다. 아주 긴 텍스트를 쓸때는 여기다 하면 됩니다."))
            setLargeIcon(bitmap)
//            setStyle(NotificationCompat.BigPictureStyle()
//                    .bigPicture(bitmap)
//                    .bigLargeIcon(null))  // hide largeIcon while expanding
            addAction(R.mipmap.ic_launcher, "Action", pendingIntent)
        }


        manager.notify(11, builder.build())
    }

}

실행 결과

Android API 33이상에서 권한 시스템 변경

안드로이드에서 알림(Notification)은 사용자에게 정보를 전달하는 중요한 수단. 안드로이드 12(API 레벨 33)부터, 알림을 보내기 위한 권한 시스템에 변화가 생김. 개발자는 이제 알림을 보내기 위해 POST_NOTIFICATIONS 권한을 앱의 매니페스트 파일에 명시적으로 추가해야함

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp">

    <!-- API 33 이상을 위한 알림 권한 추가 -->
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

    ...
</manifest>

이 변경은 사용자의 프라이버시를 강화하고, 앱이 사용자의 동의 없이 알림을 보내는 것을 방지하기 위함. API 레벨 33 이상에서 앱을 개발하거나 업데이트할 때는 매니페스트에 이 권한을 추가해야 하며, 사용자는 앱 설치 후 처음 알림을 수신할 때 이 권한을 부여할지 결정하는 대화상자를 볼 수 있음.

사용자 권한 요청

앱이 실행 중일 때 사용자에게 알림 권한을 요청하기 위해, 다음과 같은 코드를 사용 가능

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
    if (!NotificationManagerCompat.from(this).areNotificationsEnabled()) {
        // 알림 권한이 없다면, 사용자에게 권한 요청
        val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply {
            putExtra(Settings.EXTRA_APP_PACKAGE, packageName)
        }
        startActivity(intent)
    }
}

이 코드는 사용자의 기기가 API 33 이상인지 확인한 후, 알림이 활성화되어 있는지를 검사하고, 권한이 없을 경우 설정 화면으로 사용자를 안내. 알림 권한 요청은 사용자 경험을 고려하여 적절한 시점에 수행해야 하며, 사용자가 알림의 가치를 이해할 수 있도록 설득력 있는 메시지를 제공해야함

profile
음악을 사랑하는 예비 앱개발자

0개의 댓글