Bluetooth-Geräte suchen

Mit BluetoothAdapter können Sie Bluetooth-Remotegeräte entweder über die Gerätesuche oder durch Abfragen der Liste der gekoppelten Geräte finden.

Sie benötigen die entsprechenden Bluetooth-Berechtigungen und müssen Ihre App für Bluetooth einrichten, bevor Sie Bluetooth-Geräte finden können.

Bei der Gerätesuche wird die Umgebung nach Bluetooth-fähigen Geräten abgesucht und einige Informationen zu jedem Gerät angefordert. Dieser Vorgang wird manchmal als Entdecken, Abfragen oder Scannen bezeichnet. Ein Bluetooth-Gerät in der Nähe antwortet nur dann auf eine Erkennungsanfrage, wenn es derzeit Informationen annimmt, weil es auffindbar ist. Wenn ein Gerät auffindbar ist, antwortet es auf die Suche und gibt einige Informationen wie den Namen, die Klasse und die eindeutige MAC-Adresse des Geräts weiter. Anhand dieser Informationen kann das Gerät, das die Suche durchführt, eine Verbindung zum gefundenen Gerät herstellen.

Da sich über findbare Geräte Informationen zum Standort des Nutzers ermitteln lassen, ist für die Gerätesuche der Standortzugriff erforderlich. Wenn Ihre App auf einem Gerät mit Android 8.0 (API-Level 26) oder höher verwendet wird, sollten Sie stattdessen die Companion Device Manager API verwenden. Diese API führt die Gerätesuche im Namen Ihrer App durch. Ihre App muss also keine Berechtigungen zur Standortermittlung anfordern.

Sobald zum ersten Mal eine Verbindung mit einem Remote-Gerät hergestellt wurde, wird dem Nutzer automatisch eine Kopplungsanfrage angezeigt. Wenn ein Gerät gekoppelt ist, werden die grundlegenden Informationen zu diesem Gerät wie Name, Klasse und MAC-Adresse gespeichert und können mithilfe der Bluetooth APIs gelesen werden. Mit der bekannten MAC-Adresse eines Remote-Geräts kann jederzeit eine Verbindung hergestellt werden, ohne dass eine Suche durchgeführt werden muss, vorausgesetzt, das Gerät befindet sich noch in Reichweite.

Es gibt einen Unterschied zwischen „gekoppelt“ und „verbunden“:

  • Wenn zwei Geräte gekoppelt sind, sind sie sich gegenseitig bewusst, haben einen gemeinsamen Linkschlüssel, der für die Authentifizierung verwendet werden kann, und können eine verschlüsselte Verbindung miteinander herstellen.
  • Wenn die Geräte verbunden sind, teilen sie sich derzeit einen RFCOMM-Kanal und können Daten miteinander übertragen. Die aktuellen Bluetooth APIs erfordern, dass Geräte gekoppelt werden, bevor eine RFCOMM-Verbindung hergestellt werden kann. Die Kopplung erfolgt automatisch, wenn Sie eine verschlüsselte Verbindung mit den Bluetooth APIs herstellen.

In den folgenden Abschnitten wird beschrieben, wie Sie gekoppelte Geräte finden und wie Sie mit der Gerätesuche neue Geräte finden.

Gekoppelte Geräte abfragen

Bevor Sie die Gerätesuche ausführen, sollten Sie die Liste der gekoppelten Geräte abfragen, um festzustellen, ob das gewünschte Gerät bereits bekannt ist. Rufen Sie dazu getBondedDevices() auf. Dies gibt eine Reihe von BluetoothDevice-Objekten zurück, die gekoppelte Geräte darstellen. So können Sie beispielsweise alle gekoppelten Geräte abfragen und den Namen und die MAC-Adresse jedes Geräts abrufen, wie das folgende Code-Snippet zeigt:

Kotlin

val pairedDevices: Set<BluetoothDevice>? = bluetoothAdapter?.bondedDevices
pairedDevices?.forEach { device ->
   val deviceName = device.name
   val deviceHardwareAddress = device.address // MAC address
}

Java

Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices();

if (pairedDevices.size() > 0) {
   // There are paired devices. Get the name and address of each paired device.
   for (BluetoothDevice device : pairedDevices) {
       String deviceName = device.getName();
       String deviceHardwareAddress = device.getAddress(); // MAC address
   }
}

Um eine Verbindung zu einem Bluetooth-Gerät herzustellen, ist vom zugehörigen BluetoothDevice-Objekt nur die MAC-Adresse erforderlich. Sie können sie mit getAddress() abrufen. Weitere Informationen zum Herstellen einer Verbindung finden Sie unter Bluetooth-Geräte verbinden.

Geräte entdecken

Wenn Sie Geräte suchen möchten, rufen Sie startDiscovery() auf. Der Vorgang ist asynchron und gibt einen booleschen Wert zurück, der angibt, ob die Suche erfolgreich gestartet wurde. Die Suche umfasst in der Regel einen Abfragescan von etwa 12 Sekunden, gefolgt von einem Seitenscan jedes gefundenen Geräts, um den Bluetooth-Namen abzurufen.

