외로운 Nova의 작업실

안드로이드 앱 프로그래밍 - 11(소리와 진동알림, 알림) 본문

Programming/Kotlin - Android

안드로이드 앱 프로그래밍 - 11(소리와 진동알림, 알림)

Nova_ 2023. 1. 17. 16:18

- 소리 알림

사용자에게 짧은 소리로 특정한 상황을 알리때가 있습니다. 대표적으로 문자앱에서 새로운 메시지를 전달받으면 사용자 알림 효과로 짧은 소리를 이용해 알려줍니다. 이런 목적으로 사용하는 짧은 소리를 알림음이라고 합니다. 알림음은 녹음한 음원을 쓸 수도 있지만 안드로이드 시스템에 등록된 소리를 이용할 수 있습니다. 안드로이드시스템은 알림(notification), 알람(alarm), 벨소리(ringtone)등의 소리를 제공하며 이소리는 RingtonManager로 얻을 수 있습니다.

 

<소리얻기>

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val binding = ActivityMainBinding.inflate(layoutInflater)
        val items = arrayOf<String>("사과", "복숭아", "수박", "딸기")
        setContentView(binding.root)

        //소리얻기
        val notification: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)  //소리의 식별값 얻기
        val ringtone = RingtoneManager.getRingtone(applicationContext, notification) //식별값으로 소리얻기
        ringtone.play()
    }
}

 

- 진동알림

진동도 사용자 알림효과로 많이 이용합니다. 앱에서 진동이 울리게하려면 먼저 매니페스트 파일에 퍼미션을 얻어야합니다.

 <uses-permission android:name="android.permission.VIBRATE"/>

이후 getSystemService() 함수로 진동 객체를 얻어야합니다. 이때 26버전 이후로는 진도으이 세기까지 조절가능합니다.

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val binding = ActivityMainBinding.inflate(layoutInflater)
        val items = arrayOf<String>("사과", "복숭아", "수박", "딸기")
        setContentView(binding.root)

        //진동얻기
        val vibrator = getSystemService(VIBRATOR_SERVICE) as Vibrator
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
            vibrator.vibrate(VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE))
        } else{
            vibrator.vibrate(500)
        }


    }
}

 

- 알림

알림은 상태바에 앱의 정보를 출력하는 것입니다. 알림을 주려면 앱의 어떤 부분에서 알람을 주는 건지를 설정하고 빌드해준다음 빌드한 객체를 가지고 알림 객체를 설정해줍니다. 이 알림 객체를 매니저에게 전달하면 알림이 전달되게됩니다.

 

<채널 설정 및 빌드>

알림 채널 생성자는 아래와 같습니다.

NotificationChannek(id: String!, name: Charsequence!, importance: Int)

 첫번째 매개변수는 채널의 식별값이며 두번째 매개변수는 채널의 이름입니다. 세번째는 중요도 이며 다음과 같은 상수로 설정합니다.

NotificationManager.IMPORTANCE_HIGH	//긴급상황으로 알림음이 울리며 헤드업으로 표시
NotificationManager.IMPORTANCE_DEFAULT //높은 중요도이며 알림음이 울림
NotificationManager.IMPORTANCE_LOW //중간 중요도이며 알림음이 울리지 않음
NotificationManager.IMPORTANCE_MIN //낮은 중요도이며 알림음도 없고 상태바에 표시되지않음

채널의 각종정보는 함수나 프로퍼티로 설정할 수 있습니다.

fun setDescription(description: String!): Unit = 채널의 설명 문자열
fun setShowBadge(showBadge: Boolean): Unit = 홈화면의 아이콘에 배지 아이콘 출력 여부
fun setSound(sound: Uri, audioAttreibutes: AudioAttributes!): Unit = 알림음 재생
fun enableVibration(vibration: Boolean): Unit = 진동을 울릴지 여부

이제 채널을 설정하고 등록하고 알림 빌더를 만들어보갰습니다.


