# 알게 된 것
-- 👇 이번 포스팅 👇--
- 파일(이미지) 접근 권한 얻기
-- 👇 다음 포스팅 👇--
- Content Provider
- 사진첩에서 선택한 이미지 액티비티로 보내기
# 권한이란 ?
안드로이드에서는 앱이 아래와 같은 것들에 접근하여 파일이나 데이터를 이용하게 되려면 사용자가 그 권한을 확인을 해야만 접근이 가능하다.
이번 앨범 만들기 실습을 통해서, 사진첩에 있는 사진을 가져오는 권한을 얻는 방법에 대해서 공부할 수 있었다. 아래 쉽게 정리하자면 우리가 흔히보던 아래 이미지와 같은 것이다.
# 구현
먼저 위에서 보았던 그림에서 밑에 "사진 선택하기" 라는 버튼을 누르게 되면 동작하게 된다. 아래와 같이 코드를 작성했다.
addPhotoButton.setOnClickListener {
when {
ContextCompat.checkSelfPermission(this,
android.Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED -> {
// READ_EXTERNAL_STORAGE의 권한이 PERMISSION_GRANTED와 같다면..
//TODO 권한이 잘 부여되었을 때상황, 갤러리에서 사진을 선택하는 코드 구현
navigatePhotos()
}
shouldShowRequestPermissionRationale(android.Manifest.permission.READ_EXTERNAL_STORAGE) -> {
// 권한을 명시적으로 거부한 경우 true
// 처음보거나, 다시묻지 않음을 선택한 경우 false
//TODO 교육용 팝업 확인 후 권한 팝업을 띄우는 기능
showPermissionContextPopup()
}
else -> {
// 처음봤을때 띄워줌
requestPermissions(arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE),1000)
}
}
}
## checkSelfPermission
ContextCompat.checkSelfPermission(this,
android.Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED -> {
// READ_EXTERNAL_STORAGE의 권한이 PERMISSION_GRANTED와 같다면..
//TODO 권한이 잘 부여되었을 때상황, 갤러리에서 사진을 선택하는 코드 구현
navigatePhotos()
}
가장 첫번째로 checkSelfPermission을 실행한다. 인자(READ_EXTERNAL_STORAGE)로 들어온 곳에 권한을 확인하는데 만일 권한이 있다면 PackageManager.PERMISSION_GRANTED을 반환하고 없다면 PackageManager.PERMISSION_DENIED을 반환하게 된다. 즉 PackageManager.PERMISSION_GRANTED 라면 사진첩에 접근할 권한이 있기 때문에 사진첩에 접근하여 사진을 고르는 메서드를 작성하면 된다.
## shouldShowRequestPermissionRationale
shouldShowRequestPermissionRationale(android.Manifest.permission.READ_EXTERNAL_STORAGE) -> {
// 권한을 명시적으로 거부한 경우 true
// 처음보거나, 다시묻지 않음을 선택한 경우 false
//TODO 교육용 팝업 확인 후 권한 팝업을 띄우는 기능
showPermissionContextPopup()
}
두번째 분기점이다. 이곳은 권한이 거부된 경우 만나게 되는 곳이라 생각하면 된다. 반환값은 Boolean으로 true/false를 반환하게 된다.
즉 이 분기점에 오게되면, 결국 다시 권한을 요청하는 것을 물어봐야한다. 그전에 다이얼로그를 띄워서, 설명하고 권한 팝업을 띄우도록 했다. 아래는 연결되는 다이얼로그다.
private fun showPermissionContextPopup() {
AlertDialog.Builder(this)
.setTitle("권한이 필요합니다")
.setMessage("전자액자에서 사진을 선택하려면 권한이 필요합니다.")
.setPositiveButton("동의하기", {_, _ ->
requestPermissions(arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE),1000)
})
.setNegativeButton("취소하기",{ _,_ ->})
.create()
.show()
}
## requestPermissions
권한 요청을 하는 함수이다. 그러나 이 함수만 덜렁 사용하기 보다는 맨처음에 when을 이용해 3곳의 분기점을 만든 것 처럼 두번의 체크를 통해서 통과 하게 되면 requestPermissions을 호출하게 하면 된다.
else -> {
// 처음봤을때 띄워줌
requestPermissions(arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE),1000)
}
// 인자 설명
requestPermissions(arrayOf( " 권한들 " ,"requestCode")
즉 이렇게 else문으로 적게 될 경우, 처음 버튼을 눌른 경우 해당 분기문에 마주하게 된다.
requestPermissions은 인자로 array를 받게 된다. 여러개의 권한을 요청하는 경우가 당연히 생기기 때문인데, 그렇기 때문에 하나의 권한만을 요청하더라도 위처럼 array에 담아서 보내야 한다. 두번째는 requestCode인데 이후 onRequestPermissionsResult에서 결과를 정의하게 되는데 이때 이 reuqestCode를 받아서 사용하게 된다.
## onRequestPermissionsResult
위 그림처럼 권한을 묻는 팝업이 뜨게 되는데 허용/거부의 선택창이 있다. 여기서 허용 또는 거부를 눌렀을때 어떤 실행을 할지 정의하게 하는 함수다. override( 재정의 ) 하여 사용한다.
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when(requestCode){
1000 -> {
if(grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED){
// 권한이 부여 된 것입니다.
// 허용 클릭 시
navigatePhotos()
} else {
// 거부 클릭시
Toast.makeText(this,"권한을 거부했습니다.",Toast.LENGTH_SHORT).show()
}
} else -> {
//Do Nothing
}
}
}
grantResults는 empty가 될 수 없다. grantResults또한 여러개일 수 있다. 왜냐면 여러개의 퍼미션을 요청 할 수 있기 때문이다. 여기서는 한개이기 때문에 이 한개에 대한 권한이 GRANTED인지 확인하고, 맞다면 사진첩에 접근하여 파일을 가져오는 역할을 수행하도록한다.
## 매니페스트에 추가
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
매니페스트에 어떤 권한을 이 앱이 요구하는지에 대해서 적어야한다. 원하는 권한에 맞게 적어주자.
끝이다. ㅎㅎ
처음 이거 볼때는 엄청 헷갈렸던거 같은데, 정리해보면서 깔끔하게 이해 됐다. 근데 함수명같은거는 까먹을거 같다. 당연히 외우고 있을 필요는 없는거니까.. 근데 앱하나 만드는데 진짜 엄청 할게 많을거 같다... 재밌는데 막상 하나 개발하려고하면 빠트리게 되는게 매우 많을거 같다.