Android ๊ถํ Overview
์ ๊ถํ์ด ํ์ํ๊ฐ?
๋ชจ๋ Android ์ฑ์ ์ก์ธ์ค๊ฐ ์ ํ๋ ์๋๋ฐ์ค์์ ์คํ๋๋ค.
๋ฐ๋ผ์ ์ฑ์ด ์์ ์ ์๋๋ฐ์ค ์ธ๋ถ์ ๋ฆฌ์์ค๋ ์ ๋ณด๋ฅผ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ์ก์ธ์ค ๊ถํ์ ์์ฒญํ๊ฒ ํจ์ผ๋ก์จ ์์คํ ๋ณด์ ๊ธฐ๋ฅ์ ์ ์งํ๋ฉฐ ๊ฐ์ธ์ ๋ณด ๋ณดํธ์ ๋์์ ์ค ์ ์๋ค.
์๋๋ก์ด๋ ๊ถํ ์์ฒญ workflow
๊ถํ ์ข ๋ฅ
- ์ค์น ์๊ฐ ๊ถํ(Install-time Permission)
- ์์คํ ์ด ์ฌ์ฉ์๊ฐ ์ฑ์ ์ค์นํ ๋ ์๋์ผ๋ก ์ฑ์ ๊ถํ์ ๋ถ์ฌ
- ์ฑ ์คํ ์ด ์ธ๋ถ ์ ๋ณด์ ์ ๊ทผ ๊ถํ ํ๊ธฐ๋จ
- mainfest์ ์ ์ธ๋ง ํ๋ฉด ์ธ ์ ์๋ ๊ถํ
- ์ผ๋ฐ๊ถํ๊ณผ ์๋ช
๊ถํ ๋ฑ์ผ๋ก ๊ตฌ๋ถ๋จ
- ์ผ๋ฐ๊ถํ(Normal Permission)
- ์ฑ์ ์๋๋ฐ์ค ์ด์์ผ๋ก ํ์ฅ๋ ๋ฐ์ดํฐ์ ์์ ์ ์ก์ธ์ค
- ์ฌ์ฉ์์ ๊ฐ์ธ์ ๋ณด์ ๋ค๋ฅธ ์ฑ ์์ ์๋ ๊ฑฐ์ ์ํฅ์ ์ฃผ์ง ์์
- ์๋ฅผ ๋ค์ด ์ธํฐ๋ท ๊ถํ(INTERNET)์ด๋, ์ง๋ ๊ถํ(VIVRATE) ๋ฑ
protectionLevel="normal"
- ์๋ช
๊ถํ(Signiture Permission)
- ๊ถํ ์ ์ํ๋ ์ฑ์ด๋ OS์ ๋์ผ ์ธ์ฆ์๋ก ์ฑ์ด ์๋ช ๋ ๊ฒฝ์ฐ์๋ง ์ฑ์ ์๋ช ๊ถํ์ ๋ถ์ฌ
- ๊ทธ๋ฌ๋๊น ์ด๋ค ๋ค๋ฅธ ์ดํ๋ฆฌ์ผ์ด์ ์ ์๋ ๊ธฐ๋ฅ์ ํ์ฉํ๋ ๊ฒฝ์ฐ ๋ค๋ฅธ ์ดํ๋ฆฌ์ผ์ด์ ๊ณผ ๋์ผํ keystore๋ก ์ธ์ฆ๋์ด์ผ๋ง ์ฌ์ฉํ ์ ์๋ ๊ถํ
- ์๋ฅผ ๋ค์ด ์๋์์ฑ, VPN์๋น์ค ๋ฑ
protectionLevel"signiture"
- ์ผ๋ฐ๊ถํ(Normal Permission)
- ๋ฐํ์ ๊ถํ(์ํ ๊ถํ)(Runtime Permission)
- ์ฑ์์ ์ ํ๋ ๋ฐ์ดํฐ์ ์ก์ธ์คํ๊ฑฐ๋ ๋ค๋ฅธ ์ฑ์ ์ํฅ์ ๋ฏธ์น๋ ์์ ์ ๋ํ ๊ถํ.
- ๊ด๋ จ ๊ธฐ๋ฅ์ ์ก์ธ์ค ํ ๋๋ง๋ค ๊ถํ์ด ๋ถ์ฌ๋์๋์ง ํ์ธํด์ผ ํจ.
- ์๋ฅผ ๋ค์ด ๋ง์ดํฌ,์นด๋ฉ๋ผ
protectionLevel="danger"
- ํน๋ณ ๊ถํ
- ํน์ ์ฑ ์์ ์ ๊ดํ ๊ถํ
- ํ๋ซํผ, OEM๋ง ์ ์ ๊ฐ๋ฅ
- ์๋ฅผ ๋ค์ด ๋ค๋ฅธ ์ฑ ์์ ๊ทธ๋ฆฌ๊ธฐ ๊ฐ์ ์์ ๊ถํ
protectionLevel="appop"
๊ถํ ๊ทธ๋ฃน
- ๋ ผ๋ฆฌ์ ์ผ๋ก ๊ด๋ จ์ฑ ์๋ ๊ถํ์ ์งํฉ
- ๊ถํ ๊ทธ๋ฃน์ ๋ณ๊ฒฝ๋ ์ ์์ผ๋ฏ๋ก ์ฃผ์
๋ฐํ์ ๊ถํ ๊ธฐ๋ณธ ์์น
- ์ฌ์ฉ์ ๊ถํ์ด ํ์ํ ๊ธฐ๋ฅ๊ณผ ์ํธ์์ฉ ์์ ์ ๊ถํ ์์ฒญ
- ์ฌ์ฉ์ ์ฐจ๋จํ์ง ์๊ธฐ
- ์ฌ์ฉ์๊ฐ ๊ถํ์ ๊ฑฐ๋ถํ๋ฉด ์ฑ ์ฑ๋ฅ์ ๋จ๊ณ์ ์ผ๋ก ์ ํ ์์ผ ์ฑ์ ๊ณ์ ์ฌ์ฉํ ์ ์๊ฒ ํ๊ธฐ
- ์์คํ ๋์์ ๊ฐ์ ํ์ง ์๊ธฐ
๊ถ์ฅ ์ฌํญ
- ๊ผญ ํ์ํ ๊ถํ๋ง ์ต์๋ก ์์ฒญํ๊ธฐ
- ๋ฐํ์ ๊ถํ์ ๋ฏธ๋ฆฌ ์์ฒญํ์ง ๋ง๊ณ ํ์ํ ๋ ์ต๋ํ ๋ฆ๊ฒ ์์ฒญํ๊ธฐ
- ๋ผ์ด๋ธ๋ฌ๋ฆฌ ํฌํจ ์ ํด๋น ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ฌ์ฉํ๋ ๊ถํ๋ ๋ธ๋ ค์ค๋ฏ๋ก ์ฃผ์
- ๊ถํ ์์ฒญ์ ๋ชจ๋ ํ๋ก์ฐ์์ ์ฌ์ฉ์๊ฐ ์ถฉ๋ถํ ์ ๋ณด๋ฅผ ๋ฐํ์ผ๋ก ๊ฒฐ์ ์ ๋ด๋ฆด ์ ์๋๋ก ํด์ผ ํจ.(ํฌ๋ช ์ฑ ํ๋ณด)
- ๋ฏผ๊ฐํ ์ ๋ณด๋ ํ๋์จ์ด์ ์ก์ธ์ค ํ ๋ ์์คํ ์์ ์ด๋ฐ ๊ฒ๋ค์ ํ์ํ์ง ์๋๋ค๋ฉด ์ฑ์ ์ง์์ ์ผ๋ก ์๋ฆผ์ ํ์ํด์ผ ํจ. (์๋ฅผ ๋ค์ด ์นด๋ฉ๋ผ ์ฐ๋ฉด ๋์ค๋ ์ด๋ก ์ ๊ฐ์ ๊ฒ ์์ผ๋ฉด ์๋ฆผ์ ์ง์ ๋ณด๋ด์ผ ํ๋ค๋ ์๋ฏธ)
์ฑ ๊ถํ ์ ์ธ
- manifest.xml ํ์ผ์
<uses-permission>
์ ํ์ฉํด ๊ถํ์ ์ ์ธ
<manifest ...>
<uses-permission android:name="android.permission.CAMERA"/>
<application ...>
...
</application>
</manifest>
ํ๋์จ์ด ์ ํ ์ฌํญ์ผ๋ก ์ค์
ํ๋์จ์ด๊ฐ ํ์๊ฐ ์๋๋ผ๋ฉด ์๋ ์ฝ๋์ ๊ฐ์ด ํ๊ธฐํด์ผ ํ๋ค.
๊ทธ๋ ์ง ์์ผ๋ฉด ํด๋น ํ๋์จ์ด๊ฐ ์๋ ๊ธฐ๊ธฐ์์ ์ฑ์ ์ค์นํ์ง ๋ชปํ๊ฒ ํ๋ค.
<manifest ...>
<uses-permission android:name="android.permission.CAMERA"/>
<application>
...
</application>
<uses-feature android:name="android.hardware.camera"
android:required="false" />
<manifest>
์ด ๊ฒฝ์ฐ์๋ ์นด๋ฉ๋ผ์ ์ ๋ฌด์ ๋ฐ๋ฅธ ํ๋ก์ฐ๊ฐ ๋ฌ๋ผ์ ธ์ผ ํ๋ฏ๋ก ์๋์ ๊ฐ์ด ์ฝ๋๋ด์์ ๋ถ๊ธฐ์ฒ๋ฆฌ๋ฅผ ํด์ค๋ค.
if(applicationContext.packageManager.hasSystemFeature(
PackageManager.FEATURE_CAMERA_FRONT)){
//์นด๋ฉ๋ผ๊ฐ ์๋๊ฒฝ์ฐ
}else{
//์นด๋ฉ๋ผ ์๋ ๊ฒฝ์ฐ
}
API ์์ค๋ณ ๊ถํ ์ ์ธ
์๋๋ก์ด๋ 6.0 (API์์ค 23) ์ด์์ ์คํํ๋ ๊ธฐ๊ธฐ์์๋ง ๊ถํ์ ์ ์ธํ๋ ค๋ฉด <uses-permssion-sdk-23>
์ด๊ฑธ๋ก ๊ถํ์ ์ ์ธํ๋ค.
ํน์ maxSdkVersion
์ ํ์ฉํ์ฌ ์ง์ ๋ ๊ฐ๋ณด๋ค ๋์ ๋ฒ์ ์ ์คํํ๋ ๊ธฐ๊ธฐ์์ ํด๋น ๊ถํ์ ์์ฒญํ์ง ์์ ์ ์๋ค.
<uses-permission-sdk-23 android:name="..."/>
<uses-permission android:name="..."
android:maxSdkVersion="29"/>
๋ฐํ์ ๊ถํ ์์ฒญ
๋ฐํ์ ๊ถํ ์์ฒญ workflow
๊ถํ์ด ์ด๋ฏธ ๋ถ์ฌ ๋์๋์ง ํ์ธ
ContextCompat.checkSelfPermission()
์ ๊ถํ ์ ๋ฌ- ๊ถํ์ด ์๋ค๋ฉด PERMISSION_GRANTED๋ฐํ
- ์๋ค๋ฉด PERMISSION_DENIED๋ฐํ
์ฑ์ ๊ถํ์ด ํ์ํ ์ด์ ์ค๋ช
shouldShowReuqestPermissionRationale()
ํธ์ถ- ์ฌ์ฉ์๊ฐ ์์ฒญ์ ๋ช ์์ ์ผ๋ก ๊ฑฐ๋ถํ ๊ฒฝ์ฐ true๋ฅผ ๋ฐํ, ์ด ๊ฒฝ์ฐ ์ ์ด ๊ถํ์ด ํ์ํ์ง ์ฌ์ฉ์์๊ฒ ์ค๋ช
- ์ฌ์ฉ์๊ฐ ๊ถํ ์์ฒญ์ ์ฒ์ ๋ณด๊ฑฐ๋, ๋ค์ ๋ฌป์ง ์์์ ์ ํํ ๊ฒฝ์ฐ, ๊ถํ์ ํ์ฉํ ๊ฒฝ์ฐ false๋ฅผ ๋ฐํ
๊ถํ ์์ฒญ
- AndroidX๋ผ์ด๋ธ๋ฌ๋ฆฌ
RequestPermission
Contract์ฌ์ฉ
val requestPermissionLauncher=registerForActivityResult(RequestPermission()){isGranted:Boolean->
if(isGranted){
//๊ถํ์ด ๋ถ์ฌ๋์์๋ ํ๋ก์ฐ
}else{
//๊ถํ์ด ๊ฑฐ๋ถ๋์์๋ ํ๋ก์ฐ
}
}
//๊ถํ ์์ฒญ ํ์์
requestPermissionLauncher.launch()
- ๊ถํ ๊ทธ๋ฃน์ธ ๊ฒฝ์ฐ
RequestMultiplePermissions
์ฌ์ฉ - ๊ถํ ๊ด๋ จ๋ ์์คํ ๋ค์ด์ผ๋ก๊ทธ๋ ์ปค์คํ ๋ถ๊ฐ๋ฅ์ด๋ฏ๋ก ์ถ๊ฐ์ ์ธ ์ ๋ณด ๋ฑ์ด ํ์ํ๋ฉด ์ฑ UI๋ฅผ ์์
๐จย ์ฐธ๊ณ ๋ก ActivityResultLauncher
์ ๊ฒฝ์ฐ STARTED์ด์ ์ ํธ์ถ ๋์ด์ผํ๋ค. ์๋๋ฉด ์๋์ ๊ฐ์ด ์๋ฌ๊ฐ ๋์จ๋ค. ์๋ฅผ ๋ค์ด setContent
๋ด๋ถ์ UI์ฝ๋๋ onResume์์๋ ์ฌ๋ฌ๋ฒ ํธ์ถ ๋ ์ ์์ผ๋ฏ๋ก ๊ฑฐ๊ธฐ์๋ ์ฐ๋ฉด ์๋๋ค.
java.lang.IllegalStateException: LifecycleOwner kr.co.gogumac.playgroundforandroid.MainActivity@3474afb is attempting to register while current state is RESUMED. LifecycleOwners must call register before they are STARTED.
๋ฐํ์ ๊ถํ ์์ฒญ ์์ ์ฝ๋
val requestPermissionLauncher=registerForActivityResult(ActivityResultContracts.RequestPermission()){isGranted:Boolean->
if(isGranted){
//๊ถํ์ด ๋ถ์ฌ๋์์๋ ํ๋ก์ฐ
}else{
//๊ถํ์ด ๊ฑฐ๋ถ๋์์๋ ํ๋ก์ฐ
}
}
//...
when{
ContextCompat.checkSelfPermission(context,Manifest.permission.CAMERA)==PackageManager.PERMISSION_GRANTED->{
//๊ถํ์ด ์ด๋ฏธ ๋ถ์ฌ๋ ๊ฒฝ์ฐ
}
ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.CAMERA)->{
//๊ถํ์ด ๋ถ์ฌ๋์ง ์์๊ณ , ์ฌ์ฉ์๊ฐ ๋ช
์์ ์ผ๋ก ๊ฑฐ๋ถ ๋ฒํผ์ ๋๋ฅธ๊ฒฝ์ฐ
//์ด ๊ฒฝ์ฐ ํด๋น ๊ถํ์ ๋ํด ์ค๋ช
ํด์ผํจ
showInContextUI()
}
else->{
//์ฌ์ฉ์๊ฐ ๊ถํ ์์ฒญ์ ์ฒ์ ์ ํ๊ฑฐ๋, ๋ค์ ๋ฌป์ง ์์์ ์ ํํ ๊ฒฝ์ฐ
requestPermissionLauncher.launch(Manifest.permission.CAMERA)
}
}
request code๋ฅผ ์ฌ์ฉํ ๊ถํ ์์ฒญ
- ์ ์์์์๋ ์์คํ ์ด request code๋ฅผ ๊ด๋ฆฌํจ, ์ฌ๊ธฐ์๋ ์ง์ ๊ด๋ฆฌ
requestPermissions()
์ฌ์ฉ
when{
ContextCompat.checkSelfPermission(context,Manifest.permission.CAMERA)==PackageManager.PERMISSION_GRANTED->{
//๊ถํ์ด ์ด๋ฏธ ๋ถ์ฌ๋ ๊ฒฝ์ฐ
}
ActivityCompat.shouldShowRequestPermissionRationale(this,Manifest.permission.CAMERA)->{
//๊ถํ์ด ๋ถ์ฌ๋์ง ์์๊ณ , ์ฌ์ฉ์๊ฐ ๋ช
์์ ์ผ๋ก ๊ฑฐ๋ถ ๋ฒํผ์ ๋๋ฅธ๊ฒฝ์ฐ
//์ด ๊ฒฝ์ฐ ํด๋น ๊ถํ์ ๋ํด ์ค๋ช
ํด์ผํจ
showInContextUI()
}
else->{
//์ฌ์ฉ์๊ฐ ๊ถํ ์์ฒญ์ ์ฒ์ ์ ํ๊ฑฐ๋, ๋ค์ ๋ฌป์ง ์์์ ์ ํํ ๊ฒฝ์ฐ
requestPermission(context,arrayOf(Manifest.permission.CAMERA,999) //requestCode=999
}
}
//์์ฒญ ๊ฒฐ๊ณผ ๋ฐ์๋
override fun on RequestPermissionResult(requestCode:Int,permissions:Array<String>,grantResults:IntArray){
when(requestCode){
999->{
if((grantResult.isNotEmpty())&&grantResult[0]==PackageManager.PERMISSION_GRANTED)){
//๊ถํ ํ์ฉ๋ ๊ฒฝ์ฐ
}else{
//์ ์ ์๊ฒ ๊ถํ ๊ฑฐ๋ถ๋ก ์ธํด ํด๋น ๊ธฐ๋ฅ์ ์ฌ์ฉํ์ง ๋ชปํ๋ค๊ณ ์ค๋ช
.
//์ ์ ์ ๊ฒฐ์ ์ ์กด์คํ์ฌ ์์คํ
์ธํ
์ผ๋ก ์ ์ ๋ฅผ ์ด๋์์ผ์ ์ ์ ๊ฒฐ์ ์ ๋ฐ๊พธ๋ ค๋ ๋
ธ๋ ฅ์ ํ์ง ์์์ผํจ.
}
}
}
}
- ์์ฒญ ์คํจ ์ ๋น ๋ฐฐ์ด์ด ๋ค์ด์จ๋ค.
๊ถํ ๊ฑฐ๋ถ ์ฒ๋ฆฌ
- ํด๋น ๊ถํ์ด ์์ด์ ์ ํ ๋ ์ฑ UIํน์ ๋ถ๋ถ์ ๊ฐ์กฐ
- ์์ธํ ์ค๋ช
- ์ฌ์ฉ์ ์ธํฐํ์ด์ค ์ฐจ๋จํ์ง ์๊ธฐ ex) ์ ์ฒด ํ๋ฉด ๊ฒฝ๊ณ ๋ฉ์์ง X
- ์ฌ์ฉ์๊ฐ ํน์ ๊ถํ์ ๊ดํด ๊ฑฐ๋ถ๋ฅผ ๋๋ฒ์ด์ ์ ํํ๋ฉด ์ดํ ํด๋น ๊ถํ์ ์์ฒญํ ๋ ์์คํ ๋ค์ด์ผ๋ก๊ทธ๊ฐ ๋ํ๋์ง ์์.
- ์ด๋ฐ ์ด์ ๋ก ๊ผญ ํ์ํ ๋๋ง ๊ถํ์ ์์ฒญํ๋ ๊ฒ์ด ์ค์ํ ๊ฒ
์ผํ์ฑ ๊ถํ
- โ์ด๋ฒ๋ง ํ์ฉโ ๋๋ฅด๋ฉด ํด๋น ์กํฐ๋นํฐ๊ฐ ํ์๋๋ ๋์๋ง ์์์ฑ ๊ถํ์ด ๋ถ์ฌ๋จ.
- ์ฌ์ฉ์๊ฐ ์ฑ์ ๋ฐฑ๊ทธ๋ผ์ด๋๋ก ๋ณด๋ด๋ฉด ์งง์ ์๊ฐ๋์ ๋ฐ์ดํฐ์ ๊ณ์ ์ก์ธ์ค ๊ฐ๋ฅ
- ํฌ๊ทธ์ด๋ ์๋น์ค๊ฐ ์คํ๋๊ณ ์๋ค๋ฉด ํด๋น ์๋น์ค๊ฐ ์ค์ง๋ ๋๊น์ง ๊ณ์ ์ก์ธ์ค ๊ฐ๋ฅ
- ์ฌ์ฉ์๊ฐ ์์คํ ์ค์ ๋ฑ์์ ๊ถํ์ ์ทจ์ํ๋ฉด ์ด๋ฌํ ๋ชจ๋ ์์ ์ ์ค์ง๋๊ณ ์ฑ ํ๋ก์ธ์ค๊ฐ ์ข ๋ฃ๋จ
์ฌ์ฉํ์ง ์๋ ๊ถํ ์ฌ์ค์
์ฌ์ฉํ์ง ์๋ ๊ถํ ์ญ์
- Android 13(API 33) ์ด์์์๋ ๋ฐํ์ ๊ถํ์ด ๋์ด์ ํ์์๋ค๋ฉด ํด๋น ๊ถํ์ ์ญ์ ํ ์ ์์
- ์ด ๊ฒฝ์ฐ
revokeSelfPermissionOnKill()
,revokeSelfPermissionsOnKill()
์ฌ์ฉ - ๊ถํ ๊ทธ๋ฃน ์ญ์ ์ ๋ด๋ถ์ ๋ชจ๋ ๊ถํ์ ๋ํด ์ญ์ ํด์ผํจ
์ฌ์ฉํ์ง ์๋ ๊ถํ ์๋ ์ฌ์ค์
- Android 11(API 30) ์ด์์์๋ ๋ช๊ฐ์๊ฐ ์ฌ์ฉ๋์ง ์๋ ๋ฐํ์ ๊ถํ์ ์์คํ ์ด ์๋์ผ๋ก ์ฌ์ค์ ํ๊ฒ ๋์ด์์.
ํ ์คํธ ๋ชฉ์ ์ผ๋ก ๋ชจ๋ ๋ฐํ์ ๊ถํ ๋ถ์ฌ
adb shell install -g PATH_TO_APK_FILE
์ฐธ๊ณ
Android์์์ ๊ถํ ย |ย Android Developers
Android ๋ณด์ ๊ธฐ๋ฅ ย |ย Android ์คํ์์ค ํ๋ก์ ํธ ย |ย Android Open Source Project
๋๊ธ๋จ๊ธฐ๊ธฐ