** 소스코드 옮기는 과정에서 계속 띄어쓰기 및 대소문자가 뒤바뀌는 이슈가 있어서 직접 작성 혹은 수정하느라 이상한 오타가 있을 수 있습니다.
저번에 말씀드린 대로 주변 장치에서 Advertisement 라는 행위를 통해서
" 나 여기 경주최씨 충렬공파 37대손 최형배 입니다 " 라는 값들을 알리고 있다.
그러한 값들을 일단 싸그리 주워 담아야 한다.
블루투스 스캔을 하기위해서는 준비물이 필요합니다.
AndroidManifest.xml에 두가지 permission을 줘야 합니다.
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
위의 permission은 커넥션과 페어링된 기기와 데이터 송수신을 사용하겠다는 권한이며,
아래의 permission은 기기 검색, 블루투스 설정등을 다루는데 필요합니다.
android.permission.BLUETOOTH_ADMIN을 하기 위해선 상단의 android.permission.BLUETOOTH 권한이 필수로 적용되어야 합니다.
이제 권한을 주었으니 Bluetooth 기능을 사용할 수 있습니다.
나머지 준비물은 바로 Bluetooth Adapter와 Bluetooth Manager 입니다.
공식 문서에 의하면 Bluetooth Adapter는
" 로컬 장치 Bluetooth 어댑터를 나타냅니다. 을 BluetoothAdapter 사용하면 장치 검색 시작, 본딩 된 (페어링 된) 장치 목록 쿼리 BluetoothDevice, 알려진 MAC 주소를 사용하여 인스턴스화, BluetoothServerSocket다른 장치의 연결 요청 수신을위한를 생성 , Bluetooth 검색 시작과 같은 기본적인 Bluetooth 작업을 수행 할 수 있습니다. "
이고
Bluetooth Manager는
" BluetoothAdapter의 인스턴스를 얻고 전반적인 Bluetooth 관리를 수행하는 데 사용되는 고급 관리자입니다."
라고 합니다.
일단 우리는 그냥 두개를 바로 선언해서 써주기만 하면 됩니다.
저의 예시를 들어보자면
//전역변수 선언
private var m_bluetoothAdapter : BluetoothAdapter? = null
private var m_bluetoothManager : BluetoothManager? = null
// onCreate()
m_bluetoothManager = getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
m_bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
이렇게 기본 블루투스 어댑터와 매니저를 설정해 주었습니다. 위처럼 작성하시면 알아서 import 하라고 뜰겁니다.
그러면 이제 이걸 활용해서 먼저 해야할 일이 있습니다.
해당 장치가 블루투스를 지원하는지 블루투스는 켜져 있는지 확인을 해주어야 합니다.
if (m_bluetoothAdapter == null) {
//없다
}
정말 간단하게 확인할 수 있습니다. 초반에 이렇게 확인하고 없으면 다른 가이드를 주면 되겠습니다.
이거는 이제 블루투스를 지원하지 않는 경우입니다. 지원하는데 켜지 않은거랑은 완전히 다르죠
켜져있는지 꺼져있는지 확인하는 방법은 아래와 같이 사용하시면 됩니다.
private fun checkBt() : Boolean{
bluetoothStatus = m_bluetoothAdapter!!.isEnabled
return bluetoothStatus
}
자 그럼 블루투스 모듈의 유무와 블루투스를 켰는지 확인했고 주변 장치를 스캔 해보겠습니다.
스캔을 위해서는 Scanner가 필요합니다.
// 변수선언
private var m_scanner : BluetoothLeScanner? = null
//스캐너 설정
m_scanner = m_bluetoothAdapter?.bluetoothLeScanner
//스캔 시작
m_scanner?.startScan(filters, settings, mScanCallback)
//스캔 종료
m_scanner?.stopScan(mScanCallback)
??그냥 스타트하면 되는게 아니라 filter, settings , scanCallback 이라니..
여기서 저는 filter 말그대로 검색 스캔에 필요한 필터는 필요 없어서
val filters = ArrayList<Scanfilter>()
filters = ArrayList()
애초에 이렇게 그냥 초기화 시켜놓고 건들지를 않습니다만 나중에 이러한 필터 리스트에 필터에 상응하는 상수를 넣으면 아마도 필터가 적용될 것 입니다.
세팅은 말그대로 스캔을 할 때 세팅값을 주는 것 입니다.
var settings=ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).setReportDelay(500).setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES).build()
저는 이렇게 설정했는데 솔직히 이렇게 모르는 상수들을 넣어야할때는 공식 홈페이지 확인하시는게 무조건 답입니다.
developer.android.com/reference/android/bluetooth/le/ScanSettings
이렇게 스캐너를 만들면 다른 여타 스캐너들이 비슷하 듯 콜백이 있어야 합니다. 그래야 스캔 결과를 받아올 수 있으니까요
private val mScanCallback:ScanCallback = object:ScanCallback(){
@RequiresApi(Build.VERSION_CODES.O)
override fun onScanResult(callbackType : Int,result : ScanResult){
processResult(result)
}
@RequiresApi(Build.VERSION_CODES.O)
override fun onBatchScanResults(results:List<ScanResult>){
for(result in results){
processResult(result)
}
}
override fun onScanFailed(errorCode : Int){}
@RequiresApi(Build.VERSION_CODES.O)
private fun processResult(result : ScanResult){
//결과 출력값
Log.i("rssi,txpower",result.rssi.toString()+","+result.txPower+""+result.getDevice().name)
//rssi값을 이용한 거리 계산
var distance = Math.pow(10.0,(((result.txPower - result.rssi)/20).toDouble()))
}
}
이렇게 scan 결과는 processResult에 출력될 수 있다는걸 알게 되었습니다.
processResult에서 출력된 값들을 가지고 이래저래 바꾸거나 사용해서 거리를 구하거나 List에 삽입하거나 할 수 있습니다.
<수정 중>
하지만 이렇게만 한다고 무조건 되는건 아닙니다.
꼭 위치 권한을 확인해야하며 이는 AndroidManifest.xml 에서 corse, fine location 권한을 주는것 외에도 핸드폰 설정 앱에서 권한이 주어졌는지 한번더 확인하는걸 추천드립니다. 그리고 혹시 블루투스는 켜져있는지 확인도 중요합니다. 두 사례 모두 앱 배포 하기전에 사용자들이 많이 하는 실수인걸 알고 수정했습니다.
'프로그래밍 > Android (Kotlin)' 카테고리의 다른 글
[5가지 사랑의 언어] 연애 심리 테스트 앱 "얼마나 사랑해" 출시했습니다. 사랑에 대한 고뇌로 만들어진 앱 (0) | 2021.06.15 |
---|---|
[Android] BLE 통신 애플리케이션 개발하기 #1 - 개발이전에 알아두면 좋을 정보들 (0) | 2021.03.23 |