0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AndoridのBluetooth通信

Posted at

1. GATT

1.1 説明

GATT (Generic Attribute Profile) は、BLE (Bluetooth Low Energy) デバイス間でデータをやり取りするためのプロファイルです。

  • GATTサーバー: データを保持し、クライアントからの要求に応じる役割(Peripheral)
  • GATTクライアント: データを読み書きする側の役割(Central)
  • サービス(Service)とキャラクタリスティック(Characteristic)を中心に通信が行われます。

1.2 サンプルコード

  • GATTサーバーのセットアップ例

    val gattServer = bluetoothManager.openGattServer(context, gattServerCallback)
    
    val service = BluetoothGattService(
        UUID.fromString("0000180D-0000-1000-8000-00805f9b34fb"),
        BluetoothGattService.SERVICE_TYPE_PRIMARY
    )
    
    val characteristic = BluetoothGattCharacteristic(
        UUID.fromString("00002A37-0000-1000-8000-00805f9b34fb"),
        BluetoothGattCharacteristic.PROPERTY_READ or BluetoothGattCharacteristic.PROPERTY_NOTIFY,
        BluetoothGattCharacteristic.PERMISSION_READ
    )
    
    service.addCharacteristic(characteristic)
    gattServer.addService(service)
    
  • クライアント側の接続例

    val device = bluetoothAdapter.getRemoteDevice(remoteDeviceAddress)
    val gatt = device.connectGatt(context, false, gattCallback)
    

1.3 Macアドレスが変更される件

  • Android 6.0以降、BLEスキャン時に取得できるMacアドレスはプライバシー保護のために一定時間ごとにランダム化される場合があります。
  • これにより、スキャン結果のMacアドレスが実際の固定アドレスとは異なることがあります。
  • アプリでは、デバイス名やサービスUUIDなど、他の情報も併用して対象デバイスを特定する必要があります。

1.4 AdvertiseSettingsに関する注意点

  • Peripheralとしてアドバタイズする際、AdvertiseSettings で動作モードや電力レベルなどを調整できます。

  • 高速接続を優先する場合は ADVERTISE_MODE_LOW_LATENCY を使用しますが、バッテリー消費が増えます。

  • 通常はバランス型の ADVERTISE_MODE_BALANCED が推奨されます。

    val settings = AdvertiseSettings.Builder()
        .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
        .setConnectable(true)
        .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
        .build()
    

1.5 serviceUuidとcharacteristicUuid

  • BLE通信ではサービスとCharacteristicはUUIDで識別されます。
  • serviceUuid: サービス単位の識別子
  • characteristicUuid: サービス内の具体的なデータ項目を示す識別子
  • Androidでは UUID.fromString() を用いて文字列からUUIDを生成します。

以下は、例として「Heart Rate Service(心拍数サービス)」のUUIDです。

  • Heart Rate Service UUID
    0000180D-0000-1000-8000-00805f9b34fb

  • Heart Rate Measurement Characteristic UUID
    00002A37-0000-1000-8000-00805f9b34fb

val serviceUuid = UUID.fromString("0000180D-0000-1000-8000-00805f9b34fb")
val characteristicUuid = UUID.fromString("00002A37-0000-1000-8000-00805f9b34fb")

2. RFCOMM ServerとClient

2.1 説明

RFCOMMは、Bluetoothで「シリアルポートエミュレーション」を提供するプロトコルです。

  • SPP(Serial Port Profile) とも呼ばれ、従来の有線シリアル通信の置き換えとして利用されます。
  • GATTよりも単純な構造で、接続は「ソケット通信」を利用します。
  • SPPに対応したデバイス同士でデータの送受信を行う用途に向いています。

2.2 サンプルコード

  • RFCOMMサーバーのセットアップ例

    val serverSocket = bluetoothAdapter.listenUsingRfcommWithServiceRecord(
        "MyAppService",
        UUID.fromString("00001101-0000-1000-8000-00805F9B34FB") // SPPの一般的なUUID
    )
    
    val socket = serverSocket.accept() // クライアントからの接続を待機
    val inputStream = socket.inputStream
    val outputStream = socket.outputStream
    
  • クライアント側の接続例

    val device = bluetoothAdapter.getRemoteDevice(remoteDeviceAddress)
    val socket = device.createRfcommSocketToServiceRecord(
        UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")
    )
    socket.connect()
    val inputStream = socket.inputStream
    val outputStream = socket.outputStream
    

2.3 注意点

  • SPPは古い仕様ですが、通信が常時接続型になるためバッテリー消費は大きくなる傾向があります。
  • サーバーとクライアントが同じUUIDを使わないと接続ができません。通常はSPPの標準UUID (00001101-0000-1000-8000-00805F9B34FB) が利用されますが、アプリ専用のUUIDを使うことも可能です。
  • 接続の信頼性(接続失敗・切断など)のために、再接続処理を適切に実装することが重要です。
  • 使用後は必ず socket.close() を呼び出して、リソースを解放することを忘れないようにしましょう。

3. その他の大事なこと

3.1 BluetoothAdapterの取得

  • Bluetooth接続には、まず BluetoothAdapter を取得する必要があります。
  • BluetoothManager から取得する方法が一般的です。
val bluetoothManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
val bluetoothAdapter = bluetoothManager.adapter
  • 端末のBluetooth機能が有効か確認するには、以下を使用します。
if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled) {
    // Bluetooth未対応または無効
}

3.2 パーミッション

  • Android 11以下: BLUETOOTH, BLUETOOTH_ADMIN, ACCESS_FINE_LOCATION(スキャン時)
  • Android 12以降: BLUETOOTH_CONNECT, BLUETOOTH_SCAN, BLUETOOTH_ADVERTISE(役割に応じて必要)
  • Android 12以降では、Manifestに加えてRuntime Permissionのリクエストも必要です。
if (ContextCompat.checkSelfPermission(context, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) {
    // Runtime Permissionをリクエストする
}

3.3 注意点

  • BLE/GATTとRFCOMM/SPPは通信方式が異なりますが、BluetoothAdapterやパーミッション周りは共通です。
  • socketやGATT接続後は必ず close() を呼び出し、リソース解放を忘れないようにしましょう。

4. 接続前の検証と注意点

  • BLE/GATTやRFCOMMの接続コードをテストする際は、必ずデバイスが接続されていない状態で行うことを確認しましょう。
  • 既に接続済みの状態で同じ接続処理を行うと、APIの戻り値が意図しない動作を示すことがあります。
  • 特に、再接続時やスキャン開始前には close() などでリソースを解放し、クリーンな状態に戻してから実行することが重要です。

まとめ

ちなみに、Bluetoothって「青い歯」って意味ですけど、もしBluetoothの接続に失敗しても、歯医者には行かないでくださいね!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?