📘

flutter_nearby_connections で Bluetooth 通信

2022/04/22に公開

Bluetooth で PvP(対人戦)を作った

少し前に電卓騎士というキャラが対戦する電卓アプリをリリースしました。PvP 機能として Bluetooth 通信を行なっています。その際に利用したライブラリが flutter_nearby_connections というライブラリです。

対戦画面

flutter_nearby_connections

それでは flutter_nearby_connections の解説をします。

DeviceType

適当に DeviceType を定義します。
advertiserbrowser は今回 1:1 で接続します。 flutter_nearby_connections 自体は 1:N とかも可能です。

enum ConnectionDeviceType {
  advertiser,
  browser
}

NearbyService

NearbyService は Bluetooth 接続を行う Service です。

1.初期化

初期化はサービス名(任意の名前)とデバイス情報と接続方法を指定します。

// NearbyService の生成.
_nearbyService = NearbyService();

// deviceName の取得.
String devInfo = '';
final deviceInfoPlugin = DeviceInfoPlugin();
if (Platform.isAndroid) {
  final androidInfo = await deviceInfoPlugin.androidInfo;
  devInfo = androidInfo.model;
} else if (Platform.isIOS) {
  final iosInfo = await deviceInfoPlugin.iosInfo;
  devInfo = iosInfo.localizedModel;
}

_nearbyService?.init(
  serviceType: SERVICE_NAME,
  deviceName: devInfo,
  strategy: Strategy.P2P_POINT_TO_POINT, // 今回は 1:1 の接続.
  callback: (isRunning) async {
    if (isRunning) {
      // この辺りはサンプルプログラムそのまま・・・.
      switch (_deviceType) {
        case ConnectionDeviceType.browser:
          await _nearbyService?.stopBrowsingForPeers();
          await Future.delayed(Duration(microseconds: 200));
          await _nearbyService?.startBrowsingForPeers();
          break;
        case ConnectionDeviceType.advertiser:
          await _nearbyService?.stopAdvertisingPeer();
          await _nearbyService?.stopBrowsingForPeers();
          await Future.delayed(Duration(microseconds: 200));
          await _nearbyService?.startAdvertisingPeer();
          await _nearbyService?.startBrowsingForPeers();
          break;
      }
    }
  }
);

2.送信

送信は sendMessage で行います。

void sendCommand(Device device, String data) {
  _nearbyService?.sendMessage(device.deviceId, data);
}

3.イベント検知

初期化したあとは、イベント検知します。

_subscriptions.addAll(
  [
    // 接続可能なデバイスのリストを検知した時(デバイスのリストに変化があったとき).
    _nearbyService!.stateChangedSubscription(callback: (devicesList) {
      devicesList.forEach((element) {
        print(" deviceId: ${element.deviceId} | deviceName: ${element.deviceName} | state: ${element.state}");

        if (Platform.isAndroid) {
          if (element.state == SessionState.connected) {
            _nearbyService?.stopBrowsingForPeers();
          } else {
            _nearbyService?.startBrowsingForPeers();
          }
        }
      });

      final connectedDevice = devicesList.firstWhereOrNull((d) => d.state == SessionState.connected);

      // 各 Subject で状態を送信する.
      _sessionState.add(connectedDevice != null ? SessionState.connected : SessionState.notConnected);
      _devices.add(devicesList);
      _connectedDevice.add(connectedDevice);
    }),

    // データを受信したとき.
    _nearbyService!.dataReceivedSubscription(callback: (data) {
      final String receiveData = data['message'];
      final command = receiveData.split(',');
      command.removeWhere((element) => element.isEmpty);

      if (command.isEmpty) return;
      
      // この辺りは省略しますが、
      // 受信したデータをパースして、パースしたデータを各 Subject で送信します。
    })
  ]
);

4. 接続終了

disConnect は忘れずにしましょう。

void disConnect(Device device) {
  _nearbyService?.disconnectPeer(deviceID: device.deviceId);
}

NearbyService での Bluetooth 通信はこんな感じです。
これぐらいの手数で実装できるので、本当に便利なライブラリだと思います。
ただ、iOS 同士か Android 同士でしか通信できないっぽいです。そこはご注意ください。
それと、 Bluetooth 通信自体がそんなに安定していないっぽいので通信回数を抑える工夫もしたほうがベターだとは思います。

おしまい

今回は Flutter で Bluetooth 通信を行う方法を紹介しました。
Bluetooth 通信は自分で作ると結構面倒なので、本当いいライブラリだと思います!

ご紹介

今回の Tips は私が技術書典で執筆した Flutterで作るアプリとゲームの融合 〜電卓騎士の開発Tips〜 でも記載しています。
この書籍は Flutter でちょっと変な電卓の開発 Tips を色々記載しています。無料ですので良かったら DL してください。

アプリ自体も無料で公開しています。

Discussion