Saltar al contenido
CrossFly es 100% open sourceSíguenos en GitHub
CrossFlyCrossFly
Empezar

Esta página fue traducida automáticamente del portugués y puede contener errores. La versión en portugués es la canónica.

Cómo escanear y conectar a un dispositivo Bluetooth (BLE)

Propósito. Descubrir dispositivos Bluetooth cercanos, conectar a uno de ellos e intercambiar datos — por stream (Classic/SPP) o por características GATT (BLE: leer, escribir, recibir notificaciones).

⚠️ Nota de honestidad (léela antes de usar)

En el módulo core, la capa BLE es un esqueleto sobre caché en memoria, no la radio real:

  • GattCharacteristic.read() devuelve el valor en caché (CompletableFuture.completedFuture(value)), no una lectura del hardware.
  • GattCharacteristic.write(byte[]) solo guarda el valor localmente.
  • enableNotifications(...) registra el listener, pero quien dispara los datos es notifyValueChanged(...).
  • BluetoothDevice.discoverServices(...) devuelve lista vacía en el core.

La radio real (scan/conexión/GATT de verdad) la proveen los launchers de plataforma (Android/iOS). Trata el código de abajo como la API pública; el comportamiento efectivo depende del launcher en el que se ejecute la aplicación.

APIs usadas

  • BluetoothManager.getInstance() throws IOException — singleton.
  • scanForDevices(long duration, TimeUnit unit, ScanCallback cb) — descubrimiento asíncrono; ScanCallback.onSuccess(List<BluetoothDevice>) / onError(String).
  • connect(BluetoothDevice device, ConnectionCallback cb) — conexión asíncrona; ConnectionCallback.onSuccess(BluetoothConnection) / onError(String).
  • BluetoothConnection (AutoCloseable) — read() / read(int max) → byte[]; write(byte[]) / write(String) → int.
  • GATT: GattCharacteristic.read() → CompletableFuture<byte[]>; write(byte[]) → CompletableFuture<Void>; enableNotifications(Consumer<byte[]>) → CompletableFuture<Void>.
  • BluetoothManager.isBluetoothEnabled(), getPairedDevices(...), getLocalDevice().

Ejemplo completo (copiar, pegar y ejecutar)

Recuerda la nota de honestidad de arriba: en el módulo core la capa BLE es un esqueleto sobre caché en memoria — la radio real viene de los launchers de plataforma (Android/iOS). El ejemplo de abajo es la API pública; el comportamiento efectivo depende del launcher en el que se ejecute la aplicación.

package com.exemplo;

import java.util.concurrent.*;              // TimeUnit
import dev.crossfly.ui.*;                   // Window, Component, Button, Label
import dev.crossfly.ui.layout.*;            // VerticalLayout
import dev.crossfly.device.bluetooth.*;     // BluetoothManager, BluetoothDevice

/** Pantalla principal ejecutable. Apunta el launcher (classname) y corre: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      Label resultado = new Label("");
      add(LAY_AUTO, resultado);

      Button acao = new Button("Escanear Bluetooth");
      acao.onAction(c ->
      {
         try
         {
            BluetoothManager bt = BluetoothManager.getInstance();

            // Escanear (callbacks fuera de la paint thread → onUI al tocar la UI)
            bt.scanForDevices(10, TimeUnit.SECONDS, new BluetoothManager.ScanCallback()
            {
               public void onSuccess(java.util.List<BluetoothDevice> devices)
               {
                  Component.onUI(() -> resultado.setText("Encontrados: " + devices.size()));
               }
               public void onError(String error)
               {
                  Component.onUI(() -> resultado.setText("Erro: " + error));
               }
            });
         }
         catch (java.io.IOException e)
         {
            resultado.setText("Bluetooth indisponível");   // sistema Bluetooth no disponible
         }
      });
      add(LAY_AUTO, acao);
   }
}

El fragmento de abajo muestra solo el núcleo. Para ejecutarlo, colócalo en el esqueleto MainWindow de arriba.

Fragmento mínimo

// verificado en la fuente: BluetoothManager.java (getInstance, scanForDevices, connect); BluetoothConnection.java (read/write); GattCharacteristic.java (read/write/enableNotifications)
import java.util.concurrent.*;             // TimeUnit
import dev.crossfly.device.bluetooth.*;    // BluetoothManager, BluetoothDevice, BluetoothConnection, GattCharacteristic
import dev.crossfly.ui.*;                  // Component (onUI)

try {
   BluetoothManager bt = BluetoothManager.getInstance();

   // 1) Escanear (callbacks fuera de la paint thread → onUI al tocar la UI)
   bt.scanForDevices(10, TimeUnit.SECONDS, new BluetoothManager.ScanCallback() {
      public void onSuccess(java.util.List<BluetoothDevice> devices) {
         Component.onUI(() -> listarDispositivos(devices));
      }
      public void onError(String error) {
         Component.onUI(() -> mostrarErro(error));
      }
   });

   // 2) Conectar e intercambiar datos por stream (Classic/SPP)
   BluetoothDevice alvo = /* elegido por el usuario */;
   bt.connect(alvo, new BluetoothManager.ConnectionCallback() {
      public void onSuccess(BluetoothConnection conn) {
         try (conn) {                        // AutoCloseable
            conn.write("PING".getBytes());
            byte[] resposta = conn.read();    // hasta 4096 bytes
         } catch (java.io.IOException e) { /* maneja */ }
      }
      public void onError(String error) {
         Component.onUI(() -> mostrarErro(error));
      }
   });

   // 3) BLE / GATT — leer y suscribir notificaciones de una característica
   GattCharacteristic ch = /* obtenida del servicio del device */;
   ch.enableNotifications(data ->
      Component.onUI(() -> atualizarValor(data)));   // Consumer<byte[]>
   ch.read().thenAccept(valor ->
      Component.onUI(() -> mostrarValor(valor)));     // CompletableFuture<byte[]>
} catch (java.io.IOException e) {
   // sistema Bluetooth no disponible
}

Profundiza

¿Te resultó útil esta página?