[Android] (Nordic) Android-BLE-Library 정리

sute·2023년 11월 2일
0

안드로이드

목록 보기
3/3

최근 BLE 통신을 하는 앱을 개발하게 되었는데, 기존 안드로이드에서 제공하는 BLE API가 은근 사용 불편해서 괜찮은 라이브러리가 없나 찾아보았다.

2개정도 발견했는데 RxAndroidBle와 Android-BLE-Liblrary이다.
둘다 써보긴했는데 뭔가 Rx는 내손에 안맞아서 Nordic사의 Android-BLE-Liblrary를 채택하게 되었다.

근데 막상 써보려고하니 제대로된 API문서 같은게 하나도 안나와있어서, 여기다가 작성해보려고 한다.

1. BLE 통신 단계

(내 기준) 단계는 다음과 같다.
기기 스캔 -> 연결 -> service discover -> characteristic discover -> 연결완료 -> notift enable -> 데이터 수신

2. 스캔

2.1 라이브러리

아쉽게도 해당 라이브러리에서는 스캔기능을 지원하지 않고, Android-Scanner-Compat-Library 라는 라이브러리를 따로 사용해야 한다. 기존 안드로이드에서 제공하는 BLE 스캐너와 용법은 동일한데, legacy 버전까지 지원하기 위함으로 보인다.

해당 라이브러리는 API 문서가 나름 잘 나와있으므로, 해당 포스팅에서는 다루지 않아도 될것 같다.

아래 주소를 통해 라이브러리 implement 및 사용법을 확인할 수 있다.
https://github.com/NordicSemiconductor/Android-Scanner-Compat-Library

2.2 디바이스 스캔

스캔을 하게 되면 Advertising 하고 잇는 주변 BLE 기기를 스캔해 콜백으로 넘겨준다.

이때 콜백으로 받은 Device 인자를 저장해두고 있다가 이후 연결할 때 사용하면 된다.

3. 연결

스캔 단계에서 스캔한 Device를 연결한다.
처음에 좀 햇갈렸었는데, 연결한다고 바로 데이터 송수신을 하는게 아니라, service, characteristic 까지 모두 찾아낸 이후에 송수신이 가능하다.
말 그대로 연결만 하는듯?

3.1 연결 전 사전준비

기기와 연결하기 위해선 BleManager를 상속받은 클래스를 새로 생성해 줘야 한다.

class MyBleManager(context: Context): BleManager(context) {
    ...
}

그리고 몇가지 메소드들을 override 해줘야 하는데, 빼먹고 안했더니 Device not supported였나? 그런 경고 뜨면서 바로 disconnect 되더라.

3.1.1 isRequiredServiceSupported(gatt: BluetoothGatt)

해당 메소드는 연결 과정에서 반드시 포함되어야 하는 Service 혹은 Characteristic 을 지정하는 메소드이다.

해당 메소드를 override 하지 않으면, 리턴값이 false로 넘어가서 모든 기기와 연결이 거부된다.
그냥 return true 해버리면 모든 기기와 연결 가능하려나? ㅋㅋ

다음과 같이 사용할 수 있다.

override fun isRequiredServiceSupported(gatt: BluetoothGatt) {
    val myService = gatt.getService(UUID.fromString("my-uuid")) ?: return false
    
    myRxCharacteristic = myService.getCharacteristic(UUID.fromString("my-rx-uuid")) ?: return false
    
    myTxCharacteristic = myService.getCharacteristic(UUID.fromString("my-tx-uuid")) ?: return false
    
    return true
}

위와같이 작성하게 되면, my-uuid 라는 uuid를 가진 서비스가 있는 기기,
RxCharacteristic 의 UUID가 my-rx-uuid 인 기기,
TxCharacteristic 의 UUID가 my-tx-uuid 인 기기에 한해서만 연결 가능하도록 지정할 수 있다.

위 메소드에 있는 myRx(Tx)Characteristic 변수는 멤버변수로 선언했다고 가정하자.

3.1.2 initialize()

통신 전 초기화 로직들을 넣어놓는 함수로 보인다.
정확한 호출 시기는 로그를 안찍어봐서 모르겠는데, 여기서 notify enable,
notification callback, request mtu 등을 작성하면 된다.

override fun initialize() {
    setNotificationCallback(myTxCharacteristic).with { device, data ->
        // data 인자를 통해 값 수신 가능하다.
    }

    	
    beginAtomicRequestQueue()
        .add(enableNotifications(myTxCharacteristic))
        .add(requestMtu(517))
        .enqueue()
}

3.1.3 onServicesInvalidated()

기기와 disconnect 될때 호출되는 메소드로 보인다.
characteristic 멤버변수 등 자원 해제할 때 쓰면 된다.

override fun onServicesInvalidated() {
    myRxCharacteristic = null
    myTxCharacteristic = null
    ...
}

3.2 데이터 수신

이제 데이터를 수신받을 차례인데, 아무리 찾아도 onCharacteristicChange()와 비슷하게 생긴 메소드가 보이질 않아서 찾는데만 몇시간 쓴것같다 ㅡㅡ
API 문서좀 만들어놓지;;

아무튼 데이터를 수신하려면 위 initlalize()에서 setNotificationCallback() 메소드 콜백을 통해 데이터를 수신할 수 있다..

setNotificationCallback 메소드를 통해 notify callback을 받고싶은 characteristic을 넘겨주고, with 람다를 통해 넘어오는 device와 data를 통해 변경된 값을 수신할 수 있다.

3.3 데이터 송신

특정 characteristic에 데이터를 쓰고싶다면, writeCharacteristic 메소드를 사용하면 된다.
MyBleManager 내부에 래핑하는 메소드로 따로 만들어도 되고, 외부에서 직접 호출해서 써도 된다.

4. 마무리

API 문서가 하나도 없어서 답답해서 적어봤다. 추가로 더 적을거 생기면 추가할 예정.

profile
고인물이 되고싶다

0개의 댓글

관련 채용 정보