다이얼로그와 알림 이용하기

이윤설·2024년 8월 27일
0

API 레벨 호환성 고려하기

안드로이드 앱 개발 시, minSdktargetSdk를 설정하여 앱의 최소 지원 버전과 목표 버전을 지정한다.

minSdk 24
targetSdk 34

위 설정은 앱이 API 레벨 34 버전에서 개발되지만, API 레벨 24 이상을 지원하는 기기에서도 오류 없이 동작해야 함을 의미한다. 하지만, 개발 중에 minSdk 설정값보다 상위 버전에서 제공하는 API를 사용한다면, 하위 버전에서의 호환성 문제를 고려해야 한다.

API 레벨 호환성 문제 예시

위 이미지에서 Notification 클래스는 API 레벨 1에서 추가되었음을 나타낸다. 즉, 이 클래스는 모든 안드로이드 버전에서 사용할 수 있으므로, minSdk를 24로 설정한 앱에서도 API 레벨 호환성 문제가 발생하지 않는다.

그러나, 상위 버전에 새로 추가된 기능을 사용할 때는 상황이 달라진다.

예를 들어, Notification.CallStyle 클래스는 API 레벨 31에 추가되었다. 따라서 이 클래스를 사용할 경우, API 레벨 24를 사용하는 기기에서는 호환성 문제가 발생한다. 이때, 안드로이드 스튜디오에서 컴파일 에러 또는 경고가 발생할 수 있다.

호환성 문제 해결: 애너테이션 사용

안드로이드에서는 이러한 호환성 문제를 해결하기 위해 @RequiresApi 또는 if (Build.VERSION.SDK_INT >= ...) 조건문을 사용한다.

1. @RequiresApi 애너테이션 사용

@RequiresApi(Build.VERSION_CODES.S) // API 레벨 31 이상에서만 호출 가능
fun useCallStyleNotification() {
    val callStyle = Notification.CallStyle.forIncomingCall("caller", null, null)
    // API 레벨 31 이상에서만 사용 가능한 기능
}

위와 같이 @RequiresApi 애너테이션을 사용하면, 해당 함수가 특정 API 레벨 이상에서만 호출되도록 제한할 수 있다.

2. 조건문으로 버전 체크

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
    // API 레벨 31 이상에서만 사용 가능한 기능
    val callStyle = Notification.CallStyle.forIncomingCall("caller", null, null)
} else {
    // 하위 버전에서 사용할 대체 기능
}

위 코드에서는 조건문을 통해 기기의 API 레벨을 체크한 후, 해당 기능을 사용할지 여부를 결정한다.

결론

API 레벨 호환성은 안드로이드 앱 개발에서 중요한 부분이다.
minSdk보다 상위 버전의 API를 사용할 때는 반드시 호환성을 고려해야 하며, 이를 위해 애너테이션 또는 조건문을 통해 안전한 코드를 작성해야 한다.


2. 퍼미션 설정하기

안드로이드 시스템에서는 민감한 정보에 접근하거나 기기 기능을 사용할 때 사용자로부터 권한을 요청해야 한다.

1. 퍼미션의 종류

  • Normal Permissions: 기기 데이터 및 리소스에 위험이 거의 없는 권한으로, 시스템이 자동으로 부여한다. 예: 인터넷 사용 권한 (INTERNET).
  • Dangerous Permissions: 사용자의 개인 정보나 기기 데이터에 접근할 수 있는 권한으로, 명시적으로 사용자에게 요청해야 한다. 예: 카메라 사용 권한 (CAMERA), 위치 접근 권한 (ACCESS_FINE_LOCATION).
  • Signature Permissions: 앱이 동일한 서명 키로 서명된 경우에만 부여된다. 예: READ_LOGS.

2. 런타임 퍼미션

  • 안드로이드 6.0 (API 레벨 23; 2015년 출시) 이상부터는 Dangerous Permissions에 대해 런타임 시점에 권한을 요청해야 한다. 사용자가 앱을 설치할 때가 아니라, 해당 기능을 처음 사용할 때 권한을 요청해야 한다.

3. 권한 그룹

  • 안드로이드에서 권한은 그룹으로 묶여 있다.
    사용자가 같은 그룹의 하나의 권한을 승인하면, 같은 그룹 내 다른 권한도 자동으로 승인된다. 예를 들어, READ_CONTACTS 권한을 승인하면, 같은 그룹의 WRITE_CONTACTS 권한도 자동으로 승인된다.

4. 권한 요청 방법

  • 권한을 요청하려면 ActivityCompat.requestPermissions() 메서드를 사용한다.
  • 사용자 응답에 따라 onRequestPermissionsResult() 콜백 메서드를 통해 결과를 처리한다.

