본문 바로가기

Android

[안드로이드] 안드로이드 12 블루투스 퍼미션 대응하기 ― API 별 블루투스 권한 대응

728x90
반응형

 

 

Android 12에서는 새로운 블루투스 권한이 도입 되어, 대응할 필요가 있게 되었습니다.

이에 아래 공식문서를 참조하여 대응하였습니다.

 

Android 12의 새 블루투스 권한  |  Android Developers

내년 초 출시될 대형 화면용 기능 출시인 12L을 준비하세요. 지금 사용해 보기 Android 12의 새 블루투스 권한 Android 12에서는 BLUETOOTH_SCAN, BLUETOOTH_ADVERTISE, BLUETOOTH_CONNECT 권한을 도입합니다. 이를 통

developer.android.com

 

정리하자면, Android 12부터는 BLUETOOTH_SCAN, BLUETOOTH_ADVERTISE, BLUETOOTH_CONNECT 권한이 도입되었는데,

  • BLUETOOTH_SCAN : 주변 블루투스 기기를 검색하는 경우
  • BLUETOOTH_ADVERTISE: 현재 기기를 다른 블루투스 기기에서 검색할 수 있도록 하는 경우
  • BLUETOOTH_CONNECT: 이미 페어링된 기기와 통신해야할 경우

에 추가되어야 하고,

 

API 별로 Scan, Connect에 필요한 런타임 퍼미션을 정리하자면 다음과 같습니다.

Scan

API runtime permissions
18~22 런타임 퍼미션 필요 없음
23~28 아래 둘중 하나 필요
- android.permission.ACCESS_COARSE_LOCATION
- android.permission.ACCESS_FINE_LOCATION
29~30 - android.permission.ACCESS_FINE_LOCATION

* 만약 백그라운드에서 스캔이 수행되어야 할 경우 필요
- android.permission.ACCESS_BACKGROUND_LOCATION
31~ - android.permission.BLUETOOTH_SCAN

* 스캔시 유저의 위치를 포함해야 할 경우 필요
- android.permission.ACCESS_FINE_LOCATION

 

Connect

API runtime permissions
18~30 런타임 퍼미션 필요 없음
31~ - android.permission.BLUETOOTH_CONNECT

 

 

위의 사항을 참고하여, 다음과 같이 권한을 작성하였습니다.

  • AndroidManifest.xml
    <!-- Request legacy Bluetooth permissions on older devices. -->
    <uses-permission android:name="android.permission.BLUETOOTH"
        android:maxSdkVersion="30" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
        android:maxSdkVersion="30" />
    
    <!-- Include "neverForLocation" only if you can strongly assert that
         your app never derives physical location from Bluetooth scan results. -->
    <uses-permission android:name="android.permission.BLUETOOTH_SCAN"
                     android:usesPermissionFlags="neverForLocation" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
    <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
    
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

 

  • MainActivity.kt
    val PERMISSIONS = arrayOf(
        Manifest.permission.ACCESS_FINE_LOCATION
    )
    val PERMISSIONS_S_ABOVE = arrayOf(
        Manifest.permission.BLUETOOTH_SCAN,
        Manifest.permission.BLUETOOTH_CONNECT,
        Manifest.permission.ACCESS_FINE_LOCATION
    )
    val REQUEST_ALL_PERMISSION = 2
    
    ...
    
     override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
     	...
       if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.S){
            if (!hasPermissions(this, PERMISSIONS_S_ABOVE)) {
                requestPermissions(PERMISSIONS_S_ABOVE, REQUEST_ALL_PERMISSION)
            }
        }else{
            if (!hasPermissions(this, PERMISSIONS)) {
                requestPermissions(PERMISSIONS, REQUEST_ALL_PERMISSION)
            }
        }
        ...
        
    ...
    
    private fun hasPermissions(context: Context, permissions: Array<String>): Boolean {
            for (permission in permissions) {
                if (ActivityCompat.checkSelfPermission(context, permission)
                    != PackageManager.PERMISSION_GRANTED
                ) {
                    return false
                }
            }
        return true
    }
    
    ...
    // Permission check
    @RequiresApi(Build.VERSION_CODES.M)
    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<String?>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        when (requestCode) {
            REQUEST_ALL_PERMISSION -> {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    Toast.makeText(this, "Permissions granted!", Toast.LENGTH_SHORT).show()
                } else {
                    requestPermissions(permissions, REQUEST_ALL_PERMISSION)
                    Toast.makeText(this, "Permissions must be granted", Toast.LENGTH_SHORT).show()
                }
            }
        }
    }

 

공식문서를 보면, 스캔에 유저의 실제 위치를 파생 하지 않을경우, 할 경우 나누어 설명이 되어있으므로, 참고하면 좋겠습니다.

 

 

728x90
반응형