본문 바로가기

[Flutter] 플러터 블루투스 연결 구현 #4 플러터를 사용한 블루투스 연결

I'm 영서 2023. 3. 6.
반응형

1. 블루투스를 연결하기 위해 필요한것.

   - 블루투스 용어정리

   - 블루투스 라이브러리 

2. 블루투스 연결

    - 아두이노 코드분석

    - 모바일(플러터)에서 확인

3. 데이터 송수신

 

오랜만에 들어가보니 상당히 많이 변했다. 1.30.7 기준 연결방법은 아래에!

 

2023.12.26 - [Study/Flutter] - [Flutter] Flutter blue Plus 1.30.7 버전 기준 연결 예제

 

[Flutter] Flutter blue Plus 1.30.7 버전 기준 연결 예제

안드로이드 권한 업데이트로 인해 블루투스가 잘 안되서 보니 업데이트 많이했음. 따라서 최신 버전에 맞추어 예제를 작성함. (이걸 쓰는 도중에도 1.30.8에서 1.31.3 으로 올랏다;) 내가 사용한 버

theplace.tistory.com

 

 

지금까지 정리를 조금 해보자

라이브러리는 flutter_blue_plus 를 사용하기로 결정했다.

아두이노에서 서비스 UUID캐릭터리스틱 UUID 그리고 Write시 어떻게 송수신 해야하는지를 알았다. 

 

이제 플러터에서 기본적인 사용법에 대해서는 readme에 있다. 

https://pub.dev/packages/flutter_blue_plus

 

flutter_blue_plus | Flutter Package

Flutter plugin for connecting and communicationg with Bluetooth Low Energy devices, on Android and iOS

pub.dev

블루투스 사용 단계는 간략하게 나누면

  1. scan
  2. connect
  3. discorver services
  4. data transfer (write, notify, read 등)

 

이정도로 나눌수 있다.

 

한 단계씩 수행해보자

 

**전체 코드는 최하단에 작성해두었다.

 

scan

스캔 단계에서는 플러터에서 블루투스기기를 스캔하면 되는데  

스캔 단계는

 

1. startScan, stopScan 함수 작성

 void startScan() async {
    setState(() {
      isScanning = true;
      scanResults.clear();
    });
    try {
      flutterBlue.scan().listen((scanResult) {
        setState(() {
          scanResults.add(scanResult);
        });
      });
    } catch (e) {
      print('error : ${e.toString()}');
    }
  }

  Future<void> stopScan() async {
    setState(() {
      isScanning = false;
    });
    await flutterBlue.stopScan();
  }

2. 버튼을 클릭하여 혹은 다른 방법으로든 StartScan() 함수 호출.

ElevatedButton(
  onPressed: isScanning ? null : startScan,
  child: Text(isScanning ? 'Scanning...' : 'Scan'),
),

Eleveated Button 을 사용해서 호출하였다.

RefreshIndicator(
    onRefresh: () => stopScan().then((_) => startScan()),
    child:
)

refreshIndicator를 사용해 리스트 새로고침 구현하였음

 

3. scanList를 뿌려준다.

Scan결과를 가져오고 가져온 결과값을 ListView를 사용해 그려주었다.

ListView.builder(
  itemCount: scanResults.length,
  itemBuilder: (BuildContext context, int index) {
    var scanResult = scanResults[index];
    if (scanResult.device.name.isNotEmpty) {
      return Container(
      // .....
      );
    } else {
      return Container();
    }
  },
)

 

4. 뿌려준 리스트중 선택하여 connect한다.

scanResult.device.connect();

 

해당 사항을 전부 구현한 예제 화면

 

 

 

class BluetoothScreen extends StatefulWidget {
  @override
  _BluetoothScreenState createState() => _BluetoothScreenState();
}

class _BluetoothScreenState extends State<BluetoothScreen> {
  FlutterBluePlus flutterBlue = FlutterBluePlus.instance;
  List<BluetoothDevice> connectedDevices = [];
  bool isScanning = false;
  List<ScanResult> scanResults = [];

  @override
  void initState() {
    super.initState();
    // TODO: Connect to previously connected device (if any)
    getConnectedDevice();
  }

