[Android] 권한 요청 예제

이주형·2023년 5월 22일
0

📌 Permission

앱의 특정 기능에 부여하는 접근 권한을 의미한다.

위치 권한을 허용하는 버튼을 눌러서 권한을 요청하는 예제를 만들어보겠습니다.

권한을 요청하는 방법

  1. AndroidManifest.xml 파일에서 위치 권한을 추가합니다. manifest 태그 안에 다음의 코드를 추가한다.
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  1. 사용자가 Permission을 허용했는지 확인하려면 checkSelfPermission() 함수를 이용합니다. 이 함수는 위치 권한이 있는지 확인하고, 없는 경우 권한 요청을 합니다.
private fun checkLocationPermission() {
    if (ActivityCompat.checkSelfPermission(this, ACCESS_FINE_LOCATION)
        != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(
            this, ACCESS_COARSE_LOCATION
        ) != PackageManager.PERMISSION_GRANTED
    ) {
        if (ActivityCompat.shouldShowRequestPermissionRationale(
                this,
                ACCESS_FINE_LOCATION
            )
        ) {
        	// 권한이 없을 경우 권한 요청
            Toast.makeText(this, "앱 실행을 위해서는 권한을 설정해야 합니다.", Toast.LENGTH_SHORT).show()
            ActivityCompat.requestPermissions(
                this,
                arrayOf(
                    ACCESS_FINE_LOCATION,
                    ACCESS_COARSE_LOCATION
                ),
                LOCATION_PERMISSION_REQUEST_CODE
            )
        } else {
        	// 권한이 이미 있는 경우에 대한 처리
            ActivityCompat.requestPermissions(
                this,
                arrayOf(
                    ACCESS_FINE_LOCATION,
                    ACCESS_COARSE_LOCATION
                ), LOCATION_PERMISSION_REQUEST_CODE
            )
        }
    }
}
  1. onRequestPermissionsResult() 함수는 권한 요청 결과를 처리합니다.
override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<String>,
    grantResults: IntArray
) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)
    when (requestCode) {
        LOCATION_PERMISSION_REQUEST_CODE -> {
            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 위치 권한이 허용된 경우에 대한 처리
                Toast.makeText(this, "앱 실행을 위한 권한이 설정 되었습니다", Toast.LENGTH_SHORT).show()
            } else {
                // 위치 권한이 거부된 경우에 대한 처리
                showPermissionDeniedDialog()
                Toast.makeText(this, "앱 실행을 위한 권한이 취소 되었습니다", Toast.LENGTH_SHORT).show()
            }
            return
        }
    }
}

이렇게 해서 버튼을 누르게 되면 아래 그림과 같은 화면이 뜨게 된다.

이 화면에서 허용을 해주면 권한을 이용할 수 있게 되지만 허용하지 않으면 권한이 거부된다. 그럼 다시 버튼을 누르면 되지 않냐고?
안된다. 사용자가 권한 요청 대화 상자에서 권한을 거부한 경우, 앱 내에서 다시 권한을 요청할 수는 없다. 사용자가 권한을 거부한 후에는 앱 설정에서 직접 권한을 변경해야 한다.

❓ 사용자가 권한 요청 대화 상자에서 권한을 거부한 경우, 앱 내에서 다시 권한을 요청할 수는 없는 이유 ❓

시스템의 권한 관리 정책 때문이라고 한다.
권한 요청 대화 상자는 시스템 레벨에서 관리되며, 사용자가 권한을 거부하면 해당 앱은 동일한 권한을 다시 요청할 수 없다. 이는 사용자의 개인 정보 보호 및 보안을 위한 메커니즘이다.

그래서 일반적으로 사용자가 권한을 거부한 경우, 아래와 같은 절차를 따르는 것이 좋다.

  1. 사용자에게 권한이 필요한 이유를 명확하게 안내한다. 앱에서 어떤 기능을 사용하기 위해 위치 권한이 필요한지 사용자에게 이해시켜준다.

  2. 사용자에게 앱 설정으로 이동하여 권한을 변경할 수 있는 안내를 제공한다. 예를 들어, 다이얼로그나 토스트 메시지를 통해 "권한이 거부되었습니다. 앱 설정에서 위치 권한을 활성화해주세요."와 같은 안내 메시지를 보여줄 수 있다.

  3. 사용자가 앱 설정으로 이동할 수 있도록 도움을 제공한다. 예를 들어, 다이얼로그에 '설정으로 이동' 버튼을 추가하여 클릭하면 앱 설정 화면으로 이동하도록 할 수 있다.

private fun showAppSettingsDialog() {
    val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
    val uri = Uri.fromParts("package", packageName, null)
    intent.data = uri
    startActivity(intent)
}

private fun showPermissionDeniedDialog() {
    val alertDialogBuilder = AlertDialog.Builder(this)
    alertDialogBuilder.apply {
        setTitle("권한 거부")
        setMessage("앱 설정으로 이동하여 위치 권한을 활성화해주세요.")
        setPositiveButton("설정으로 이동") { _, _ ->
            showAppSettingsDialog()
        }
        setNegativeButton("취소") { dialog, _ ->
            dialog.dismiss()
        }
    }
    val dialog = alertDialogBuilder.create()
    dialog.show()
}

위의 코드에서

  • showAppSettingsDialog() 함수는 앱 설정 화면으로 이동하기 위한 인텐트를 생성하고 실행한다.
  • showPermissionDeniedDialog() 함수는 권한 거부 다이얼로그를 보여주고, '설정으로 이동' 버튼을 클릭하면 showAppSettingsDialog() 함수를 호출하여 앱 설정 화면으로 이동한다.

위에 권한 요청 결과를 처리하는 onRequestPermissionsResult() 함수를 잘 보면 위치 권한이 거부된 경우에 showPermissionDeniedDialog() 함수를 호출한 것을 볼 수 있다.

위 코드를 종합하여 실행해보면

이렇게 잘 나오는걸 볼 수 있다.

📌 Compose에서 카메라 권한 예시

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            Prat2Theme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    CameraPermissionExample()
                }
            }
        }
    }
}

@Composable
fun CameraPermissionExample() {
    val context = LocalContext.current
    var hasPermission by remember {
        mutableStateOf(
            ContextCompat.checkSelfPermission(
                context,
                android.Manifest.permission.CAMERA
            ) == PackageManager.PERMISSION_GRANTED
        )
    }

    val launcher = rememberLauncherForActivityResult(
        contract = ActivityResultContracts.RequestPermission(),
        onResult = { isGranted ->
            hasPermission = isGranted
        }
    )

    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        if (hasPermission) {
            Text("카메라 권한이 허용되었습니다.")
        } else {
            Text("카메라 권한이 필요합니다.")
            Spacer(modifier = Modifier.height(16.dp))
            Button(onClick = {
                launcher.launch(android.Manifest.permission.CAMERA)
            }) {
                Text("카메라 권한 요청")
            }
        }
    }
}

0개의 댓글