[Android] Permission ์ •๋ฆฌ

Minjun Kimยท2023๋…„ 9์›” 3์ผ
0

Android

๋ชฉ๋ก ๋ณด๊ธฐ
31/47
post-thumbnail

๐Ÿ“ SeSAC์˜ 'JetPack๊ณผ Kotlin์„ ํ™œ์šฉํ•œ Android App ๊ฐœ๋ฐœ' ๊ฐ•์ขŒ๋ฅผ ์ •๋ฆฌํ•œ ๊ธ€ ์ž…๋‹ˆ๋‹ค.


๐Ÿ“‡ Permission ๊ฐœ๋…

B์˜ ์•ฑ์—์„œ A ์•ฑ์˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‹คํ–‰์‹œํ‚ฌ ์ˆ˜ ์žˆ๊ฒŒ๋” ํ•˜๊ณ ๋Š” ์‹ถ์€๋ฐ ๋ณด์•ˆ์„ ๊ฑธ๊ณ  ์‹ถ์„ ๋•Œ, ์ด๋Ÿฐ ๊ฒฝ์šฐ์— ํผ๋ฏธ์…˜์„ ์„ค์ •ํ•˜๋ฉด ๋œ๋‹ค. ๋งค๋‹ˆํŽ˜์ŠคํŠธ ํŒŒ์ผ์— <permission> ํƒœ๊ทธ ๋ฅผ ๋“ฑ๋กํ•ด์ฃผ๋ฉด ๋œ๋‹ค.
์ด๋Ÿฌ๋ฉด ์•„๋ฌด๋ฆฌ ์•”์‹œ์  ์ธํ…ํŠธ ์ฝ”๋“œ๊ฐ€ ์ž˜ ์ž‘์„ฑ๋˜์–ด ์žˆ๋‹ค ํ•˜๋”๋ผ๋„ ์‹คํ–‰์ด ์•ˆ๋˜๊ฑฐ๋‚˜ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

๊ทธ๋Ÿผ ์–ด๋–ป๊ฒŒ ํผ๋ฏธ์…˜์„ ํš๋“ ํ•  ์ˆ˜ ์žˆ์„๊นŒ?
๋งค๋‹ˆํŽ˜์ŠคํŠธ ํŒŒ์ผ์— <uses-permission> ํƒœ๊ทธ๋ฅผ ๋‹ฌ์•„์ฃผ๋ฉด ๋œ๋‹ค.

๐Ÿ“š permission ํƒœ๊ทธ

<permission android:name="com.example.permission.TEST_PERMISSION"
	android:label="Test Permission"
    android:description="@string/permission_desc"
    android:protectionLevel="dangerous"/>
  • AndroidManifest.xml ํŒŒ์ผ ์„ค์ •

  • name : permission ์˜ ์ด๋ฆ„

  • label, description : permission ์— ๋Œ€ํ•œ ์„ค๋ช…

  • protectionLevel : ๋ณดํ˜ธ ์ˆ˜์ค€

๐Ÿ“Œ protectionLevel ์ข…๋ฅ˜

  • normal : ๋‚ฎ์€ ์ˆ˜์ค€์˜ ๋ณดํ˜ธ. ์œ ์ €์—๊ฒŒ ๊ถŒํ•œ ๋ถ€์—ฌ ์š”์ฒญ์ด ํ•„์š” ์—†๋Š” ๊ฒฝ์šฐ.

  • dangerous : ๋†’์€ ์ˆ˜์ค€์˜ ๋ณดํ˜ธ. ์œ ์ €์—๊ฒŒ ๊ถŒํ•œ ๋ถ€์—ฌ ์š”์ฒญ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ.

  • signature : ๋™์ผํ•œ ํ‚ค๋กœ ์‚ฌ์ธ๋œ ์•ฑ๋งŒ ์‹คํ–‰.

  • signatureOrSystem : ์•ˆ๋“œ๋กœ์ด๋“œ ์‹œ์Šคํ…œ ์•ฑ ์ด๊ฑฐ๋‚˜ ๋™์ผํ‚ค๋กœ ์‚ฌ์ธ๋œ ์•ฑ๋งŒ ์‹คํ–‰