class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val binding = ActivityMainBinding.inflate(layoutInflater)
        val builder: NotificationCompat.Builder //알림 빌더 선언

        //알림 빌더 작성
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channelId = "test-chennel"
            val channelName = "test channel"
            val channel =
                NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH)

            //채널에 다양한 정보 설정
            channel.description = "chennel test"
            channel.setShowBadge(true)
            val uri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
            val audioAttributes =
                AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                    .setUsage(AudioAttributes.USAGE_ALARM)
                    .build()
            channel.setSound(uri, audioAttributes)
            channel.enableVibration(true)

            //채널을 NotificationManger에 등록
            val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.createNotificationChannel(channel)

            //채널을이용해 알림 빌더 생성
            builder = NotificationCompat.Builder(this, channelId)
        } else {
            builder = NotificationCompat.Builder(this)

        }
    }
}

 

<알림 빌더 설정>

알림 빌더를 이제 아이콘 제목 알림 시각, 내용등을 설정해줘야합니다. 아래 설정 함수로 가능합니다.

builder.setSmallIcon(R.drawable.image1)
builder.setWhen(System.currentTimeMillis())
builder.setContentTitle("Content Title")
builder.setContentText("message")

이제 계속해서 코딩해줍니다.

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val binding = ActivityMainBinding.inflate(layoutInflater)
        val builder: NotificationCompat.Builder //알림 빌더 선언

        //알림 빌더 작성
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channelId = "test-chennel"
            val channelName = "test channel"
            val channel =
                NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH)

            //채널에 다양한 정보 설정
            channel.description = "chennel test"
            channel.setShowBadge(true)
            val uri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
            val audioAttributes =
                AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                    .setUsage(AudioAttributes.USAGE_ALARM)
                    .build()
            channel.setSound(uri, audioAttributes)
            channel.enableVibration(true)

            //채널을 NotificationManger에 등록
            val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.createNotificationChannel(channel)

            //채널을이용해 빌더 생성
            builder = NotificationCompat.Builder(this, channelId)
        } else {
            builder = NotificationCompat.Builder(this)
        }

        //알림 빌더 설정
        builder.setSmallIcon(R.drawable.image1)
        builder.setWhen(System.currentTimeMillis())
        builder.setContentTitle("Content Title")
        builder.setContentText("message")
        
        //알림 빌더로 알림 발생시키기
        with(NotificationManagerCompat.from(this)) {
            // notificationId is a unique int for each notification that you must define
            notify(11, builder.build())
        }
    }
}

 

<알림 취소>

알림을 없애는 것은 사용자가 알림을 터치하거나 슬라이드로 밀어내는 경우가 있습니다. 하지만 이런경우에도 알림을 없애지 못하게 할 수 있습니다.

builder.setAutoCancel(false) //알람을 터치해도 알람이 사라지지않습니다.
builder.setOngoing(true)  //알림을 밀어내도 사라지지않습니다.

위처럼 모두 2가지 설정을 했다면 코드에서 cancel 함수로 취소해줘야합니다. 이때 매개변수는 알림의 ID입니다.

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val binding = ActivityMainBinding.inflate(layoutInflater)
        val builder: NotificationCompat.Builder //알림 빌더 선언

        //알림 빌더 작성
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channelId = "test-chennel"
            val channelName = "test channel"
            val channel =
                NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH)

            //채널에 다양한 정보 설정
            channel.description = "chennel test"
            channel.setShowBadge(true)
            val uri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
            val audioAttributes =
                AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                    .setUsage(AudioAttributes.USAGE_ALARM)
                    .build()
            channel.setSound(uri, audioAttributes)
            channel.enableVibration(true)

            //채널을 NotificationManger에 등록
            val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.createNotificationChannel(channel)

            //채널을이용해 빌더 생성
            builder = NotificationCompat.Builder(this, channelId)
        } else {
            builder = NotificationCompat.Builder(this)
        }

        //알림 빌더 설정
        builder.setSmallIcon(R.drawable.image1)
        builder.setWhen(System.currentTimeMillis())
        builder.setContentTitle("Content Title")
        builder.setContentText("message")
        builder.setAutoCancel(false)
        builder.setOngoing(true)

        //알림 빌더로 알림 발생시키기
        with(NotificationManagerCompat.from(this)) {
            // notificationId is a unique int for each notification that you must define
            notify(11, builder.build())
        }
        
        //알림 취소
        NotificationManagerCompat.from(this).cancel(11)



    }
}

 