5. 권한 요청 전에 이유 설명 (Rationale)

  • 사용자가 권한 요청을 거부한 적이 있거나, 권한 요청에 대해 추가 설명이 필요한 경우, shouldShowRequestPermissionRationale() 메서드를 통해 권한이 필요한 이유를 설명하는 UI를 제공하는 것이 좋다.

6. 권한 거부 시 대처

  • 사용자가 권한을 거부하거나 "다시 묻지 않음"을 선택한 경우, 해당 기능을 사용할 수 없다는 메시지를 보여주거나, 설정으로 이동하여 권한을 직접 부여할 수 있도록 안내할 수 있다.

7. Android 10 (API 레벨 29) 이후 변경사항

  • 위치 권한이 ACCESS_FINE_LOCATIONACCESS_COARSE_LOCATION 외에 백그라운드 위치 권한 (ACCESS_BACKGROUND_LOCATION)으로 세분화되었다.
  • 저장소 접근 권한이 Scoped Storage로 변경되어, 앱별로 별도의 저장소에 접근하도록 관리됩니다.

8. Android 11 (API 레벨 30) 이후 변경사항

  • "한 번만 허용" 옵션이 추가되어 사용자가 일회성으로만 권한을 허용할 수 있다.
  • 사용자가 오랜 기간 앱을 사용하지 않으면, 시스템이 자동으로 권한을 리셋하는 기능이 추가되었다.

9. Best Practices

  • 필요한 최소한의 권한만 요청한다.
  • 권한을 요청하기 전에 사용자에게 명확한 이유를 제공한다.
  • 권한이 필요한 기능을 사용할 때만 런타임에 요청하여 사용자 경험을 개선한다.
  • 정기적으로 권한 정책을 검토하고 최신 안드로이드 버전에서의 권한 처리 방식을 숙지한다.

3. 다양한 다이얼로그

1. 기능 설명

1.1. 토스트 메시지(Toast Message) 띄우기

  • 토스트 메시지는 짧은 시간 동안 화면에 나타나는 간단한 메시지다. 사용자에게 알림이나 상태를 전달할 때 사용된다. 기본적으로 몇 초 동안 화면 하단에 나타났다 사라진다.
Toast.makeText(context, "This is a Toast message", Toast.LENGTH_SHORT).show()
  • Toast.LENGTH_SHORT는 짧은 시간(약 2초), Toast.LENGTH_LONG은 긴 시간(약 3.5초) 동안 표시됩니다.

1.2. 날짜 또는 시간 입력받기

  • 안드로이드에서 날짜나 시간을 입력받을 때는 DatePickerDialogTimePickerDialog를 사용한다. 이 다이얼로그들은 사용자가 날짜 또는 시간을 선택할 수 있는 UI를 제공한다.

  • 날짜 선택 다이얼로그:

    DatePickerDialog(context, { _, year, month, dayOfMonth ->
        // 선택된 날짜 처리
    }, year, month, day).show()
  • 시간 선택 다이얼로그:

    TimePickerDialog(context, { _, hourOfDay, minute ->
        // 선택된 시간 처리
    }, hour, minute, true).show() // true는 24시간 형식 사용 여부

1.3. 알림창(AlertDialog) 띄우기

  • AlertDialog는 사용자가 어떤 작업을 수행하기 전에 확인을 받거나 중요한 메시지를 전달할 때 사용한다.
AlertDialog.Builder(context)
    .setTitle("Alert")
    .setMessage("This is an alert dialog")
    .setPositiveButton("OK") { dialog, _ -> dialog.dismiss() }
    .setNegativeButton("Cancel") { dialog, _ -> dialog.dismiss() }
    .show()

4. 소리와 진동

1. 소리 (Sound)

안드로이드에서 소리를 재생하기 위해 다양한 방법을 사용할 수 있다.

1.1. SoundPool

  • SoundPool은 짧은 오디오 클립(효과음 등)을 재생하는 데 최적화된 클래스다. 게임이나 앱에서 빠르게 반복 재생해야 하는 소리(예: 버튼 클릭 소리, 충돌 소리 등)를 다룰 때 적합합니다.
  • 여러 소리를 동시에 재생하거나 반복 재생할 수 있다.
val soundPool = SoundPool.Builder().setMaxStreams(5).build()
val soundId = soundPool.load(this, R.raw.sound_file, 1)
soundPool.play(soundId, 1f, 1f, 0, 0, 1f)

1.2. MediaPlayer

  • MediaPlayer는 긴 오디오 파일(예: 음악, 스트리밍 오디오)을 재생할 때 주로 사용된다. 다양한 포맷의 오디오 파일을 지원하며, 로컬 파일이나 URL을 통해 스트리밍 오디오도 재생 가능하다.
val mediaPlayer = MediaPlayer.create(this, R.raw.music_file)
mediaPlayer.start()

