๐๐ฉ ๋ฐํ์ ๊ถํ(Runtime Permissions)
์๋๋ก์ด๋ 6.0(API 23) ์ด์์์๋ ๋ฐํ์ ๊ถํ(Runtime Permission) ๋๋ ์ํ ๊ถํ(Dangerous Permission)์ด๋ผ๋ ๊ฐ๋ ์ด ๋์ ๋์์ต๋๋ค.
๐๐ฉ ๋ฐํ์ ๊ถํ์ด๋?
๋ฐํ์ ๊ถํ์ ์ฑ์ด ์ ํ๋ ๋ฐ์ดํฐ์ ์ ๊ทผํ๊ฑฐ๋, ์์คํ
๋ฐ ๋ค๋ฅธ ์ฑ์ ์ํฅ์ ์ค ์ ์๋ ๋์์ ์ํํ ๋ ๋ฐ๋์ ์์ฒญํด์ผ ํ๋ ๊ถํ์
๋๋ค.
์ค์น ์ ์๋์ผ๋ก ๋ถ์ฌ๋์ง ์์ผ๋ฉฐ, ์ฑ ์คํ ์ค ์ค์ ๋ก ํ์ํ ๋ ํ์
๋ค์ด์ผ๋ก๊ทธ๋ก ์์ฒญ๋ฉ๋๋ค.
์ฆ, ๊ฐ๋ฐ์๋ ๊ถํ์ด ์ด๋ฏธ ๋ถ์ฌ๋์ด ์๋ค๊ณ ๊ฐ์ ํด์๋ ์๋๋ฉฐ, ๊ธฐ๋ฅ ์คํ ์ ๋ง๋ค ๊ถํ์ ํ์ธํ๊ณ ํ์ ์ ์์ฒญํด์ผ ํฉ๋๋ค.

