며칠전 갑자기 테스트 중인 앱이 원인을 알 수 없는 오류가 잔뜩 발생했다.
정식 출시는 한참 전이었는데 안드로이드 기기에서의 업데이트는 왜 이제서야 자동 업데이트가 진행된걸까. 절대로 내가 게을러서 이제서야 알게 된게 아니다.
진짜다.
일단 공식 문서부터 훑어봤다.
...훑어는 봤다.
사실 다시금 문서를 보게 된 계기는 블루투스 때문이었다.
내부에서 테스트 중이던 앱이 테스트 장비에서 안드로이드 12 업데이트 이후
런타임 익셉션으로 사망하는 현상이 발생했기 때문이다.
아래 오류와 함께 블루투스를 검색하는 순간 런타임 에러가 발생.
java.lang.SecurityException: Need android.permission.BLUETOOTH_CONNECT permission for AttributionSource { uid = 10323, packageName = com.***.***, attributionTag = null, token = android.os.BinderProxy@effd826, next = null }: getAddress
at android.os.Parcel.createExceptionOrNull(Parcel.java:2437)
at android.os.Parcel.createException(Parcel.java:2421)
at android.os.Parcel.readException(Parcel.java:2404)
at android.os.Parcel.readException(Parcel.java:2346)
at android.bluetooth.IBluetoothManager$Stub$Proxy.getAddress(IBluetoothManager.java:1165)
at android.bluetooth.BluetoothAdapter.getAddress(BluetoothAdapter.java:2326)
.
.
.
Caused by: android.os.RemoteException: Remote stack trace:
at com.android.server.BluetoothManagerService.checkPermissionForDataDelivery(BluetoothManagerService.java:5019)
at com.android.server.BluetoothManagerService.checkConnectPermissionForDataDelivery(BluetoothManagerService.java:5037)
at com.android.server.BluetoothManagerService.getAddress(BluetoothManagerService.java:2800)
at android.bluetooth.IBluetoothManager$Stub.onTransact(IBluetoothManager.java:527)
at android.os.Binder.execTransactInternal(Binder.java:1215)
설마 안드로이드 12 와 함께 또, 또... 또!!
또 권한이 변경된 건 아닐까 다시금 레퍼런스를 훑어 보게 되었다.
아니나 다를까, 권한 요청 퍼미션이 변경되었다...
마치 내 여자친구의 마음과 같다. aka 갈대.
<manifest>
<!-- 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" />
<!-- Needed only if your app looks for Bluetooth devices.
You must add an attribute to this permission, or declare the
ACCESS_FINE_LOCATION permission, depending on the results when you
check location usage in your app. -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<!-- Needed only if your app makes the device discoverable to Bluetooth
devices. -->
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<!-- Needed only if your app communicates with already-paired Bluetooth
devices. -->
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
...
</manifest>
내용은 크게 복잡하지 않았다.
sdk 31 을 타겟팅하는 앱의 경우 새 권한을 부여한다는 내용이다.
위 내용처럼 기존에 부여했던 android.permission.BLUETOOTH, android.permission.BLUETOOTH_ADMIN 에는
android:maxSdkVersion="30" 를 추가해 30 이전의 sdk 에만 적용하게 하고,
BLUETOOTH_SCAN, BLUETOOTH_ADVERTISE, BLUETOOTH_CONNECT
를 추가해주었다.
여기서 끝이 아니었다.
사용자에게 표시되는 대화상자
BLUETOOTH_SCAN, BLUETOOTH_ADVERTISE, BLUETOOTH_CONNECT 권한은 런타임 권한입니다. 따라서 명시적으로 앱에서 사용자 승인을 요청해야 블루투스 기기를 찾거나 기기를 다른 기기에서 검색할 수 있게 하거나 이미 페어링된 블루투스 기기와 통신할 수 있습니다.앱이 새 블루투스 권한 중 하나 이상을 요청하면 시스템은 그림 1과 같이 앱이 근처 기기에 액세스하도록 허용하라는 메시지를 사용자에게 표시합니다.
"BLUETOOTH_SCAN, BLUETOOTH_ADVERTISE, BLUETOOTH_CONNECT 권한은 런타임 권한입니다."
그렇다. 이 녀석들은 런타임 권한이라, 실행 시 퍼미션 체크를 해주어야 한다.
private fun asyncPermissionCheck() = lifecycleScope.launch{
TedPermission.create()
.setPermissions(
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.BLUETOOTH_SCAN,
Manifest.permission.BLUETOOTH_ADVERTISE,
Manifest.permission.BLUETOOTH_CONNECT
)
.check()
}
애용하던 TedPermission 에서 체크하도록 위 권한들을 추가해주었더니,
예시처럼 블루투스 기기 검색에 대한 권한 요청 팝업이 나타나게 된다.
그리고 평화...
매번 구글링으로 답만 찾아 해내다가 처음으로 기술로그를 남기는게 기분이 묘하다.
경험이 있다면 조금만 찾아봐도 얻을 수 있는 내용이지만,
나 또한 처음 개발하던 때부터, 어느 정도 능숙해졌다고 생각한 시점에서도
문제 해결을 위한 답을 찾지 못해 해맬때가 많았다.
이 별거 아닌 내용이 누군가에게 도움이 될거라고 생각하면, 아주 조금은 가슴 한켠이 아늑해진다.