  void getConnectedDevice() async {
    connectedDevices = await flutterBlue.connectedDevices;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Bluetooth Screen'),
      ),
      body: Column(
        children: [
          Flexible(
            flex: 1,
            child: ConnectedDevices(),
          ),
          Flexible(
            flex: 4,
            child: ScanningDevices(),
          ),
        ],
      ),
    );
  }

  Widget ConnectedDevices() {
    return Column(
      children: [
        Container(
          alignment: Alignment.centerLeft,
          child: const Text(
            'Connected Devices',
            style: TextStyle(
                color: Colors.Blue[300], fontSize: 18, fontWeight: FontWeight.w700),
          ),
        ),
        Expanded(
          child: ListView.builder(
            itemCount: connectedDevices.length,
            itemBuilder: (context, index) {
              var connectedDevice = connectedDevices[index];
              return Container(
                margin:
                    const EdgeInsets.symmetric(horizontal: 5.0, vertical: 5.0),
                height: 100,
                decoration: BoxDecoration(
                  borderRadius: BorderRadius.circular(20),
                  color: Colors.lightBlue[100],
                ),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: [
                    const Icon(Icons.bluetooth),
                    const SizedBox(width: 8),
                    Column(
                      crossAxisAlignment: CrossAxisAlignment.center,
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        Text(
                          connectedDevice!.name,
                          style: const TextStyle(
                            fontSize: 14,
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                        const SizedBox(height: 4),
                        Text(
                          'ID : [${connectedDevice!.id.toString()}]',
                          style: const TextStyle(
                            fontSize: 10,
                          ),
                        ),
                      ],
                    ),
                    const SizedBox(
                      width: 20,
                    ),
                    Column(
                      children: [
                        ElevatedButton(
                          style: ButtonStyle(
                            backgroundColor:
                                MaterialStateProperty.all(Colors.lightBlue[50]),
                          ),
                          onPressed: () {
                            // TODO: Connect to selected device
                            print('ID [ ${connectedDevice!.id}]');
                            print('Name [ ${connectedDevice!.name}]');
                            connectedDevice!.disconnect();
                            setState(() {
                              connectedDevices.remove(connectedDevice);
                            });
                          },
                          child: const Text('disConnect'),
                        ),
                        ElevatedButton(
                          style: ButtonStyle(
                            backgroundColor: MaterialStateProperty.all(
                                Colors.orangeAccent[700]),
                          ),
                          onPressed: () {
                            Navigator.push(
                              context,
                              MaterialPageRoute(
                                  builder: (context) =>
                                      DeviceScreen(device: connectedDevice)),
                            );
                          },
                          child: const Text('Device..'),
                        )
                      ],
                    ),
                  ],
                ),
              );
            },
          ),
        ),
      ],
    );
  }

  Widget ScanningDevices() {
    return Column(
      children: [
        Row(
          children: [
            ElevatedButton(
              onPressed: isScanning ? null : startScan,
              child: Text(isScanning ? 'Scanning...' : 'Scan'),
            ),
            ElevatedButton(
              onPressed: stopScan,
              child: Text('Stop!'),
            ),
          ],
        ),
        Container(
          alignment: Alignment.centerLeft,
          child: const Text(
            'Scanning Devices',
            style: TextStyle(
                color: Colors.Blue[300], fontSize: 18, fontWeight: FontWeight.w700),
          ),
        ),
        const SizedBox(height: 10),
        Expanded(
          child: RefreshIndicator(
            onRefresh: () => stopScan().then((_) => startScan()),
            child: ListView.builder(
              itemCount: scanResults.length,
              itemBuilder: (BuildContext context, int index) {
                var scanResult = scanResults[index];
                if (scanResult.device.name.isNotEmpty) {
                  return Container(
                    margin: const EdgeInsets.symmetric(
                        horizontal: 5.0, vertical: 5.0),
                    height: 100,
                    decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(20),
                      color: Colors.grey[200],
                    ),
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: [
                        const Icon(Icons.bluetooth),
                        const SizedBox(width: 8),
                        Column(
                          crossAxisAlignment: CrossAxisAlignment.center,
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: [
                            Text(
                              scanResult.device.name,
                              style: const TextStyle(
                                fontSize: 14,
                                fontWeight: FontWeight.bold,
                              ),
                            ),
                            const SizedBox(height: 4),
                            Text(
                              'ID : [${scanResult.device.id.toString()}]',
                              style: const TextStyle(
                                fontSize: 10,
                              ),
                            ),
                          ],
                        ),
                        const SizedBox(
                          width: 20,
                        ),
                        ElevatedButton(
                          style: ButtonStyle(
                              backgroundColor: MaterialStateProperty.all(
                                  Colors.lightBlue[50]),
                              foregroundColor:
                                  MaterialStateProperty.all(Colors.black)),
                          onPressed: () {
                            // TODO: Connect to selected device
                            scanResult.device.connect();
                            print('ID [ ${scanResult.device.id}]');
                            print('Name [ ${scanResult.device.name}]');

                            setState(() {
                              scanResults.remove(scanResult.device);
                              connectedDevices.add(scanResult.device);
                            });
                          },
                          child: const Text('Connect'),
                        ),
                      ],
                    ),
                  );
                } else {
                  return Container();
                }
              },
            ),
          ),
        ),
      ],
    );
  }

  void startScan() async {
    setState(() {
      isScanning = true;
      scanResults.clear();
    });
    try {
      flutterBlue.scan().listen((scanResult) {
        setState(() {
          scanResults.add(scanResult);
        });
      });
    } catch (e) {
      print('error : ${e.toString()}');
    }
  }

  Future<void> stopScan() async {
    setState(() {
      isScanning = false;
    });
    await flutterBlue.stopScan();
  }
}
 
반응형

댓글