๐Ÿงฉ Permission ์„ค์ •

๐Ÿ“Œ ํผ๋ฏธ์…˜์œผ๋กœ ๋ณดํ˜ธ

<activity
	android:name=".MainActivity"
    android:exported="true"
    android:permission="com.example.TEST_PERMISSION">
    
</activity>    
  • ํผ๋ฏธ์…˜์„ ๊ฑธ๊ณ  ์‹ถ์€ ์•กํ‹ฐ๋น„ํ‹ฐ์—๋งŒ <permission> ํƒœ๊ทธ์— ํผ๋ฏธ์…˜ ์ด๋ฆ„์„ ์ ์–ด์ฃผ๋ฉด ๋œ๋‹ค.

๐Ÿ“Œ ํผ๋ฏธ์…˜์„ ํš๋“

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
  • <uses-permission> ํƒœ๊ทธ์— ํš๋“ํ•  ํผ๋ฏธ์…˜ ์ด๋ฆ„์„ ๋˜‘๊ฐ™์ด ์ ๋Š”๋‹ค.

โž• ํผ๋ฏธ์…˜ ํš๋“์ด ํ•„์š”ํ•œ, <uses-permission> ํƒœ๊ทธ๋ฅผ ์ž‘์„ฑํ•œ ์•ฑ์ด ํ•ธ๋“œํฐ์— ์„ค์น˜๋˜๋ฉด ํ•ด๋‹น ์•ฑ์ด ์š”๊ตฌํ•˜๋Š” ํผ๋ฏธ์…˜์„ ํ•ธ๋“œํฐ ํ™˜๊ฒฝ์„ค์ •์˜ ๊ถŒํ•œ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ๋•Œ, ํผ๋ฏธ์…˜์— ๋Œ€ํ•œ ์„ค๋ช…์— label ํ˜น์€ description ๋ฌธ์ž์—ด์ด ํ‘œ์‹œ๋˜๋Š”๋ฐ, ์ด ๊ถŒํ•œ์— ๋Œ€ํ•œ ์„ค๋ช…์€ ํผ๋ฏธ์…˜์„ ์ด์šฉํ•˜๋Š” ์•ฑ์ด ์•„๋‹Œ, ํผ๋ฏธ์…˜์œผ๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ณดํ˜ธํ•˜๋Š” ์•ฑ์—์„œ ์ž‘์„ฑํ•œ ๋ฌธ์ž์—ด์ด ํ‘œ์‹œ๋œ๋‹ค.

์ฆ‰, ํผ๋ฏธ์…˜์œผ๋กœ ๋ณดํ˜ธํ•˜๋Š” A ์•ฑ๊ณผ ํผ๋ฏธ์…˜์„ ์ด์šฉํ•˜๋Š” B ์•ฑ์ด ์„ค์น˜๋˜๋ฉด, B ์•ฑ์˜ ๊ถŒํ•œ ์„ค๋ช…์— A ์•ฑ์— ์ž‘์„ฑ๋œ ํผ๋ฏธ์…˜์˜ label ํ˜น์€ description ๋ฌธ์ž์—ด์ด ํ‘œ์‹œ๋œ๋‹ค.

๊ทผ๋ฐ protectionLevel ์ด normal ์ธ๊ฑด ์•„์˜ˆ ๊ถŒํ•œ์— ํ‘œ์‹œ๋˜์ง€ ์•Š๋Š”๋‹ค. dangerous ์˜ ๊ฒฝ์šฐ์— ํ‘œ์‹œ๋œ๋‹ค.

๐Ÿงฉ ์‹œ์Šคํ…œ Permission

์‹œ์Šคํ…œ์—์„œ ์š”๊ตฌ๋˜๋Š” ํผ๋ฏธ์…˜. ์‹œ์Šคํ…œ์—์„œ ํผ๋ฏธ์…˜์œผ๋กœ ๋ณดํ˜ธํ•˜๋Š” ๊ธฐ๋Šฅ์ด ์žˆ๋‹ค.

