안드로이드 개발자 사이트에서 Android12 Bluetooth 관련 변경점들이 추가되었다. 자세한 내용은 아래의 링크를 참조하자.
요약하자면 Android12 이상의 기기 및 targetSDKversion 31 이상의 앱에서는 블르투스 기능을 사용하기 위해 아래의 세가지 런타임 퍼미션을 승인 받아야 한다.
BLUETOOTH_SCAN은 앱이 블루투스 주변기기를 스캔하는 경우 필요한 권한이다.
BLUETOOTH_ADVERTISE은 현재 기기를 다른 기기가 스캔하여 찾을 수 있도록 Advertising 하는 경우 필요한 권한이다.
BLUETOOTH_CONNECT은 블루투스 기기화 연결하여 통신할 경우 필요한 권한이다.
<!-- API 31(S) 이상 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"
android:usesPermissionFlags="neverForLocation"
tools:targetApi="s" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- 31미만 23(M) 이상 -->
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
여기서 주목할 점은 31미만 버전에서 위치 관련 ACCESS_COARSE_LOCATION, ACCESS_FINE_LOCATION가 필요한 이유는 해당 권한이 허용되자 않으면 Bluetooth Scan을 할 수 없기 때문이다.
그리고 BLUETOOTH_SCAN 퍼미션에 android:usesPermissionFlags="neverForLocation" 속성을 넣었는데 이 속성이 없으면 실제로 기기가 스캔이 되지 않고 위치권한을 추가적으로 받아야 스캔이 되는것을 확인했다.
그밖의 BLUETOOTH/BLUETOOTH_ADMIN 퍼미션은 BluetoothManager 등 블루투스 관련 기능을 위한 권한이다.
// 위치 관련 퍼미션
private val PERMISSIONS_LOCATION = arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION)
// 블루투스 관련 펴미션
@RequiresApi(Build.VERSION_CODES.S)
private val PERMISSIONS_BLUETOOTH = arrayOf(
Manifest.permission.BLUETOOTH_CONNECT,
Manifest.permission.BLUETOOTH_ADVERTISE,
Manifest.permission.BLUETOOTH_SCAN)
// Activity Result Launcher
private lateinit var activityResultLauncherLocationPermissions: ActivityResultLauncher<Array<String>> // 위치 관련 퍼미션
private lateinit var activityResultLauncherBluetoothPermissions: ActivityResultLauncher<Array<String>> // 블루투스 관련 퍼미션
// Activity Result Launcher 초기화
private fun initActivityResultLauncher() {
// 위치 정보 퍼미션
activityResultLauncherLocationPermissions = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { result: MutableMap<String,Boolean> ->
val deniedList: List<String> = result.filter {
!it.value
}.map {
it.key
}
// 퍼미션 허용 여부
if (deniedList.isEmpty()) {
checkEnableBluetooth()
} else {
showPopupPermissionsDenied()
}
}
// 블루투스 퍼미션
activityResultLauncherBluetoothPermissions = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { result: MutableMap<String,Boolean> ->
val deniedList: List<String> = result.filter {
!it.value
}.map {
it.key
}
// 퍼미션 허용 여부
if (deniedList.isEmpty()) {
checkEnableBluetooth()
} else {
showPopupPermissionsDenied()
}
}
}
/**
* 권한 체크
*/
private fun checkPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
activityResultLauncherBluetoothPermissions.launch(PERMISSIONS_BLUETOOTH)
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
activityResultLauncherLocationPermissions.launch(PERMISSIONS_LOCATION)
} else {
checkEnableBluetooth()
}
}
위 내용은 블루투스 관련 퍼미션들을 정의하고 SDK 버전에 따라서 다른 권한을 요청하는 코드이다.
API 31 이상에서는 BLUETOOTH 관련 권한들을 요청하고
31미만인 경우에는 위치관련 권한을 요청한다.
android.permission.BLUETOOTH_ADMIN
android.permission.BLUETOOTH
Androidmanifest에 정의한 위 두 퍼미션은 런타임 퍼미션이 아니므로 따로 권한요청을 할 필요가 없다.