Kotlin에서 앱에 런타임 권한 추가하기

1. 환영합니다

소개

앱 권한을 사용하면 앱의 샌드박스에서 제공하는 것 이상의 데이터와 기능에 액세스할 수 있습니다. 앱 권한은 인터넷과 기기 위치, 카메라 등에 액세스하도록 허용하여 앱의 기능을 개선할 수 있습니다.

이러한 기능을 사용하려면 사용자에게 권한을 요청해야 합니다. 이 Codelab에서는 런타임 권한을 추가하고 권한이 부여되었는지 확인하는 데 필요한 단계를 설명합니다.

필요한 항목

기본 요건

학습할 내용

  • Android 매니페스트에 권한을 추가하는 방법
  • 권한 요청 방법
  • 권한이 허용될 때와 거부될 때 처리하는 방법
  • 권한이 부여되었는지 확인하는 방법

빌드할 항목

카메라 권한을 요청하는 앱을 만듭니다. 앱의 권한 부분은 구현하지만, 카메라 부분은 구현하지 않습니다.

2. Android 스튜디오 프로젝트 만들기

  1. 새 Android 스튜디오 프로젝트를 시작합니다.
  2. Empty Activity를 선택합니다.

70e5de28256e3dcb.png

  1. 프로젝트 이름을 Permissions Codelab으로 지정하고 언어를 Kotlin으로 설정합니다.

f2948b584ca99c47.png

3. 코드 설정

  1. 다음 종속 항목의 최신 버전을 앱 수준의 build.gradle 파일에 추가합니다. 이렇게 하면 Codelab의 뒷부분에서 다루는 Activity 라이브러리를 사용할 수 있습니다.
implementation "androidx.activity:activity-ktx:1.2.2"
implementation "androidx.fragment:fragment-ktx:1.3.2"
  1. Android 블록에서 viewBinding 빌드 옵션을 true로 설정하여 ViewBinding을 사용 설정합니다.
android {
   ...
   buildFeatures {
       viewBinding true
   }
}
  1. 그런 다음, 녹색 망치 모양 버튼을 눌러 빌드합니다. 이렇게 하면 나중에 ViewBinding에 사용할 ActivityMainBinding이라는 결합 클래스가 생성됩니다.

d4064454e5c50111.png

  1. 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:id="@+id/main_layout"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context=".MainActivity">

   <Button
       android:id="@+id/button"
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="Request Permissions"
       android:onClick="onClickRequestPermission"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintEnd_toEndOf="parent"
       app:layout_constraintStart_toStartOf="parent"
       app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
  1. 다음 문자열을 strings.xml 파일에 추가합니다.
<string name="app_name">Permissions Codelab</string>
<string name="permission_required">Camera access is required to display the camera preview.</string>
<string name="ok">OK</string>
<string name="permission_granted">Permission is granted. You can use the camera now.</string>
  1. MainActivity.kt에서 onCreate() 메서드 위에 레이아웃 및 ViewBinding을 위한 변수를 정의합니다.
private lateinit var layout: View
private lateinit var binding: ActivityMainBinding
  1. onCreate() 메서드의 코드를 아래 코드로 교체합니다. 이 코드는 결합을 초기화하고 뷰를 나타내는 val을 만들어서 바인딩의 루트로 설정하고 레이아웃을 바인딩의 mainLayout으로 설정합니다.
override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   binding = ActivityMainBinding.inflate(layoutInflater)
   val view = binding.root
   layout = binding.mainLayout
   setContentView(view)
}
  1. 파일 하단의 MainActivity 클래스 아래에 Codelab 전체에 스낵바를 표시하는 확장 함수를 추가합니다.
fun View.showSnackbar(
   view: View,
   msg: String,
   length: Int,
   actionMessage: CharSequence?,
   action: (View) -> Unit
) {
   val snackbar = Snackbar.make(view, msg, length)
   if (actionMessage != null) {
       snackbar.setAction(actionMessage) {
           action(this)
       }.show()
   } else {
       snackbar.show()
   }
}

4. 매니페스트에 권한 추가

가장 먼저 해야 할 일은 <uses-permission> 태그를 사용하여 Android manifest에서 권한이 사용된다고 선언하는 것입니다.