1.3. AudioManager

  • AudioManager는 기기의 오디오 설정을 제어하는 데 사용된다. 예를 들어, 벨소리, 미디어 볼륨, 알림음 등을 제어할 수 있다.
val audioManager = getSystemService(Context.AUDIO_SERVICE) as AudioManager
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volumeLevel, 0)

2. 진동 (Vibration)

진동은 사용자가 기기에서 특정 이벤트를 인식하도록 도와준다.
알림, 경고, 사용자 인터페이스 상호작용 시 피드백을 제공하는 데 유용하다.

2.1. Vibrator

  • 진동을 제어하기 위해 Vibrator 클래스를 사용한다. 간단한 진동부터 패턴 진동까지 다양한 설정을 할 수 있다.
val vibrator = getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    vibrator.vibrate(VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE)) // 500ms 진동
} else {
    vibrator.vibrate(500) // 500ms 진동 (레거시 방식)
}

2.2. 패턴 진동

  • 진동을 패턴으로 설정하여 더 복잡한 진동 효과를 줄 수 있다. 예를 들어, 진동과 멈춤을 반복하는 패턴을 만들 수 있다.
val pattern = longArrayOf(0, 200, 100, 300) // 대기 0ms, 진동 200ms, 멈춤 100ms, 진동 300ms
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    vibrator.vibrate(VibrationEffect.createWaveform(pattern, -1)) // -1은 반복 없음
} else {
    vibrator.vibrate(pattern, -1) // 레거시 방식
}

3. 소리와 진동 사용 시 고려 사항

  • 사용자 설정: 사용자가 기기의 소리 및 진동을 제어할 수 있도록 권한을 요청하거나 설정에서 허용 여부를 확인해야 한다.
  • 환경에 따른 제어: 상황에 맞게 소리와 진동을 다르게 처리할 수 있도록 AudioManager를 통해 현재 기기의 소리 모드를 확인하고(예: 무음, 진동 모드) 이에 맞게 동작을 조정해야 한다.
  • 권한: 진동 사용을 위해 VIBRATE 권한이 필요하며, 알림이나 소리 관련 기능을 추가할 때 권한 요청 및 설정이 적절히 이루어져야 한다.

5. 알림

1. 알림의 기본 개념

알림은 안드로이드 시스템 상단의 상태 바에 표시되며, 사용자가 이를 클릭하면 특정 액션을 수행하도록 할 수 있다. 기본적으로 알림은 다음과 같은 구조로 이루어진다:

  1. Notification Channel (알림 채널): API 레벨 26(Android 8.0, Oreo) 이상에서 도입된 개념이다. 알림을 분류하여 관리할 수 있도록 도와주며, 사용자에게 각 채널별로 알림 설정을 제어할 수 있게 한다. 채널은 중요도, 소리, 진동 등을 정의할 수 있다.

예시)

  1. NotificationCompat.Builder: 알림을 생성하기 위한 빌더 클래스다. 이 빌더를 사용해 알림의 제목, 내용, 아이콘, 우선순위 등을 설정한다.

  2. NotificationManager: 생성된 알림을 시스템에 전달하여 실제로 표시되도록 하는 클래스다. notify() 메서드를 통해 알림을 화면에 띄운다.

2. API 레벨 33 이상: 알림 권한 요청

API 레벨 33(Android 13, Tiramisu) 이상에서는 알림을 띄우기 전에 사용자에게 권한을 요청해야 한다. 이는 사용자가 원치 않는 알림을 받을 가능성을 줄이기 위한 보안 조치이다.

3. 알림 구성의 기본 구조

알림은 다음 단계로 구성된다.

  1. Notification Channel 생성 (API 레벨 26 이상)
  2. NotificationCompat.Builder로 알림 구성
  3. Notification 객체 생성NotificationManager를 통해 알림 표시

4. 알림 권한 관리

API 레벨 33 이상에서는 알림을 띄우기 전에 권한을 요청해야 한다.
권한이 부여되지 않으면 알림을 띄울 수 없으므로, 권한이 필요한 경우 이를 처리하는 로직을 추가해야 한다.

5. 추가 팁

  • 알림의 중요도: 중요도에 따라 알림의 표시 방식이 달라진다. 예를 들어, IMPORTANCE_HIGH로 설정하면 알림이 팝업으로 표시되고 소리와 진동이 함께 발생한다.
  • PendingIntent 사용: 알림을 클릭했을 때 특정 액티비티나 동작을 실행하고자 할 때 PendingIntent를 사용한다.

{책의 내용은 너무 방대해서 스킵하고 간단하게 정리하였다.}


참고도서: https://www.yes24.com/Product/Goods/116012310

profile
화려한 외면이 아닌 단단한 내면

0개의 댓글