Damit Ihre App Informationen zu jedem erkannten Gerät erhält, muss sie einen BroadcastReceiver für die ACTION_FOUND-Intent registrieren. Das System sendet diesen Intent für jedes Gerät. Der Intent enthält die zusätzlichen Felder EXTRA_DEVICE und EXTRA_CLASS, die jeweils ein BluetoothDevice und ein BluetoothClass enthalten. Das folgende Code-Snippet zeigt, wie Sie sich registrieren können, um die Übertragung zu verarbeiten, wenn Geräte gefunden werden:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
   ...

   // Register for broadcasts when a device is discovered.
   val filter = IntentFilter(BluetoothDevice.ACTION_FOUND)
   registerReceiver(receiver, filter)
}

// Create a BroadcastReceiver for ACTION_FOUND.
private val receiver = object : BroadcastReceiver() {

   override fun onReceive(context: Context, intent: Intent) {
       val action: String = intent.action
       when(action) {
           BluetoothDevice.ACTION_FOUND -> {
               // Discovery has found a device. Get the BluetoothDevice
               // object and its info from the Intent.
               val device: BluetoothDevice =
                       intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)
               val deviceName = device.name
               val deviceHardwareAddress = device.address // MAC address
           }
       }
   }
}

override fun onDestroy() {
   super.onDestroy()
   ...

   // Don't forget to unregister the ACTION_FOUND receiver.
   unregisterReceiver(receiver)
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
   ...

   // Register for broadcasts when a device is discovered.
   IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
   registerReceiver(receiver, filter);
}

// Create a BroadcastReceiver for ACTION_FOUND.
private final BroadcastReceiver receiver = new BroadcastReceiver() {
   public void onReceive(Context context, Intent intent) {
       String action = intent.getAction();
       if (BluetoothDevice.ACTION_FOUND.equals(action)) {
           // Discovery has found a device. Get the BluetoothDevice
           // object and its info from the Intent.
           BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
           String deviceName = device.getName();
           String deviceHardwareAddress = device.getAddress(); // MAC address
       }
   }
};

@Override
protected void onDestroy() {
   super.onDestroy();
   ...

   // Don't forget to unregister the ACTION_FOUND receiver.
   unregisterReceiver(receiver);
}

Wenn Sie eine Verbindung zu einem Bluetooth-Gerät herstellen möchten, rufen Sie getAddress() auf dem BluetoothDevice auf, um die zugehörige MAC-Adresse abzurufen.

Sichtbarkeit erhöhen

Damit das lokale Gerät für andere Geräte sichtbar ist, rufen Sie startActivityForResult(Intent, int) mit der ACTION_REQUEST_DISCOVERABLE-Intent auf. Dadurch wird eine Anfrage gesendet, um den Sichtbarkeitsmodus des Systems zu aktivieren, ohne dass Sie die Einstellungen öffnen müssen, was Ihre eigene App beenden würde. Standardmäßig ist das Gerät zwei Minuten lang sichtbar. Sie können eine andere Dauer von bis zu fünf Minuten festlegen, indem Sie EXTRA_DISCOVERABLE_DURATION hinzufügen.

Im folgenden Code-Snippet wird festgelegt, dass das Gerät fünf Minuten lang sichtbar ist:

Kotlin

val requestCode = 1;
val discoverableIntent: Intent = Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE).apply {
   putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300)
}
startActivityForResult(discoverableIntent, requestCode)

Java

int requestCode = 1;
Intent discoverableIntent =
       new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivityForResult(discoverableIntent, requestCode);


Abbildung 2:Dialogfeld zum Aktivieren der Sichtbarkeit.

Es wird ein Dialogfeld angezeigt, in dem der Nutzer um Erlaubnis gebeten wird, das Gerät sichtbar zu machen (siehe Abbildung 2). Wenn der Nutzer „Zulassen“ anklickt, ist das Gerät für den angegebenen Zeitraum sichtbar. Ihre Aktivität erhält dann einen Aufruf des onActivityResult()-Callbacks mit dem Ergebniscode, der der Dauer entspricht, während der das Gerät auffindbar ist. Wenn der Nutzer „Ablehnen“ ausgewählt hat oder ein Fehler aufgetreten ist, lautet der Ergebniscode RESULT_CANCELED.

Das Gerät bleibt während der festgelegten Zeit im Modus „Auffindbar“. Wenn Sie benachrichtigt werden möchten, wenn sich der Modus für die Sichtbarkeit geändert hat, registrieren Sie eine BroadcastReceiver für die Absicht ACTION_SCAN_MODE_CHANGED. Dieser Intent enthält die zusätzlichen Felder EXTRA_SCAN_MODE und EXTRA_PREVIOUS_SCAN_MODE, die den neuen bzw. alten Scanmodus angeben. Folgende Werte sind für jedes Extra möglich:

SCAN_MODE_CONNECTABLE_DISCOVERABLE
Das Gerät ist im Sichtbarkeitsmodus.
SCAN_MODE_CONNECTABLE
Das Gerät ist nicht im Sichtbarkeitsmodus, kann aber trotzdem Verbindungen empfangen.
SCAN_MODE_NONE
Das Gerät befindet sich nicht im Sichtbarkeitsmodus und kann keine Verbindungen empfangen.

Wenn Sie die Verbindung zu einem Remotegerät herstellen, müssen Sie die Geräteerkennung nicht aktivieren. Die Sichtbarkeit muss nur aktiviert werden, wenn Ihre App einen Server-Socket hosten soll, der eingehende Verbindungen akzeptiert. Remote-Geräte müssen andere Geräte erkennen können, bevor sie Verbindungen zu diesen Geräten herstellen können.