์•ฑ๊ณผ ์•ฑ ๊ฐ„์˜ ์—ฐ๋™ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์‹œ์Šคํ…œ์—์„œ ๊ด€๋ฆฌ๋˜๋Š” ๊ธฐ๋Šฅ ์—ฐ๋™์—๋„ ํ•„์š”ํ•˜๋‹ค.

  • ACCESS_FINE_LOCATION : ์œ„์น˜ ์ •๋ณด ์ ‘๊ทผ

  • ACESS_NETWORK_STATE : ๋„คํŠธ์›Œํฌ ์ •๋ณด ์ ‘๊ทผ

  • ACCESS_WIFI_STATE : Wi-Fi ๋„คํŠธ์›Œํฌ ์ •๋ณด ์ ‘๊ทผ

  • BATTERY_STATS : ๋ฐฐํ„ฐ๋ฆฌ ์ •๋ณด ์ ‘๊ทผ

  • BLUETOOTH : ๋ธ”๋ฃจํˆฌ์Šค ์žฅ์น˜์— ์—ฐ๊ฒฐ

  • BLUETOOTH_ADMIN : ๋ธ”๋ฃจํˆฌ์Šค ์žฅ์น˜๋ฅผ ๊ฒ€์ƒ‰ํ•˜๊ณ  ํŽ˜์–ด๋ง

  • CAMERA : ์นด๋ฉ”๋ผ ์žฅ์น˜์— ์ ‘๊ทผ

  • INTERNET : ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ

  • READ_EXTERNAL_STORAGE : ์™ธ๋ถ€ ์ €์žฅ์†Œ์—์„œ ํŒŒ์ผ ์ฝ๊ธฐ

  • WRITE_EXTERNAL_STORAGE : ์™ธ๋ถ€ ์ €์žฅ์†Œ์— ํŒŒ์ผ ์“ฐ๊ธฐ

  • READ_PHONE_STATE : ์ „ํ™”๊ธฐ๋กœ์„œ์˜ ๊ฐ์ข… ์ •๋ณด ์ ‘๊ทผ

  • SEND_SMS : SMS ๋ฐœ์‹ 

  • RECEIVE_SMS : SMS ์ˆ˜์‹ 

  • RECEIVE_BOOT_COMPLETED : ๋ถ€ํŒ… ์™„๋ฃŒ ์‹œ ์‹คํ–‰

  • VIBRATE : ์ง„๋™ ์šธ๋ฆฌ๊ธฐ


๐Ÿ“‡ Permission Check, Request

ํผ๋ฏธ์…˜์€ API 1 ๋ฒ„์ „ ๋ถ€ํ„ฐ ์ œ๊ณต๋œ ๊ฐœ๋…์ด๋‹ค. ๊ทธ๋Ÿฌ๋‹ค API Level 23 ์—์„œ ํผ๋ฏธ์…˜ ์ •์ฑ…์ด ๋ณ€๊ฒฝ ๋˜์—ˆ๋‹ค.

  • API Level 23 ์ด์ „ ๋ฒ„์ „์—์„œ ํผ๋ฏธ์…˜์€ ์‹ ๊ณ ์ œ

  • API Level 23 ๋ฒ„์ „๋ถ€ํ„ฐ ํผ๋ฏธ์…˜์€ ํ—ˆ๊ฐ€์ œ

์›๋ž˜๋Š” ํผ๋ฏธ์…˜ ์š”๊ตฌ๋ฅผ ์œ ์ €๊ฐ€ ๊ฑฐ๋ถ€ํ•  ์ˆ˜ ์—†์—ˆ๋‹ค. ํ•ธ๋“œํฐ ํ™˜๊ฒฝ์„ค์ •์˜ ์•ฑ ๊ถŒํ•œ์—์„œ ์–ด๋–ค ํผ๋ฏธ์…˜์„ ์š”๊ตฌ ํ•˜๋Š”์ง€๋Š” ํ™•์ธํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋Œ ์ˆ˜๋Š” ์—†์—ˆ๋‹ค๊ณ  ํ•œ๋‹ค. ๊ทธ๋ž˜์„œ ์ด๊ฒƒ์ด ์œ ์ € ์‚ฌ์ƒํ™œ ๋ณดํ˜ธ์— ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๋Š” ํŒ๋‹จ ํ•˜์— 23 ๋ฒ„์ „๋ถ€ํ„ฐ ์ •์ฑ…์ด ๋ณ€๊ฒฝ๋˜์–ด ์œ ์ €๊ฐ€ ๊ถŒํ•œ์„ ๊ฑฐ๋ถ€ํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.

