ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Android Kotlin] Permission에 대해서 정리해보기
    Framework/Android 2022. 4. 17. 22:39
    반응형

    Android Permission이란?

    안드로이드 마시멜로(Android API23) 이후에 출시된 안드로이드는 스마트폰 보안 정책을 강화하기 위해 핸드폰안에 권한을 설정하여 설정된 권한을

    부여한 것만 가져다 사용할 수 있도록 변경 되었다.

     

    Android Permission 워크 플로우

    https://developer.android.com/training/permissions/requesting?hl=ko

    워크 플로우란? 개발자에게UI/UX및 Permission관련 로직을 제공해주기 위해 설계된 플로우이다. 위에 내용을 해석해 보면 아래와 같이 표현 할 수 있다. 이것을 바탕으로 시나리오를 작성해보자.

    • 1 - Manifest에 필요한 Permission 내용 선언
    • 2~3 - 필요한 Permission에 맞게 앱 디자인 설계(Permission허락 관련)
    • 4 - Permission이미 허락 되었는지 아닌지 확인
      • 5~6 아니라면 Permission관련 내용 해석하여 알려주고 Permission 허락 요청 아니라면 재요청
      • 7~8 이미 Permission허락 된 경우 권한사용하여 내용(저장소, 카메라등) 접근하여 사용

     

    권한과 관련된 시나리오

    1. 최초로 권한을 요청하는 경우
    2. 거절당한 권한을 다시 요청하는 경우
    3. 거절과 동시에 해당 권한요청을 다시 표시하지 않음 옵션을 선택한 경우

     

    Permission 작성 순서

    1. Manifest에 Permission관련 내용 삽입
    2. 소스에서 SelfCheckPermission(권한 있는지 파악)하는 로직 구현
    3. 소스에서 관련 내용 가져와 Permission request(권한 수락 요청) 만들기
    4. 권한 없으면 재요청 하는 로직 만들기

     

    Manifest에 Permission관련 내용 삽입

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.permissionkt">
    
    	<!--추가한 부분-->
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28"/> <!-- 28 이상은 쓰기 권한 을 받을 필요가 없다-->
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
        <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
        <uses-permission android:name="android.permission.CAMERA"/>
        <uses-feature android:name="android.hardware.camera" android:required="true"/>
    	<!---->
    
        <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.PermissionKt">
            <activity
                android:name=".MainActivity"
                android:exported="true">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>

     

     

    소스에서 SelfCheckPermission(권한 있는지 파악)하는 로직 구현

    //권한 등록되어있는지 체크
    private fun selfCheckPermission() {
        //위치 기반 권한 체크
        isAccessCoarseLocationPermissionGranted = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION
        ) == PackageManager.PERMISSION_GRANTED
    
        isLocationPermissionGranted = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION
        ) == PackageManager.PERMISSION_GRANTED
    
        //저장소 일기 권한 체크
        isReadPermissionGranted = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE
        ) == PackageManager.PERMISSION_GRANTED
    
        //저장소 쓰기 권한 체크
        val isWritePermission = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE
        ) == PackageManager.PERMISSION_GRANTED
        val minSdkLevel = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q //쓰기 권한은 28이후에 나왔으므로
        isWritePermissionGranted = isWritePermission || minSdkLevel
    
        //오디오
        isRecordAudioPermissionGranted = ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO
        ) == PackageManager.PERMISSION_GRANTED
    }

     

    소스에서 관련 내용 가져와 Permission request(권한 수락 요청) 만들기

    //권한 없는것 요청
    private fun requestPermission() {
        val permissionRequest : MutableList<String> = ArrayList()
        if(!isAccessCoarseLocationPermissionGranted){ permissionRequest.add(Manifest.permission.ACCESS_COARSE_LOCATION) }
        if(!isLocationPermissionGranted)            { permissionRequest.add(Manifest.permission.ACCESS_FINE_LOCATION) }
        if(!isReadPermissionGranted)                { permissionRequest.add(Manifest.permission.READ_EXTERNAL_STORAGE) }
        if(!isWritePermissionGranted)               { permissionRequest.add(Manifest.permission.WRITE_EXTERNAL_STORAGE) }
        if(!isRecordAudioPermissionGranted)         { permissionRequest.add(Manifest.permission.RECORD_AUDIO) }
    
        //없는 권한 ArrayList로 만들어 Launch로 MultiPermission열기
        if(permissionRequest.isNotEmpty()){permissionLauncher.launch(permissionRequest.toTypedArray())}
    }

     

    권한 없으면 재요청 하는 로직 만들기

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    
        permissionLauncher = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()){ permissions ->
            isAccessCoarseLocationPermissionGranted = permissions[Manifest.permission.ACCESS_COARSE_LOCATION] ?: isAccessCoarseLocationPermissionGranted
            isReadPermissionGranted = permissions[Manifest.permission.ACCESS_FINE_LOCATION] ?: isReadPermissionGranted
            isWritePermissionGranted = permissions[Manifest.permission.READ_EXTERNAL_STORAGE] ?: isWritePermissionGranted
            isLocationPermissionGranted = permissions[Manifest.permission.WRITE_EXTERNAL_STORAGE] ?: isLocationPermissionGranted
            isRecordAudioPermissionGranted = permissions[Manifest.permission.RECORD_AUDIO] ?: isRecordAudioPermissionGranted
    
            //자리에 맞게 재요청 할 내용 Toast표시 및 requestPermission다시 보내기 등 하면 되는 자리
    		//if문으로 권한 재요청 할 것 작성하면 됨.
        }
    
        selfCheckPermission()
        requestPermission()
    }

     

    전체 소스

    package com.example.permissionkt
    
    import android.Manifest
    import android.content.pm.PackageManager
    import android.os.Build
    import androidx.appcompat.app.AppCompatActivity
    import android.os.Bundle
    import androidx.activity.result.ActivityResultLauncher
    import androidx.activity.result.contract.ActivityResultContract
    import androidx.activity.result.contract.ActivityResultContracts
    import androidx.core.content.ContextCompat
    
    class MainActivity : AppCompatActivity() {
    
        private lateinit var permissionLauncher : ActivityResultLauncher<Array<String>>
    
        private var isAccessCoarseLocationPermissionGranted = false
        private var isReadPermissionGranted = false
        private var isWritePermissionGranted = false
        private var isLocationPermissionGranted = false
        private var isRecordAudioPermissionGranted = false
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
            permissionLauncher = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()){ permissions ->
                isAccessCoarseLocationPermissionGranted = permissions[Manifest.permission.ACCESS_COARSE_LOCATION] ?: isAccessCoarseLocationPermissionGranted
                isReadPermissionGranted = permissions[Manifest.permission.ACCESS_FINE_LOCATION] ?: isReadPermissionGranted
                isWritePermissionGranted = permissions[Manifest.permission.READ_EXTERNAL_STORAGE] ?: isWritePermissionGranted
                isLocationPermissionGranted = permissions[Manifest.permission.WRITE_EXTERNAL_STORAGE] ?: isLocationPermissionGranted
                isRecordAudioPermissionGranted = permissions[Manifest.permission.RECORD_AUDIO] ?: isRecordAudioPermissionGranted
    
                //자리에 맞게 재요청 할 내용 Toast표시 및 requestPermission다시 보내기 등 하면 되는 자리
            }
    
            selfCheckPermission()
            requestPermission()
        }
    
    
        //권한 없는것 요청
        private fun requestPermission() {
            val permissionRequest : MutableList<String> = ArrayList()
            if(!isAccessCoarseLocationPermissionGranted){ permissionRequest.add(Manifest.permission.ACCESS_COARSE_LOCATION) }
            if(!isLocationPermissionGranted)            { permissionRequest.add(Manifest.permission.ACCESS_FINE_LOCATION) }
            if(!isReadPermissionGranted)                { permissionRequest.add(Manifest.permission.READ_EXTERNAL_STORAGE) }
            if(!isWritePermissionGranted)               { permissionRequest.add(Manifest.permission.WRITE_EXTERNAL_STORAGE) }
            if(!isRecordAudioPermissionGranted)         { permissionRequest.add(Manifest.permission.RECORD_AUDIO) }
    
            //없는 권한 ArrayList로 만들어 Launch로 MultiPermission열기
            if(permissionRequest.isNotEmpty()){permissionLauncher.launch(permissionRequest.toTypedArray())}
        }
    
        //권한 등록되어있는지 체크
        private fun selfCheckPermission() {
            //위치 기반 권한 체크
            isAccessCoarseLocationPermissionGranted = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION
            ) == PackageManager.PERMISSION_GRANTED
    
            isLocationPermissionGranted = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION
            ) == PackageManager.PERMISSION_GRANTED
    
            //저장소 일기 권한 체크
            isReadPermissionGranted = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE
            ) == PackageManager.PERMISSION_GRANTED
    
            //저장소 쓰기 권한 체크
            val isWritePermission = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE
            ) == PackageManager.PERMISSION_GRANTED
            val minSdkLevel = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q //쓰기 권한은 28이후에 나왔으므로
            isWritePermissionGranted = isWritePermission || minSdkLevel
    
            //오디오
            isRecordAudioPermissionGranted = ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO
            ) == PackageManager.PERMISSION_GRANTED
        }
    }
    반응형

    댓글

Designed by Tistory.