안드로이드 개발자의 창고
[33일차 Android] Permission 본문
출처 : 안드로이드 앱스쿨 2기 윤재성 강사님 수업 PPT
📖 Permission
- 앱의 특정 기능에 부여하는 접근 권한
- 개인 정보와 관련된 기능을 사용하기 위해서는 권한을 등록해야 한다.
- 권한 등록의 목적은 사용자에게 애플리케이션이 어떠한 기능을 사용하는지 알려주는 목적으로 사용
- 모든 권한에 대해서 한번에 요청하고자 한다면 requestPermissions을 사용
- 권한 확인 후에 처리가 필요하다면 onRequestPermissionsResult 메서드를 overriding하고 권한 별로 분기하여 처리
- 만약 권한 요청 후 필요한 처리를 권한 별로 나눠서 구현하고 싶다면 ActivityResultCallback을 사용
예제 코드
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
tools:context=".MainActivity" >
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="권한 확인하기" />
<Button
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="위치 권한 확인" />
<Button
android:id="@+id/button3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="연락처 권한 확인" />
<Button
android:id="@+id/button4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="저장소 권한 확인" />
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
</LinearLayout>
</ScrollView>
</LinearLayout>
MainActivity.kt
class MainActivity : AppCompatActivity() {
lateinit var activityMainBinding: ActivityMainBinding
// 확인 받을 권한 목록
val permissionList = arrayOf(
Manifest.permission.INTERNET,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.READ_CONTACTS,
Manifest.permission.WRITE_CONTACTS,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
activityMainBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(activityMainBinding.root)
// 위치 정보 권한 확인을 위한 객체들을 생성
val r1 = ActivityResultContracts.RequestMultiplePermissions()
val callback1 = LocationPermissionCallback()
val locationLauncher = registerForActivityResult(r1, callback1)
val r2 = ActivityResultContracts.RequestMultiplePermissions()
val callback2 = ContractPermissionCallback()
val contactLauncher = registerForActivityResult(r2, callback2)
activityMainBinding.run {
button.run {
setOnClickListener {
// 권한 확인 요청
requestPermissions(permissionList, 0)
}
}
button2.run {
setOnClickListener {
// 권한 요청
val a1 = arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
locationLauncher.launch(a1)
}
}
button3.run {
setOnClickListener {
val a1 = arrayOf(
Manifest.permission.READ_CONTACTS,
Manifest.permission.WRITE_CONTACTS
)
contactLauncher.launch(a1)
}
}
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>, // 권한 이름들
grantResults: IntArray // 허용 여부 값
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
activityMainBinding.run{
textView.text = ""
for(idx in 0 until permissions.size){
// 현재 번째의 권한 이름을 가져온다.
val p1 = permissions[idx]
// 권한 허용 여부 값을 가져온다.
val g1 = grantResults[idx]
when(p1){
Manifest.permission.ACCESS_FINE_LOCATION -> {
if(g1 == PackageManager.PERMISSION_GRANTED){
textView.append("위치 1 : 허용\n")
} else {
textView.append("위치 1 : 거부\n")
}
}
Manifest.permission.ACCESS_COARSE_LOCATION -> {
if(g1 == PackageManager.PERMISSION_GRANTED){
textView.append("위치 2 : 허용\n")
} else {
textView.append("위치 2 : 거부\n")
}
}
Manifest.permission.READ_CONTACTS ->{
if(g1 == PackageManager.PERMISSION_GRANTED) {
textView.append("연락처 1 : 허용\n")
} else {
textView.append("연락처 1 : 거부\n")
}
}
Manifest.permission.WRITE_CONTACTS ->{
if(g1 == PackageManager.PERMISSION_GRANTED){
textView.append("연락처 2 : 허용\n")
} else {
textView.append("연락처 2 : 거부\n")
}
}
Manifest.permission.READ_EXTERNAL_STORAGE -> {
if(g1 == PackageManager.PERMISSION_GRANTED){
textView.append("저장소 1 : 허용\n")
} else {
textView.append("저장소 1 : 거부\n")
}
}
Manifest.permission.WRITE_EXTERNAL_STORAGE ->{
if(g1 == PackageManager.PERMISSION_GRANTED){
textView.append("저장소 2 : 허용\n")
} else {
textView.append("저장소 2 : 거용\n")
}
}
Manifest.permission.INTERNET ->{
if(g1 == PackageManager.PERMISSION_GRANTED){
textView.append("네트워크 : 허용\n")
} else {
textView.append("네트워크 : 거부\n")
}
}
}
}
}
}
inner class LocationPermissionCallback : ActivityResultCallback<Map<String, Boolean>>{
override fun onActivityResult(result: Map<String, Boolean>?) {
activityMainBinding.run{
textView.text = "위치 권한 확인\n"
if(result != null) {
// 확인한 권한 만큼 반복한다.
for (key in result.keys) {
// 권한 만큼 반복한다.
when(key) {
Manifest.permission.ACCESS_FINE_LOCATION -> {
if (result[key] == true) {
textView.append("위치1 권한 허용\n")
} else {
textView.append("위치1 권한 거부\n")
}
}
Manifest.permission.ACCESS_COARSE_LOCATION ->{
if(result[key] == true){
textView.append("위치2 권한 허용\n")
} else {
textView.append("위치2 권한 거부\n")
}
}
}
}
}
}
}
}
inner class ContractPermissionCallback : ActivityResultCallback<Map<String, Boolean>>{
override fun onActivityResult(result: Map<String, Boolean>?) {
activityMainBinding.run {
textView.text = "연락처 권한 확인\n"
if (result != null){
for (permission in result.keys){
when(permission){
Manifest.permission.READ_CONTACTS -> {
if(result[permission] == true){
textView.append("연락처1 권한 허용1\n")
} else {
textView.append("연락처1 권한 거부\n")
}
}
Manifest.permission.WRITE_CONTACTS -> {
if(result[permission] == true){
textView.append("연락처2 권한 허용\n")
} else {
textView.append("연락처2 권한 거부\n")
}
}
}
}
}
}
}
}
}
코드 리뷰
button.run {
setOnClickListener {
// 권한 확인 요청
requestPermissions(permissionList, 0)
}
}
- requestPermissions을 사용하여 권한 확인을 요청한다.
- 확인이 필요한 권한 중에서 허용되지 않은 권한에 대해 물어본다.
- 확인이 필요하지 않은 권한은 건너뛴다.
button2.run {
setOnClickListener {
// 권한 요청
val a1 = arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
)
locationLauncher.launch(a1)
}
}
- 위치 정보에 대한 권한을 요청한다.
- ACCESS_FINE_LOCATION : 앱이 정확한 위치에 액세스
- ACCESS_COARSE_LOCATION : 앱이 대략적인 위치에 액세스
button3.run {
setOnClickListener {
val a1 = arrayOf(
Manifest.permission.READ_CONTACTS,
Manifest.permission.WRITE_CONTACTS
)
contactLauncher.launch(a1)
}
}
- 연락처에 대한 권한을 요청한다.
- Manifest.permission.READ_CONTACTS : 앱이 연락처 데이터를 읽을 수 있도록 한다.
- Manifest.permission.WRITE_CONTACTS : 앱이 연락처 데이터를 작성할 수 있도록 한다.
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>, // 권한 이름들
grantResults: IntArray // 허용 여부 값
) { ... }
- requestPermission 메서드를 통해 권한을 요청하여 요청 작업이 끝나면 자동으로 호출되는 메서드
inner class LocationPermissionCallback : ActivityResultCallback<Map<String, Boolean>>{
...
}
- 권한 요청 후 필요한 처리를 권한 별로 나눠서 구현하기 위한 inner class
- Map에는 권한의 이름, 권한 허용 여부 값을 들어온다.
'Computer > Android' 카테고리의 다른 글
[34일차 Android] Context Menu (1) | 2023.06.17 |
---|---|
[34일차 Android] Option Menu (0) | 2023.06.17 |
[32일차 Android] RecyclerView (0) | 2023.06.16 |
[32일차 Android] Spinner (0) | 2023.06.16 |
[32일차 Android] ListView - CustomAdapter (0) | 2023.06.15 |