๐Ÿ“š Permission Check

val status = ContextCompat.checkSelfPermission(this, "android.permission.ACCESS_FINE_LOCATION")
if (status == PackageManager.PERMISSION_GRANTED) {
	Log.d("Permission", "permission granted")
} else {
	Log.d("Permission", "permission denied")
}
  • ํผ๋ฏธ์…˜ ์ฒดํฌ๋Š” checkSelfPermission() ํ•จ์ˆ˜ ์ด์šฉ. ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ํผ๋ฏธ์…˜ ์ด๋ฆ„์„ ์ค€๋‹ค.

  • ๊ฒฐ๊ณผ ๊ฐ’์€ ์ƒ์ˆ˜๋กœ ์ „๋‹ฌ

  • PackageManager.PERMISSION_GRANTED : ํผ๋ฏธ์…˜์ด ํ—ˆ๋ฝ๋œ ๊ฒฝ์šฐ

  • PackageManager.PERMISSION_DENIED : ํผ๋ฏธ์…˜์ด ๊ฑฐ๋ถ€๋œ ๊ฒฝ์šฐ

ํผ๋ฏธ์…˜์ด ํ—ˆ๋ฝ๋œ ์ƒํ™ฉ์ด๋ฉด ๊ทธ๋ƒฅ ๊ทธ ์ž‘์—…์„ ์‹คํ–‰ํ•˜๋ฉด ๋œ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ํผ๋ฏธ์…˜์ด ๋ง‰ํ˜€ ์žˆ๋‹ค๋ฉด?

์œ ์ €์—๊ฒŒ ํผ๋ฏธ์…˜์„ ํ—ˆ๋ฝํ•ด ๋‹ฌ๋ผ๋Š” ์š”์ฒญ์„ ๋ณด๋‚ด์•ผ ํ•œ๋‹ค.

๐Ÿ“š Permission Request

์˜ค๋ž˜ ์ „๋ถ€ํ„ฐ ์ด์šฉํ•œ ๋ฐฉ๋ฒ•๊ณผ ์ตœ๊ทผ์— ์ถ”๊ฐ€๋œ ๋ฐฉ๋ฒ•, 2๊ฐ€์ง€์˜ ์š”์ฒญ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

๐Ÿ“Œ requestPermissions() ๋ฐฉ๋ฒ•

ActivityCompat.requestPermissions(this, arrayOf<String>("android.permission.ACCESS_FINE_LOCATION"), 100)
  • ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ํผ๋ฏธ์…˜ ์ด๋ฆ„์„ ์ฃผ๋Š”๋ฐ, ํ•œ๊บผ๋ฒˆ์— ์—ฌ๋Ÿฌ๊ฐœ์˜ ํผ๋ฏธ์…˜์„ ๋ฐฐ์—ด๋กœ ์ค„ ์ˆ˜ ์žˆ๋‹ค.

  • requestPermissions() ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ํ•ธ๋“œํฐ์— ํผ๋ฏธ์…˜ ์š”์ฒญ์„ ์œ„ํ•œ ์‹œ์Šคํ…œ ๋‹ค์ด์–ผ๋กœ๊ทธ๊ฐ€ ๋œฌ๋‹ค.

  • ์œ ์ €๊ฐ€ ๊ฑฐ๋ถ€ ํ˜น์€ ํ™•์ธ์„ ์„ ํƒํ•˜์—ฌ ๋‹ค์ด์–ผ๋กœ๊ทธ๊ฐ€ ์ข…๋ฃŒ๋œ ์ˆœ๊ฐ„ onRequestPermissionsResult() ํ•จ์ˆ˜๊ฐ€ ์ž๋™ ์ฝœ ๋œ๋‹ค.