요청하는 권한에는 다른 요구사항이 있는 경우도 있습니다. 이 경우 기기에 카메라가 있어야 카메라 앱을 사용할 수 있습니다. 따라서 <uses-feature> 태그도 매니페스트에 추가합니다.

  1. AndroidManifest.xml 파일의 <application> 태그 위에 카메라 권한을 추가합니다.
<uses-permission android:name="android.permission.CAMERA" />

5. 권한 런처 만들기

requestPermissionLauncher라는 val을 만들고 이 코드를 MainActivity.kt에 복사합니다. 다음 글머리 기호 몇 개는 여기에 있는 내용을 분석합니다.

private val requestPermissionLauncher =
   registerForActivityResult(
       ActivityResultContracts.RequestPermission()
   ) { isGranted: Boolean ->
       if (isGranted) {
           Log.i("Permission: ", "Granted")
       } else {
           Log.i("Permission: ", "Denied")
       }
   }
private val requestPermissionLauncher =
   registerForActivityResult(
       ActivityResultContracts.RequestPermission())
  • 부여 여부를 처리하는 콜백을 추가합니다. 여기에서는 결과를 기록합니다.
{ isGranted: Boolean ->
       if (isGranted) {
           Log.i("Permission: ", "Granted")
       } else {
           Log.i("Permission: ", "Denied")
       }
}

6. 권한 요청

  1. onClickRequestPermission(view: View)라는 함수를 만들고 이 코드를 함수에 복사합니다. 다음 글머리 기호 몇 개에서 안에 담긴 내용을 분석합니다.
fun onClickRequestPermission(view: View) {
   when {
       ContextCompat.checkSelfPermission(
           this,
           Manifest.permission.CAMERA
       ) == PackageManager.PERMISSION_GRANTED -> {
           layout.showSnackbar(
               view,
               getString(R.string.permission_granted),
               Snackbar.LENGTH_INDEFINITE,
               null
           ) {}
       }

       ActivityCompat.shouldShowRequestPermissionRationale(
           this,
           Manifest.permission.CAMERA
       ) -> {
           layout.showSnackbar(
               view,
               getString(R.string.permission_required),
               Snackbar.LENGTH_INDEFINITE,
               getString(R.string.ok)
           ) {
               requestPermissionLauncher.launch(
                   Manifest.permission.CAMERA
               )
           }
       }

       else -> {
           requestPermissionLauncher.launch(
               Manifest.permission.CAMERA
           )
       }
   }
}
  • when 문을 설정하여 다음 세 가지 경우를 다룹니다. 권한이 이미 부여된 경우, 앱에서 요청 권한 근거를 표시해야 한다고 판단하는 경우, 아직 요청하지 않은 경우
when {
   ContextCompat.checkSelfPermission(
       this,
       Manifest.permission.CAMERA
   ) == PackageManager.PERMISSION_GRANTED -> {

   }

   ActivityCompat.shouldShowRequestPermissionRationale(
       this,
       Manifest.permission.CAMERA
   ) -> {

   }

   else -> {

   }
}
  • 권한이 부여된 경우 이를 알리는 스낵바를 표시합니다.
ContextCompat.checkSelfPermission(
   this,
   Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED -> {
   layout.showSnackbar(
       view,
       getString(R.string.permission_granted),
       Snackbar.LENGTH_INDEFINITE,
       null
   ) {}
}
  • shouldShowRequestPermissionRationale()이 true를 반환하면 기능에 특정 권한이 필요한 이유를 자세히 설명하고 사용자에게 UI에서 권한을 수락/거부하는 방법을 제공하는 UI를 표시합니다.

a25d8c6c1d5051d.png

ActivityCompat.shouldShowRequestPermissionRationale(
   this,
   Manifest.permission.CAMERA
) -> {
   layout.showSnackbar(
       view,
       getString(R.string.permission_required),
       Snackbar.LENGTH_INDEFINITE,
       getString(R.string.ok)
   ) {
       requestPermissionLauncher.launch(
           Manifest.permission.CAMERA
       )
   }
}
  • 그 외의 경우에는 권한을 요청합니다.
else -> {
   requestPermissionLauncher.launch(
       Manifest.permission.CAMERA
   )
}

7. 요약

모든 작업이 완료되었습니다. 이 Codelab은 런타임 권한을 추가하는 방법을 보여주며 위치, 네트워크, 미디어 등과 관련된 권한에 사용할 수 있습니다.

최종 코드를 확인하고 문서에서 자세히 알아보세요.