๐ SeSAC์ 'JetPack๊ณผ Kotlin์ ํ์ฉํ Android App ๊ฐ๋ฐ' ๊ฐ์ข๋ฅผ ์ ๋ฆฌํ ๊ธ ์ ๋๋ค.
B์ ์ฑ์์ A ์ฑ์ ์ปดํฌ๋ํธ๋ฅผ ์คํ์ํฌ ์ ์๊ฒ๋ ํ๊ณ ๋ ์ถ์๋ฐ ๋ณด์์ ๊ฑธ๊ณ ์ถ์ ๋, ์ด๋ฐ ๊ฒฝ์ฐ์ ํผ๋ฏธ์
์ ์ค์ ํ๋ฉด ๋๋ค. ๋งค๋ํ์คํธ ํ์ผ์ <permission> ํ๊ทธ
๋ฅผ ๋ฑ๋กํด์ฃผ๋ฉด ๋๋ค.
์ด๋ฌ๋ฉด ์๋ฌด๋ฆฌ ์์์ ์ธํ
ํธ ์ฝ๋๊ฐ ์ ์์ฑ๋์ด ์๋ค ํ๋๋ผ๋ ์คํ์ด ์๋๊ฑฐ๋ ์๋ฌ๊ฐ ๋ฐ์ํ๋ค.
๊ทธ๋ผ ์ด๋ป๊ฒ ํผ๋ฏธ์
์ ํ๋ ํ ์ ์์๊น?
๋งค๋ํ์คํธ ํ์ผ์ <uses-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 : ๋ณดํธ ์์ค
normal : ๋ฎ์ ์์ค์ ๋ณดํธ. ์ ์ ์๊ฒ ๊ถํ ๋ถ์ฌ ์์ฒญ์ด ํ์ ์๋ ๊ฒฝ์ฐ.
dangerous : ๋์ ์์ค์ ๋ณดํธ. ์ ์ ์๊ฒ ๊ถํ ๋ถ์ฌ ์์ฒญ์ด ํ์ํ ๊ฒฝ์ฐ.
signature : ๋์ผํ ํค๋ก ์ฌ์ธ๋ ์ฑ๋ง ์คํ.
signatureOrSystem : ์๋๋ก์ด๋ ์์คํ
์ฑ ์ด๊ฑฐ๋ ๋์ผํค๋ก ์ฌ์ธ๋ ์ฑ๋ง ์คํ
<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 ์ ๊ฒฝ์ฐ์ ํ์๋๋ค.
์์คํ ์์ ์๊ตฌ๋๋ ํผ๋ฏธ์ . ์์คํ ์์ ํผ๋ฏธ์ ์ผ๋ก ๋ณดํธํ๋ ๊ธฐ๋ฅ์ด ์๋ค.
์ฑ๊ณผ ์ฑ ๊ฐ์ ์ฐ๋ ๋ฟ๋ง ์๋๋ผ ์์คํ ์์ ๊ด๋ฆฌ๋๋ ๊ธฐ๋ฅ ์ฐ๋์๋ ํ์ํ๋ค.
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 : ์ง๋ ์ธ๋ฆฌ๊ธฐ
ํผ๋ฏธ์ ์ API 1 ๋ฒ์ ๋ถํฐ ์ ๊ณต๋ ๊ฐ๋ ์ด๋ค. ๊ทธ๋ฌ๋ค API Level 23 ์์ ํผ๋ฏธ์ ์ ์ฑ ์ด ๋ณ๊ฒฝ ๋์๋ค.
API Level 23 ์ด์ ๋ฒ์ ์์ ํผ๋ฏธ์ ์ ์ ๊ณ ์
API Level 23 ๋ฒ์ ๋ถํฐ ํผ๋ฏธ์ ์ ํ๊ฐ์
์๋๋ ํผ๋ฏธ์
์๊ตฌ๋ฅผ ์ ์ ๊ฐ ๊ฑฐ๋ถํ ์ ์์๋ค. ํธ๋ํฐ ํ๊ฒฝ์ค์ ์ ์ฑ ๊ถํ์์ ์ด๋ค ํผ๋ฏธ์
์ ์๊ตฌ ํ๋์ง๋ ํ์ธํ ์ ์์ง๋ง, ๋ ์๋ ์์๋ค๊ณ ํ๋ค. ๊ทธ๋์ ์ด๊ฒ์ด ์ ์ ์ฌ์ํ ๋ณดํธ์ ๋ฌธ์ ๊ฐ ์๋ค๋ ํ๋จ ํ์ 23 ๋ฒ์ ๋ถํฐ ์ ์ฑ
์ด ๋ณ๊ฒฝ๋์ด ์ ์ ๊ฐ ๊ถํ์ ๊ฑฐ๋ถํ ์ ์๊ฒ ๋์๋ค.
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 : ํผ๋ฏธ์ ์ด ๊ฑฐ๋ถ๋ ๊ฒฝ์ฐ
ํผ๋ฏธ์ ์ด ํ๋ฝ๋ ์ํฉ์ด๋ฉด ๊ทธ๋ฅ ๊ทธ ์์ ์ ์คํํ๋ฉด ๋๋ค. ๊ทธ๋ฐ๋ฐ ํผ๋ฏธ์ ์ด ๋งํ ์๋ค๋ฉด?
์ ์ ์๊ฒ ํผ๋ฏธ์
์ ํ๋ฝํด ๋ฌ๋ผ๋ ์์ฒญ์ ๋ณด๋ด์ผ ํ๋ค.
์ค๋ ์ ๋ถํฐ ์ด์ฉํ ๋ฐฉ๋ฒ๊ณผ ์ต๊ทผ์ ์ถ๊ฐ๋ ๋ฐฉ๋ฒ, 2๊ฐ์ง์ ์์ฒญ ๋ฐฉ๋ฒ์ด ์๋ค.
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()
}
}
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)
์ ์ ์์น ์ ๋ณด ํผ๋ฏธ์ ์์ฒญ
<?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>
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()
}
}
}