跳到内容
CrossFly 是 100% 开源在 GitHub 关注我们
CrossFlyCrossFly
开始使用

本页面由葡萄牙语机器翻译,可能存在错误。葡萄牙语版本为准。

如何扫描并连接到蓝牙设备(BLE)

目的。 发现附近的蓝牙设备,连接 到其中一个并交换数据 —— 通过流(Classic/SPP)或通过 GATT 特征(BLE:读取、写入、接收通知)。

⚠️ 诚实说明(使用前请阅读)

在 core 模块 中,BLE 层是一个 基于内存缓存的骨架,而不是真正的射频:

  • GattCharacteristic.read() 返回的是 缓存中的值(CompletableFuture.completedFuture(value)),而不是从硬件读取。
  • GattCharacteristic.write(byte[]) 只是把值 保存 在本地。
  • enableNotifications(...) 注册 了监听器,但触发数据的是 notifyValueChanged(...)。
  • BluetoothDevice.discoverServices(...) 在 core 中返回 空列表。

真正的射频(真实的扫描/连接/GATT)由 平台启动器 (Android/iOS)提供。请将下面的代码视为 公共 API;实际行为取决于 应用运行所在的启动器。

使用的 API

  • BluetoothManager.getInstance() throws IOException — 单例。
  • scanForDevices(long duration, TimeUnit unit, ScanCallback cb) — 异步发现;ScanCallback.onSuccess(List<BluetoothDevice>) / onError(String)。
  • connect(BluetoothDevice device, ConnectionCallback cb) — 异步连接;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()。

完整示例(复制、粘贴并运行)

记住上面的诚实说明: 在 core 模块中,BLE 层是一个 基于内存缓存的 骨架 —— 真正的射频来自平台启动器(Android/iOS)。下面的示例是 公共 API;实际行为取决于应用运行所在的启动器。

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

/** 可执行的主界面。将 launcher 指向此类(classname)并运行: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();

            // 扫描(回调在 paint thread 之外 → 操作 UI 时用 onUI)
            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");   // 蓝牙系统不可用
         }
      });
      add(LAY_AUTO, acao);
   }
}

下面的片段只展示 核心部分。要运行它,请把它放进上面的 MainWindow 骨架里。

最小片段

// 已在源码验证: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) 扫描(回调在 paint thread 之外 → 操作 UI 时用 onUI)
   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) 连接并通过流交换数据(Classic/SPP)
   BluetoothDevice alvo = /* 由用户选择 */;
   bt.connect(alvo, new BluetoothManager.ConnectionCallback() {
      public void onSuccess(BluetoothConnection conn) {
         try (conn) {                        // AutoCloseable
            conn.write("PING".getBytes());
            byte[] resposta = conn.read();    // 最多 4096 字节
         } catch (java.io.IOException e) { /* 做相应处理 */ }
      }
      public void onError(String error) {
         Component.onUI(() -> mostrarErro(error));
      }
   });

   // 3) BLE / GATT — 读取并订阅某个特征的通知
   GattCharacteristic ch = /* 从 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) {
   // 蓝牙系统不可用
}

深入了解

这个页面有帮助吗?