본문으로 바로가기

[Android App] BLE GATT:: [2] 서비스 리스트 출력하기

category Android_app 2023. 4. 25. 17:57

BLE GATT:: [1] 번 글 연속 강의  ==> [1]번 글 링크는 마지막에 넣었습니다.

 : 이번에는 Gatt Server 와  연결이 수립된후  서비스 리스트를 검색해 화면에 출력을 해보겠습니다. 

    연결이 완료된지는 BluetoothGattCallback 의 onConnectionStateChage() 함수로 확인할수 있습니다.

private val mGattCallback = object :BluetoothGattCallback() {
    override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {
        super.onConnectionStateChange(gatt, status, newState)
        when(newState){
            BluetoothProfile.STATE_CONNECTED -> {  <--- 요기
                Log.d(TAG,"Connected to GATT server")
                ~~ 중략 ~~
            }
        }
    }
}

 

목차

      ▶ BluetoothGatt.discoverServices()  호출 코드 추가

         : 연결완료된 시점에 호출코드를 넣어주고  onServiceDiscovered() callback을 기다립니다.

    private var mBtGatt :BluetoothGatt? = null
    private val mGattCallback = object :BluetoothGattCallback() {
        @SuppressLint("MissingPermission")
        override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {
            super.onConnectionStateChange(gatt, status, newState)
            when(newState){
                BluetoothProfile.STATE_CONNECTED -> {
                    ~~ 중략 ~~
                    // Attempt to start service discovery
                    mBtGatt!!.discoverServices()  <----- 요기
                }
                ~~ 중략 ~~
            }
        }
    
        override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
            super.onServicesDiscovered(gatt, status)
            <---------요기
        }
    }

      

      ▶ 서비스 리스트 검색은 Service 객체에서 작성하고,  완료시 Broadcast 메시지를  전송을 합니다.

    val ACTION_GATT_DISCONNECTED = "com.example.test.ACTION_GATT_DISCONNECTED"
    
    private val mGattCallback = object :BluetoothGattCallback() {       
        override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
            super.onServicesDiscovered(gatt, status)
            Log.d(TAG,"Services is discovered.")
            val intent = Intent(ACTION_GATT_SERVICE_DISCOVERED)
            sendBroadcast(intent)
        }
    }

     

      ▶ Activity 의 onResume() 함수 안의 registerRecevier() 함수에 broadcast 메시지 필터를 추가해 줍니다.

        override fun onResume() {
            ~~ 중략 ~~
            val filter = IntentFilter()
            ~~ 중략 ~~
            filter.addAction(BluetoothLeService.ACTION_GATT_SERVICE_DISCOVERED)
            registerReceiver(mGattUpdateReceiver,filter)
        }

     

      ▶ BroadcastReceiver 객체의 onReceive() 함수 안에 action 추가 및 List<BluetoothGattService> 가져오기

    private var bluetoothLeService :BluetoothLeService?= null
    private var mBtGattServices: List<BluetoothGattService>? = null
    
    private val mGattUpdateReceiver = object :BroadcastReceiver() {
        override fun onReceive(p0: Context?, p1: Intent?) {
            val action =p1!!.action
            when(action){
                ~~ 중략 ~~
                BluetoothLeService.ACTION_GATT_SERVICE_DISCOVERED -> {
                    mBtGattServices= bluetoothLeService!!.getSupportedGattServices()
                    mBtGattServices!!.forEach {
                        Log.d(TAG,"Service = ${it.uuid.toString()}")
                    }
                }
            }
        }
    }

     

      ▶ 화면표시를 위한 viewModel 클래스에 속성 및 메서드  추가하기

    class MainViewModel: ViewModel() {
        private val _serviceDiscoveryComplete = MutableLiveData<Int>(0)
        val serviceDiscoveryComplete:LiveData<Int> = _serviceDiscoveryComplete
        fun setServiceDiscoveryComplete(){
            _serviceDiscoveryComplete.value =1
        }
    
        fun clearServiceDiscoveryComplete(){
            _serviceDiscoveryComplete.value =0
        }
    }

     

      ▶ 서비스 검색완료시 setServiceDiscoveryComplete() 메서드 삽입

    val mainViewModel:MainViewModel by viewModels()
    ~~ 중략~~
    private val mGattUpdateReceiver = object :BroadcastReceiver() {
        override fun onReceive(p0: Context?, p1: Intent?) {
            val action =p1!!.action
            when(action){
                ~~ 중략 ~~
                BluetoothLeService.ACTION_GATT_SERVICE_DISCOVERED -> {
                    mBtGattServices= bluetoothLeService!!.getSupportedGattServices()
                    mainViewModel.setServiceDiscoveryComplete()
                }
            }
        }
    }

     

     ▶ 서비스리스트 출력 Composable 함수 작성

    @Composable
    fun DisplayServiceList(){
        val serviceUpdate = mainViewModel.serviceDiscoveryComplete.observeAsState()
        if(serviceUpdate.value ==1) {
            Spacer(modifier = Modifier.size(50.dp))
            Text("Service List")
            Column{
               mBtGattServices!!.forEach {
                   Text("   " +it.uuid.toString(), fontSize = 12.sp )
                   Spacer(modifier = Modifier.size(10.dp))
               }
           }
        }
    }

     

     < 결과 영상> 

     

    < 정리>

      1> GATT Server 연결완료시 서비스 검색하기

         → BluetoothGatt.discoverServices()

     

      2> 서비스 검색완료 Callback 받으면 Activity 로 메시지 전송하기

         → sendBroadcast(...)

          registerReceiver(...)

          BroadcastReceiver::onReceive() {...}

     

      3>  화면에 서비스 리스트 출력하기

          viewModel() 변수추가

          @Composable 함수 추가

     

     

     ▶  BLE GATT::[1] 번 글 링크

    https://leevisual.tistory.com/224

     

    [Android App] BLE GATT:: [1] 연결시 코드 분석하기 (거꾸로 생각하기)

    : 안드로이드 블루투스 통신을 마지막단에서 반대로 분석을 해 봤습니다. Bluetooth LE 장치와 스마트폰사이에 마지막 단인 Gatt 통신을 하기위한 클래스는 BluetoothGatt 이고 이부분을 직접 넣으면서

    leevisual.tistory.com

     

    이글을 읽어주셔서 감사합니다.

     

    반응형