override fun onRequestPermissionsResult(
	requestCode: Int,
    permissions: Array<out String>,
    grantResults: IntArray
) {
	super.onRequestPermissionsResult(requestCode, permissions,grantResults)
    if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
    	Toast.makeText(this, "permission granted", Toast.LENGTH_SHORT).show()
    } else {
    	Toast.makeText(this, "permission denied", Toast.LENGTH_SHORT).show()
    }       
}
  • ์„ธ ๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜ ๊ฐ’์œผ๋กœ ์œ ์ €์˜ ์„ ํƒ์ด ์ „๋‹ฌ ๋œ๋‹ค.

๐Ÿ“Œ registerForActivityResult() ๋ฐฉ๋ฒ•

API 31 ๋ฒ„์ „์—์„œ ์ถ”๊ฐ€๋œ ๊ฐœ๋…

val requestPermissionLauncher = registerForActivityResult(
	ActivityResultContracts.RequestPermission()
) { isGranted ->
	if (isGranted) {
    	Toast.makeText(this, "permission granted", Toast.LENGTH_SHORT).show()
	} else {
    	Toast.makeText(this, "permission denied", Toast.LENGTH_SHORT).show()
	}        
}
requestPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION)

๐Ÿงฉ ์‹ค์Šต ์˜ˆ์ œ

์œ ์ € ์œ„์น˜ ์ •๋ณด ํผ๋ฏธ์…˜ ์š”์ฒญ

  • AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.AndroidLab">
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

  • MainActivity.kt
package com.kotdev99.android.c51

class MainActivity : AppCompatActivity() {
	override fun onCreate(savedInstanceState: Bundle?) {
		super.onCreate(savedInstanceState)
		setContentView(R.layout.activity_main)

		// test2...
		val requestPermissionLauncher = registerForActivityResult(
			ActivityResultContracts.RequestPermission()
		) {
			if (it) {
				Toast.makeText(this, "granted...", Toast.LENGTH_SHORT).show()
			} else {
				Toast.makeText(this, "denied...", Toast.LENGTH_SHORT).show()
			}
		}

		// ํผ๋ฏธ์…˜์˜ ํ—ˆ๋ฝ/๊ฑฐ๋ถ€ ์—ฌ๋ถ€ ํ™•์ธ
		val status = ContextCompat.checkSelfPermission(
			this,
			"android.permission.ACCESS_FINE_LOCATION"
		)
		if (status == PackageManager.PERMISSION_GRANTED) {
			Toast.makeText(this, "granted...", Toast.LENGTH_SHORT).show()
		}
		// ํผ๋ฏธ์…˜ ์š”์ฒญ์„ ์œ„ํ•œ ์‹œ์Šคํ…œ ๋‹ค์ด์–ผ๋กœ๊ทธ ์ถœ๋ ฅ
		else {
			// test1...
//			ActivityCompat.requestPermissions(
//				this,
//				arrayOf<String>("android.permission.ACCESS_FINE_LOCATION"),
//				100
//			)

			// test2...
			requestPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION)
		}
	}

	// requestPermissions() ํ˜ธ์ถœ ์‹œ ์ž๋™ ์ฝœ
	override fun onRequestPermissionsResult(
		requestCode: Int,
		permissions: Array<out String>,
		grantResults: IntArray
	) {
		super.onRequestPermissionsResult(requestCode, permissions, grantResults)
		if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
			Toast.makeText(this, "granted...", Toast.LENGTH_SHORT).show()
		} else {
			Toast.makeText(this, "denied...", Toast.LENGTH_SHORT).show()
		}
	}
}

๐Ÿ“ฒ ๊ฒฐ๊ณผ

profile
์‘์•  ๋‚˜ ์•„๊ธฐ ๋‰ด๋น„

0๊ฐœ์˜ ๋Œ“๊ธ€