๐๐ฉ ์ํ ๊ถํ ์์
๋ฐํ์ ๊ถํ ๋๋ถ๋ถ์ ๋ฏผ๊ฐํ ์ฌ์ฉ์ ๋ฐ์ดํฐ์ ๊ด๋ จ์ด ์์ต๋๋ค.
- ์์น ์ ๋ณด (Location)
- ์ฐ๋ฝ์ฒ (Contacts)
- ๋ง์ดํฌ (Microphone)
- ์นด๋ฉ๋ผ (Camera)
์ด ์ค ํนํ ๋ง์ดํฌ์ ์นด๋ฉ๋ผ๋ ์ฌ์ํ๊ณผ ์ง์ ์ ์ผ๋ก ์ฐ๊ฒฐ๋ ๋งค์ฐ ๋ฏผ๊ฐํ ์ ๋ณด์ ์ ๊ทผํ ์ ์๊ธฐ ๋๋ฌธ์, ์๋๋ก์ด๋๋ ์ฑ์ด ํด๋น ๊ถํ์ ์์ฒญํ ๋ ์ฌ์ฉ์์๊ฒ ๊ถํ์ด ํ์ํ ์ด์ ๋ฅผ ์ค๋ช ํ ์ ์๋๋ก ์ง์ํฉ๋๋ค.
๐๐ฉ ์์คํ ๋ณดํธ ์์ค
์๋๋ก์ด๋๋ ๋ฐํ์ ๊ถํ์ dangerous(์ํ)๋ณดํธ ์์ค์ผ๋ก ๋ถ๋ฅํฉ๋๋ค.
Normal๊ถํ → ์๋ ๋ถ์ฌ (์: ์ธํฐ๋ท ์ ๊ทผ)Dangerous๊ถํ → ๋ฐํ์์ ์ฌ์ฉ์ ๋์ ํ์ (์: ์์น, ์นด๋ฉ๋ผ ๋ฑ)
๐๐ฉ ๊ถํ ์ฒ๋ฆฌ ๊ฐ์ด๋
1. ๊ถํ ์ ์ธ ๋ฐ ํ์ธ
๊ถํ์ ์์ฒญํ๊ธฐ ์ ์ AndroidManifest.xml์ ํด๋น ๊ถํ์ ์ ์ธํด์ผ ํฉ๋๋ค.
<uses-permission android:name="android.permission.CAMERA" />
๋ฐํ์ ์์๋ ์ฌ์ฉ์๊ฐ ์ค์ ๋ก ํด๋น ๊ธฐ๋ฅ์ ์ฌ์ฉํ ๋๋ง ๊ถํ์ ์์ฒญํ๋ ๊ฒ์ด ๋ฐ๋์งํ๋ฉฐ ์์ฒญ ์ ์๋ ๋ฐ๋์ ContextCompat.checkSelfPermission()์ ํตํด ๊ถํ์ด ์ด๋ฏธ ๋ถ์ฌ๋์๋์ง ํ์ธํด์ผ ํฉ๋๋ค.
- ํ์ฉ๋จ → ๊ธฐ๋ฅ ์คํ
- ํ์ฉ๋์ง ์์ → ๊ถํ ์์ฒญ ์งํ
// ๊ถํ ํ์ธ ๋ฐ ์์ฒญ
fun checkAndRequestPermission() {
when {
// ์ด๋ฏธ ๊ถํ ์์
ContextCompat.checkSelfPermission(
this, Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED -> {
startCamera()
}
// ๊ถํ์ด ํ์ํ ์ด์ ์ค๋ช
shouldShowRequestPermissionRationale(Manifest.permission.CAMERA) -> {
showPermissionExplanationDialog {
requestPermissionLauncher.launch(Manifest.permission.CAMERA)
}
}
// ๊ถํ ์์ฒญ
else -> {
requestPermissionLauncher.launch(Manifest.permission.CAMERA)
}
}
}
2. ๊ถํ ์์ฒญํ๊ธฐ
์๋๋ก์ด๋์์ ๊ถ์ฅํ๋ ์ต์ ๋ฐฉ์์ ActivityResultLauncher API ๋ฅผ ํ์ฉํ๋ ๊ฒ์
๋๋ค.
์์คํ
์ด ์๋์ผ๋ก ๊ถํ ๋ค์ด์ผ๋ก๊ทธ๋ฅผ ๋์์ฃผ๊ณ , ์ฌ์ฉ์๋ ํ์ฉ/๊ฑฐ๋ถ๋ฅผ ์ ํํ ์ ์์ต๋๋ค. ๊ฒฐ๊ณผ๋ ์ฝ๋ฐฑ์ผ๋ก ๊ฐ๋จํ ์ฒ๋ฆฌํ ์ ์์ด ์ฝ๋๊ฐ ๊น๋ํด์ง๋๋ค.
// ๊ถํ ์์ฒญ ๋ฐ์ฒ ๋ฑ๋ก
private val requestPermissionLauncher =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean ->
if (isGranted) {
// ๊ถํ ํ์ฉ๋จ → ๊ธฐ๋ฅ ์คํ
} else {
// ๊ถํ ๊ฑฐ๋ถ๋จ → ์ฌ์ฉ์ ์๋ด
}
}
3. ๊ถํ ์์ฒญ ๊ทผ๊ฑฐ ์ ๊ณตํ๊ธฐ
๊ฒฝ์ฐ์ ๋ฐ๋ผ ์์คํ
์ shouldShowRequestPermissionRationale()์ true๋ก ๋ฐํํ ์ ์์ต๋๋ค. ์ด๋๋ ๊ถํ ์์ฒญ ์ , ์ฌ์ฉ์์๊ฒ ํด๋น ๊ธฐ๋ฅ์ ๊ถํ์ด ์ ํ์ํ์ง UI๋ก ์ค๋ช
ํด์ผ ํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ์ฌ์ฉ์๊ฐ ๊ถํ์ ํ์์ฑ์ ์ดํดํ์ฌ ๊ถํ ํ์ฉ ๊ฐ๋ฅ์ฑ์ ๋์ผ ์ ์์ต๋๋ค.
4. ๊ถํ ๊ฑฐ๋ถ ์ฒ๋ฆฌํ๊ธฐ
์ฌ์ฉ์๊ฐ ๊ถํ์ ์ฌ๋ฌ ๋ฒ ๊ฑฐ๋ถํ๋ฉด, ์๋๋ก์ด๋๋ ์ด๋ฅผ ์๊ตฌ ๊ฑฐ๋ถ๋ก ๊ฐ์ฃผํฉ๋๋ค. ์ด ๊ฒฝ์ฐ ์ฑ์ ๋ ์ด์ ๊ถํ ์์ฒญ ๋ค์ด์ผ๋ก๊ทธ๋ฅผ ๋์ธ ์ ์์ผ๋ฉฐ, ์ฑ์ ์ฌ์ฉ์์๊ฒ ๊ธฐ๋ฅ ์ ํ์ ๋ช ํํ ์๋ดํ๊ณ ํ์ํ ๊ฒฝ์ฐ ์์คํ ์ค์ ํ๋ฉด์ผ๋ก ์ด๋ํ๋๋ก ์ ๋ํด์ผ ํฉ๋๋ค.
[์ฑ ์คํ]
โ
โผ
[๊ถํ ์ ์ธ ํ์ธ (Manifest)]
โ
โผ
[๊ถํ ํ์ธ]
โโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ โ
โผ โผ โผ
์ด๋ฏธ ํ์ฉ๋จ ์ค๋ช
ํ์(true) ๊ถํ ์์
(๋ฐ๋ก ์คํ) → ๊ทผ๊ฑฐ ํ์ ํ ์์ฒญ → ๊ถํ ์์ฒญ
โ
โผ
์ฌ์ฉ์ ์๋ต
โโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโ
โ โ โ
โผ โผ โผ
ํ์ฉ๋จ ๊ฑฐ๋ถ๋จ ์๊ตฌ ๊ฑฐ๋ถ๋จ
๊ธฐ๋ฅ ์คํ → ์๋ด ๋ฉ์์ง → ์ค์ ํ๋ฉด ์ ๋
๐ ์ฐธ๊ณ
- Manifest Interview Android
- https://developer.android.com/guide/topics/permissions/overview?hl=ko#runtime
'Android' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [Android] ์๋๋ก์ด๋์์ ์์ธ(Exceptions) ์ถ์ ํ๊ธฐ (0) | 2025.09.17 |
|---|---|
| [Android] ์๋๋ก์ด๋์ Looper, Handler, HandlerThread ์ดํดํ๊ธฐ (0) | 2025.09.17 |
| [Android] SparseArray์ ๋ํ์ฌ (0) | 2025.09.14 |
| [Android] ActivityManager๋? (0) | 2025.09.13 |
| [Android] ํ๋ฉด ํ์ ๊ณผ ๊ฐ์ ๊ตฌ์ฑ ๋ณ๊ฒฝ์ด ๋ฐ์ํ ๋ Activity์ ์๊ธฐ๋ ๋ณํ (0) | 2025.08.31 |