<알림 인텐트 설정>

사용자가 알림을 누르거나 버튼을 누르게되면 시스템은 알림빌더의 인텐트를 실행하게됩니다. 그래서 저희는 인텐트를 만들어 알림빌더에 등록을 해줘야합니다. 이번에는 간단하게 알림을 터치하게되면 그 액티비티를 실행하는 인텐트를 등록해볼 것입니다. 

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val binding = ActivityMainBinding.inflate(layoutInflater)
        val builder: NotificationCompat.Builder //알림 빌더 선언

        //알림 빌더 작성
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channelId = "test-chennel"
            val channelName = "test channel"
            val channel =
                NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH)

            //채널에 다양한 정보 설정
            channel.description = "chennel test"
            channel.setShowBadge(true)
            val uri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
            val audioAttributes =
                AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
                    .setUsage(AudioAttributes.USAGE_ALARM)
                    .build()
            channel.setSound(uri, audioAttributes)
            channel.enableVibration(true)

            //채널을 NotificationManger에 등록
            val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.createNotificationChannel(channel)

            //채널을이용해 빌더 생성
            builder = NotificationCompat.Builder(this, channelId)
        } else {
            builder = NotificationCompat.Builder(this)
        }

        //알림 빌더 설정
        builder.setSmallIcon(R.drawable.image1)
        builder.setWhen(System.currentTimeMillis())
        builder.setContentTitle("Content Title")
        builder.setContentText("message")
        builder.setAutoCancel(false)
        builder.setOngoing(true)
        
        //알림 인텐트 만들기
        val intent = Intent(this, MainActivity::class.java)
        val pendingIntent =
                PendingIntent.getActivity(this, 10, intent, PendingIntent.FLAG_UPDATE_CURRENT)
        
        //알림 인텐트를 알림에 등록하기
        builder.setContentIntent(pendingIntent)
        
        //알림 빌더로 알림 발생시키기
        with(NotificationManagerCompat.from(this)) {
            // notificationId is a unique int for each notification that you must define
            notify(11, builder.build())
        }

사용자가 만약 알림을 누른다면 시스템은 pendingintent를 실행시켜 앱에서의 intent를 실행하게도됩니다. 즉 구성은 아래와 같습니다.

이 pendingintent 객체는 시스템으로부터 명령이 올때까지 기다렸다가 신호가 오면 앱상의 인텐트를 실행시켜주는 인텐트입니다. 또한 pendinginent는 신호가오면 액티비티를 실행시켜주는 인텐트와 브로드캐스트를 해주는 인텐트와 서비스를 실행시켜주는 인텐트로 나눌 수있으며, 각각인텐트를 가져오는 함수는 아래와 같습니다.

getActivity(Context, int, Intent, int) -> Activity를 시작하는 인텐트를 생성함
getBroadcast(Context, int, Intent, int) -> BroadcastReceiver를 시작하는 인텐트를 생성함
getService(Context, int, Intent, int)  -> Service를 시작하는 인텐트를 생성함

첫번째 매개변수는 컨텍스트이며 두번째 매개변수는 요청 식별자이며 세번째 매개변수는 실행할 인텐트 네번째 매개변수는 플래그입니다. 따라서 위 코드를 실행해 알림을 터치하게되면 액티비티를 실행하게됩니다.

 

- 추가적인 인텐트설정

카카오톡에보면 알림창에서도 답장을 보낼 수 있는 기능이 있습니다. 이는 getBoradCast의 pendingintent를 사용합니다. 사용자가 답장을 보내면 시스템은 getBoradCast의 pendingintet를 실행시키면 브로드캐스트를 내보내고, 앱에서 intent는 그 브로드캐스트를 받고 리시버를 실행시켜 앱에서 처리합니다.

 

Comments