안드로이드 권한2 : 위험 권한 허가 확인 및 허가 요청 코드 작성 방법
카메라, 공용 저장소와 같이 사용자의 개인 정보와 관련된 위험 권한 사용하는 방법
에 대해 정리합니다. 일반 권한 사용법은 이전 포스트인 아래의 링크를 참조해주세요.
런타임 권한(위험 권한)
런타임 권한 종류
위험 권한은 사용자의 개인정보와 관련된 데이터나 기능으로, 앱 실행중에 해당 데이터나 기능을 실행시 사용자에게 허가를 받아야 합니다. 아래는 위험 권한에 해당되는 예시입니다.
- 캘린더 읽기/쓰기
- 카메라
- 주소록 읽기/쓰기/계정정보 가져오기
- 위치 정보 사용
- 마이크 녹음
- 전화,문자관련
- 바디 센서
- 안드로이드 공용 저장소 읽기/쓰기
<!--위험 권한 - 코드 작성 필요-->
<!--권한 그룹 : CARENDAR-->
<uses-permission android:name="android.permission.READ_CALENDAR"/>
<uses-permission android:name="android.permission.WRITE_CALENDAR"/>
<!--권한 그룹 : CAMERA -->
<uses-permission android:name="android.permission.CAMERA"/>
<!--권한 그룹 : CONTACTS-->
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<!--권한 그룹 : LOCATION-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION_LOCATION"/>
<!-- 권한 그룹 : MICROPHONE-->
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<!-- 권한 그룹 : PHONE-->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.MODIFY_PHONE_NUMBER"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS"/>
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<uses-permission android:name="android.permission.WRITE_CALL_LOG"/>
<uses-permission android:name="android.permission.ADD_VOICEMAIL"/>
<uses-permission android:name="android.permission.USE_SIP"/>
<!-- 권한 그룹 : SENSOR-->
<uses-permission android:name="android.permission.BODY_SENSORS"/>
<!-- 권한 그룹 : SMS-->
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.RECEIVE_WAP_PUSH"/>
<uses-permission android:name="android.permission.RECEIVE_MMS"/>
<!-- 권한 그룹 : STORAGE-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
안드로이드 기기 기능의 권한 명세 및 권한 요청 필요성 검토는 아래의 링크를 참조해주세요.
권한 처리하기
위험 권한을 사용하기 위해 아래의 절차로 진행합니다.
- Manifest에 권한 명세
- 권한 확인 및 요청 코드 작성
권한 명세
사용하고자 하는 권한을 AndroidManifest.xml 파일에서 <uses-permission> 태그를 사용하여 권한 추가합니다. 카메라와 외부메모리를 사용하고 싶은 경우 아래와 같이 코드를 작성합니다. 자동완성 기능을 사용하면 쉽게 코드 작성이 가능합니다.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.blacklog.permission">
<!--권한 그룹 : CAMERA -->
<uses-permission android:name="android.permission.CAMERA"/>
<!-- 권한 그룹 : STORAGE-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Permission">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
API버전별 권한 명세 옵션
권한의 종류에 따라 API별 권한 명세 조건이 다른 경우가 있습니다. 예를들어, 앱에서 공용 저장소의 사진, 동영상 등의 콘텐츠를 표시 하는 경우 아래와 같이 API 수준에 따라 처리 방식이 구분됩니다.
- API 28이하 : 외부 저장소 읽기 권한 명세 필요
- API 29이상 : 외부 저장소 읽기 권한 명세 불필요, 미디어 저장소를 사용하여 파일을 열기
이런 경우 <user-permission> 태그의 maxSdkVersion 옵션을 사용하여 API 28이하 기기에서만 권한을 명세하도록 설정 할 수 있습니다.
....
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="28"/>
....
(참고)기능 명세 필터링 옵션 변경
<uses-permission> 으로 AndroidManifest.xml 에 카메라 권한이 명세되어 있으면, 카메라가 없는 기기의 구글 앱스토어에서는 해당 앱이 검색 되지 않습니다. 자동적으로 기기의 하드웨어 스펙에 맞게 필터링됩니다. 만약 카메라가 없는 기기에서도 해당 앱이 검색되어야 하면 아래의 같이 <uses-feature> 태그 및 requeired 옵션을 이용해서 앱 필터링을 조정할 수 있습니다.
- requeired 옵션
- true : 해당 기능이 없는 기기의 앱 스토어에는 앱이 검색 되지 않음
- false : 해당 기능의 유/무와 관계없이 앱스토에서 검색 가능
....
<!--권한 그룹 : CAMERA -->
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.permission.CAMERA" android:required="false"/>
<!-- 권한 그룹 : STORAGE-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
....
위와 같이 권한과 기능이 명세되어 있는 앱은, 카메라가 없는 기기의 앱스토어에서 검색이 가능합니다.
권한 요청 관련 코드
일반적으로 권한 요청은 아래의 3가지 단계가 있습니다.
- 권한 확인하기
ContextCompat.checkSelfPermission()메서드 사용- 권한 확인 결과 승인시
PackageManager.PERMISSION_GRANTED값을 반환
- (권한 미 승인시)권한 요청하기
- 권한 요청은
ActivityCompat.requestPermission()함수를 사용합니다. - 권한 요청은 그룹으로 요청 합니다.
- 권한 요청은
- 권한 요청 결과 처리
onRequestPermissionResult()함수를 override 하여 결과를 처리합니다.
권한 확인하기
권한 확인은 ContextCompat.CheckSelfPermission() 메서드를 사용합니다. 메서드의 인자 첫번째는 Context, 두번째 인자는 확인할 권한을 입력하면 됩니다. 메서드가 반환하는 값은 아래와 같습니다.
- ContextCompat.CheckSelfPermission() 반환 값
- 권한 승인 : PackageManager.PERMISSION_GRANTED
- 권한 미승인 : PackageManager.PERMISSION_DENIED
fun checkPermission(){
val permission = Manifest.permission.CAMERA
val permissionResult = ContextCompat.checkSelfPermission(this, permission)
when(permissionResult){
PackageManager.PERMISSION_GRANTED -> {
Toast.makeText(this, "Permission Granted", Toast.LENGTH_SHORT).show()
// Go Main Function
}
PackageManager.PERMISSION_DENIED -> {
Toast.makeText(this, "Permission Denied", Toast.LENGTH_SHORT).show()
// Go Request Permission
}
}
}
권한 요청하기
권한 요청은 ActivityCompat.requestPermissions() 함수를 사용하며, 권한 요청은 그룹으로 요청합니다. 함수의 인자로 Context, 권한 어레이(권한 그룹별 처리) 및 권한 요청 코드를 사용합니다. 권한 요청 코드는 사용자가 지정하고, 권한 그룹별 권한 요청 결과를 식별하기 위해 사용됩니다.
fun checkPermission(){
val permission = Manifest.permission.CAMERA
val permissionResult = ContextCompat.checkSelfPermission(this, permission)
when(permissionResult){
PackageManager.PERMISSION_GRANTED -> {
Toast.makeText(this, "Permission Granted", Toast.LENGTH_SHORT).show()
// Go Main Function
}
PackageManager.PERMISSION_DENIED -> {
Toast.makeText(this, "Permission Denied", Toast.LENGTH_SHORT).show()
ActivityCompat.requestPermissions(this, arrayOf(permission), 100)
}
}
}
권한 요청 결과 확인
권한 요청 결과 처리 코드는 onRequestPermissionResult() 콜백 함수에서 작성합니다. 클래스 내에서 Ctrl + O 를 눌러 콜백 함수를 검색 후 Override 할 수 있습니다.
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when(requestCode){
100 -> {
if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
Toast.makeText(this, "Permission Granted", Toast.LENGTH_SHORT).show()
// Go Main Function
}else{
Toast.makeText(this, "Permission Denied", Toast.LENGTH_SHORT).show()
// Finish() or Show Guidance on the need for permission
}
}
}
}
권한 처리하기 예제
프로젝트 생성
- 템플릿 : Empy Activity
- 프로젝트명 : Permission
- 언어 : Kotlin
앱 권한 매니패스트에 등록
app > manifests > AndroidManifest.xml 에 인터넷 사용 권한을 명시합니다. 카메라와 외장 메모리 읽기/쓰기를 등록하였습니다.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.blacklog.permission">
<!--권한 그룹 : CAMERA -->
<uses-permission android:name="android.permission.CAMERA"/>
<!-- 권한 그룹 : STORAGE-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Permission">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
View Binding 환경 설정
build.gradle(Module) 파일에 viewBinding 요소를 추가합니다.
android {
...
viewBinding {
enabled = true
}
}
실제 build.gradle(Module) 파일에서 아래와 같이 코드를 추가하면 됩니다.
※ View Binding은 레이아웃 View의 Id를 사용해서 코드와 연결해주는 도구 입니다. View Binding과 관련된 설명은 아래의 링크를 참조해주세요.
Manifest에 권한 명세하기
카메라와 외부저장소 권한을 명세하기 위해 AndroidManifest.xml 에 아래와 같이 코드를 작성합니다.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.blacklog.permission">
<!--권한 그룹 : CAMERA -->
<uses-permission android:name="android.permission.CAMERA"/>
<uses-feature android:name="android.permission.CAMERA" android:required="true"/>
<!-- 권한 그룹 : STORAGE-->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Permission">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
UI 만들기
레이아웃 파일 activity_main.xml 파일에서 아래와 같이 코드를 작성 합니다. 기존 코드에서 textView를 삭제하고 2개의 버튼을 추가하였습니다.
<?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/btnCameraPermission"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="Camera Permission"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/btnStoragePermission"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:text="External Storage Permission"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/btnCameraPermission" />
</androidx.constraintlayout.widget.ConstraintLayout>
코드 작성하기 MainActivity.kt
아래 코드는 카메라와 공용 저장소 권한을 확인하고 승인 받기 위한 코드입니다.
package com.blacklog.permission
import android.Manifest
import android.content.pm.PackageManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.Toast
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.blacklog.permission.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity(){
lateinit var binding : ActivityMainBinding
// 권한 정의
val CAMERA_PERMISSION = arrayOf(Manifest.permission.CAMERA)
val CAMERA_PERMISSION_REQUEST = 100
val STORAGE_PERMISSION = arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE)
val STORAGE_PERMISSION_REQUEST = 200
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
binding.btnCameraPermission.setOnClickListener {
checkPermission(CAMERA_PERMISSION, CAMERA_PERMISSION_REQUEST)
}
binding.btnStoragePermission.setOnClickListener {
checkPermission(STORAGE_PERMISSION, STORAGE_PERMISSION_REQUEST)
}
}
fun checkPermission(permissions: Array<String>, permissionRequestNumber:Int){
val permissionResult = ContextCompat.checkSelfPermission(this, permissions[0])
when(permissionResult){
PackageManager.PERMISSION_GRANTED -> {
Toast.makeText(this, "Permission Granted", Toast.LENGTH_SHORT).show()
// Go Main Function
}
PackageManager.PERMISSION_DENIED -> {
ActivityCompat.requestPermissions(this, permissions, permissionRequestNumber)
}
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when(requestCode){
CAMERA_PERMISSION_REQUEST -> {
if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
Toast.makeText(this, "Camera Permission Granted", Toast.LENGTH_SHORT).show()
// Go Main Function
}else{
Toast.makeText(this, "Camera Permission Denied", Toast.LENGTH_SHORT).show()
// Finish() or Show Guidance on the need for permission
}
}
STORAGE_PERMISSION_REQUEST -> {
if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
Toast.makeText(this, "Storage Permission Granted", Toast.LENGTH_SHORT).show()
// Go Main Function
}else{
Toast.makeText(this, "Storage Permission Denied", Toast.LENGTH_SHORT).show()
// Finish() or Show Guidance on the need for permission
}
}
}
}
fun toast(message: String){
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
}
실행 결과
위 코드를 실행하면 아래와 같이 Camera 및 Storage 권한이 승인 되는 것을 확인 할 수 있습니다.
끝까지 읽어 주셔서 감사합니다.^^
'Programming > Android App(Kotlin)' 카테고리의 다른 글
안드로이드 코틀린 : 토스트(Toast) 팝업 메세지 사용법 및 전역 함수로 사용법 (2) | 2021.03.19 |
---|---|
안드로이드 저장소 정리 : 앱 전용 디렉토리? 내부 저장소? 외부 저장소? 공용저장소 (0) | 2021.03.17 |
안드로이드 코틀린 : 권한 개요 및 일반 권한 사용하기 - WebView (0) | 2021.03.15 |
안드로이드 View Binding 사용하기 - kotlin-android-extensions 지원 중단 (0) | 2021.03.12 |
안드로이드 코틀린 : 전환된 Activity 종료 결과 수신하기, startActivityForResult() 와 onActivityResult() (1) | 2021.03.11 |