Como escanear e conectar a um dispositivo Bluetooth (BLE)
Propósito. Descobrir dispositivos Bluetooth próximos, conectar a um deles e trocar dados — por stream (Classic/SPP) ou por características GATT (BLE: ler, escrever, receber notificações).
⚠️ Nota de honestidade (leia antes de usar)
No módulo
core, a camada BLE é um esqueleto sobre cache em memória, não o rádio real:
GattCharacteristic.read()devolve o valor em cache (CompletableFuture.completedFuture(value)), não uma leitura do hardware.GattCharacteristic.write(byte[])apenas guarda o valor localmente.enableNotifications(...)registra o listener, mas quem dispara os dados énotifyValueChanged(...).BluetoothDevice.discoverServices(...)retorna lista vazia no core.O rádio real (scan/conexão/GATT de verdade) é fornecido pelos launchers de plataforma (Android/iOS). Trate o código abaixo como a API pública; o comportamento efetivo depende do launcher em que a aplicação roda.
APIs usadas
BluetoothManager.getInstance() throws IOException— singleton.scanForDevices(long duration, TimeUnit unit, ScanCallback cb)— descoberta assíncrona;ScanCallback.onSuccess(List<BluetoothDevice>)/onError(String).connect(BluetoothDevice device, ConnectionCallback cb)— conexão assí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().
Exemplo completo (copiar, colar e rodar)
Lembre-se da nota de honestidade acima: no módulo
corea camada BLE é um esqueleto sobre cache em memória — o rádio real vem dos launchers de plataforma (Android/iOS). O exemplo abaixo é a API pública; o comportamento efetivo depende do launcher em que a aplicação roda.
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
/** Tela principal executável. Aponte o launcher (classname) e rode: 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 fora da paint thread → onUI ao tocar na 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 indisponível
}
});
add(LAY_AUTO, acao);
}
}
O trecho abaixo mostra só o miolo. Para rodar, coloque-o no esqueleto
MainWindowacima.
Trecho mínimo
// verificado na fonte: 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 fora da paint thread → onUI ao tocar na 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 trocar dados por stream (Classic/SPP)
BluetoothDevice alvo = /* escolhido pelo usuário */;
bt.connect(alvo, new BluetoothManager.ConnectionCallback() {
public void onSuccess(BluetoothConnection conn) {
try (conn) { // AutoCloseable
conn.write("PING".getBytes());
byte[] resposta = conn.read(); // até 4096 bytes
} catch (java.io.IOException e) { /* trate */ }
}
public void onError(String error) {
Component.onUI(() -> mostrarErro(error));
}
});
// 3) BLE / GATT — ler e assinar notificações de uma característica
GattCharacteristic ch = /* obtida do serviço do 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 indisponível
}
Aprofunde-se
- Guia de Bluetooth/BLE: Bluetooth & BLE