在物联网、智能硬件开发中,BLE(Bluetooth Low Energy,低功耗蓝牙)早已成为设备间近距离通信的核心技术——从智能手环、蓝牙温湿度传感器,到工业设备的数据传输,都离不开BLE协议栈的支撑。很多开发者在开发BLE相关项目时,常常陷入“会调用API,但不懂底层逻辑”的困境:明明能实现设备连接,却搞不清GAP和GATT的区别;能读写特征值,却不知道ATT协议在背后扮演的角色;遇到通信卡顿、连接断开等问题,更是无从排查。

本文将从底层到上层,完整拆解BLE核心协议栈的5个核心层级——HCI、L2CAP、ATT、GATT、GAP,讲清每个层级的定位、核心功能和交互逻辑,同时配套iOS(Swift)、安卓(Kotlin)、Flutter三种主流开发语言的实战代码,让你既能理解底层原理,又能快速落地开发,彻底搞懂BLE协议栈的全貌。

一、BLE协议栈整体架构:从底层到上层的层级划分

BLE协议栈采用分层架构设计,遵循“上层依赖下层、下层为上层提供服务”的原则,从下到上依次为:HCI(主机控制器接口)→ L2CAP(逻辑链路控制和适配协议)→ ATT(属性协议)→ GATT(通用属性配置文件)→ GAP(通用访问配置文件)

简单来说,底层(HCI、L2CAP)负责“数据传输的通道和规则”,中间层(ATT)负责“数据的定义和编码”,上层(GATT、GAP)负责“设备的交互逻辑和用户可见的行为”。我们可以用一个形象的比喻理解:协议栈就像快递配送系统——GAP是“快递员和收件人”(负责设备发现、连接),GATT是“快递包裹的分类规则”(负责数据的组织和读写),ATT是“包裹上的标签”(定义数据的属性),L2CAP是“快递运输的路线和规则”(负责数据分片和路由),HCI是“快递中转站”(负责主机和控制器的通信)。

接下来,我们逐一拆解每个层级的核心细节,结合实战场景说明其作用,最后给出三种语言的开发示例。

二、分层拆解:每个层级的核心作用与实战意义

第一层:HCI(Host Controller Interface,主机控制器接口)—— 协议栈的“中转站”

HCI是BLE协议栈的最底层(衔接硬件),核心作用是实现主机(Host,如手机)和控制器(Controller,如蓝牙芯片)之间的通信,将上层协议的指令(如“发起连接”“发送数据”)转换为控制器能识别的硬件指令,同时将控制器的状态(如“连接成功”“数据接收”)反馈给上层协议。

通俗来讲,HCI就像主机和控制器之间的“翻译官”:主机(手机App)发出的是“高层指令”(比如“连接设备A”),HCI会将其翻译成控制器(蓝牙芯片)能理解的“底层指令”;反之,控制器检测到设备连接状态变化后,会通过HCI将“底层状态”翻译成“高层反馈”,传递给上层协议(如GAP、GATT)。

核心特点:

  • 不直接参与数据的传输和解析,仅负责“指令转换”和“状态反馈”;

  • 是硬件和软件的衔接层,不同蓝牙芯片的HCI接口可能不同,但上层协议(GATT、GAP等)完全一致;

  • 开发中无需直接操作HCI(系统已封装),但排查连接失败、数据丢失等问题时,需关注HCI日志(如蓝牙芯片是否正常响应指令)。

第二层:L2CAP(Logical Link Control and Adaptation Protocol,逻辑链路控制和适配协议)—— 数据的“运输通道”

L2CAP位于HCI之上,核心作用是为上层协议提供可靠的数据传输通道,主要负责数据的分片、重组和路由,解决“上层数据长度超过蓝牙硬件传输上限”的问题。

BLE硬件的单次数据传输长度有限(默认27字节,BLE 5.0可扩展到251字节),当上层协议(如ATT)发送的数据超过这个上限时,L2CAP会将数据拆分成多个小数据包,传输到对方设备后,再重组为完整数据;同时,L2CAP还会负责数据的路由,确保不同类型的数据(如连接指令、用户数据)能准确传递到对应的上层协议。

核心特点:

  • 支持数据分片与重组,突破硬件传输长度限制;

  • 提供两种传输模式:面向连接(用于可靠数据传输,如特征值读写)和无连接(用于广播数据,如Beacon广播);

  • 开发中无需直接操作L2CAP(系统已封装),但需注意数据长度限制——若读写的数据超过27字节,需开启“长包传输”(BLE 4.2+支持)。

第三层:ATT(Attribute Protocol,属性协议)—— 数据的“标签定义”

ATT位于L2CAP之上,核心作用是定义数据的属性格式和交互规则,是GATT协议的基础。BLE设备之间的数据交互,本质上是“属性的读写操作”,而ATT协议就负责定义这些属性的结构、类型和访问权限。

ATT协议中,每个属性都有三个核心要素:

  • 属性句柄(Handle):唯一标识一个属性(类似数组下标),上层协议通过句柄定位属性;

  • 属性类型(UUID):定义属性的用途(如“温度数据”“设备名称”),常用的UUID有固定规范(如设备名称UUID为0x2A00);

  • 属性值(Value):实际存储的数据(如温度值25℃、设备名称“Smart Sensor”);

  • 访问权限(Permissions):定义属性的操作权限(如只读、可写、可通知)。

核心特点:

  • ATT协议的交互逻辑非常简单:只有“读属性”“写属性”两种核心操作;

  • 所有GATT服务、特征值,本质上都是ATT属性的组合;

  • 开发中,我们操作GATT特征值时,底层其实是通过ATT协议的“读句柄”“写句柄”实现的。

第四层:GATT(Generic Attribute Profile,通用属性配置文件)—— 数据的“组织规则”

GATT位于ATT之上,核心作用是将ATT属性组织成“服务(Service)”和“特征值(Characteristic)”的结构,让数据的交互更具逻辑性,方便开发者理解和使用。

我们可以把GATT的结构理解为“文件夹-文件”的结构:

  • 服务(Service):一组相关属性的集合(类似文件夹),每个服务有一个唯一的UUID(如“温湿度监测服务”UUID为0x180A);

  • 特征值(Characteristic):服务下的具体数据项(类似文件),每个特征值对应一个ATT属性,包含“特征值UUID”“特征值数据”“访问权限”;

  • 描述符(Descriptor):用于补充特征值的信息(如特征值的单位、范围),也是一种ATT属性(如“温度单位描述符”)。

核心特点:

  • GATT是BLE数据交互的核心,几乎所有BLE设备的通信都基于GATT协议;

  • 设备连接后,需先发现对方的GATT服务和特征值,才能进行数据读写、通知等操作;

  • 开发中,我们最常操作的就是GATT服务和特征值(如读取温湿度特征值、写入控制指令)。

第五层:GAP(Generic Access Profile,通用访问配置文件)—— 设备的“交互入口”

GAP是BLE协议栈的最上层,核心作用是定义设备的对外交互行为,负责设备的发现、连接、配对、广播等用户可见的操作,是设备之间建立通信的“入口”。

GAP协议将BLE设备分为两种角色:

  • 广播者(Advertiser):主动发送广播数据(如设备名称、UUID、信号强度),让其他设备发现自己(如智能传感器、手环);

  • 扫描者(Scanner):主动扫描周围的广播设备,发起连接请求(如手机、平板)。

核心功能:

  • 广播与扫描:广播者发送广播包,扫描者扫描广播包,获取设备基本信息;

  • 连接管理:扫描者发起连接,广播者接受连接,建立BLE连接;

  • 配对与加密:为了保证数据安全,连接后可进行配对(如输入PIN码),对数据进行加密传输;

  • 设备信息展示:定义设备名称、外观、角色等信息,供扫描者识别。

核心特点:

  • GAP是设备之间建立通信的第一步,没有GAP的广播和扫描,就无法建立GATT连接;

  • 开发中,我们首先要实现的就是GAP相关操作(扫描设备、发起连接),再进行GATT数据交互。

三、三种语言实战:GAP/GATT核心操作代码(落地可用)

理解了各层级的核心作用后,我们结合实战场景,给出iOS(Swift)、安卓(Kotlin)、Flutter三种语言的核心代码——实现“扫描BLE设备→发起连接→发现GATT服务和特征值→读写特征值”的完整流程,覆盖GAP和GATT的核心操作(底层HCI、L2CAP、ATT由系统封装,无需手动操作)。

1. iOS(Swift)实战代码(基于CoreBluetooth框架)

iOS中使用CoreBluetooth框架操作BLE,核心是CBPeripheralManager(广播者)和CBCentralManager(扫描者),以下是扫描、连接、读写特征值的完整代码:

import CoreBluetooth

// 扫描者(手机端):负责扫描设备、发起连接、读写特征值
class BLECentralManager: NSObject, CBCentralManagerDelegate, CBPeripheralDelegate {
    private var centralManager: CBCentralManager!
    private var targetPeripheral: CBPeripheral? // 目标设备
    // 目标服务和特征值UUID(根据实际设备修改)
    private let targetServiceUUID = CBUUID(string: "0000180A-0000-1000-8000-00805F9B34FB") // 设备信息服务
    private let targetCharUUID = CBUUID(string: "00002A00-0000-1000-8000-00805F9B34FB") // 设备名称特征值
    
    override init() {
        super.init()
        // 初始化中心管理器(GAP扫描的核心)
        centralManager = CBCentralManager(delegate: self, queue: DispatchQueue.main)
    }
    
    // 中心管理器状态变化(检查蓝牙是否可用)
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        switch central.state {
        case .poweredOn:
            print("蓝牙已开启,开始扫描设备(GAP扫描)")
            // 开始扫描GAP广播的设备,过滤目标服务UUID
            central.scanForPeripherals(withServices: [targetServiceUUID], options: [CBCentralManagerScanOptionAllowDuplicatesKey: false])
        case .poweredOff:
            print("蓝牙已关闭")
        default:
            print("蓝牙状态异常:\(central.state)")
        }
    }
    
    // 发现BLE设备(GAP广播被扫描到)
    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
        print("发现设备:\(peripheral.name ?? "未知设备"),RSSI:\(RSSI)")
        // 过滤目标设备(可根据设备名称、UUID过滤)
        if peripheral.name == "Smart Sensor" {
            targetPeripheral = peripheral
            // 停止扫描,发起连接(GAP连接)
            central.stopScan()
            central.connect(peripheral, options: nil)
        }
    }
    
    // 连接设备成功
    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
        print("设备连接成功,开始发现GATT服务")
        // 设置外设代理,用于发现GATT服务和特征值
        peripheral.delegate = self
        // 发现设备的GATT服务(ATT属性的组织)
        peripheral.discoverServices([targetServiceUUID])
    }
    
    // 发现GATT服务
    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
        guard let services = peripheral.services else { return }
        for service in services {
            print("发现GATT服务:\(service.uuid)")
            // 发现服务下的GATT特征值
            peripheral.discoverCharacteristics([targetCharUUID], for: service)
        }
    }
    
    // 发现GATT特征值
    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
        guard let characteristics = service.characteristics else { return }
        for char in characteristics {
            print("发现GATT特征值:\(char.uuid),权限:\(char.properties)")
            // 读取特征值(底层通过ATT协议读属性)
            if char.uuid == targetCharUUID {
                peripheral.readValue(for: char)
                // 若特征值支持通知,开启通知(实时接收数据)
                if char.properties.contains(.notify) {
                    peripheral.setNotifyValue(true, for: char)
                }
            }
        }
    }
    
    // 读取特征值成功(获取ATT属性值)
    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
        guard let data = characteristic.value, let value = String(data: data, encoding: .utf8) else { return }
        print("读取特征值成功:\(value)")
    }
    
    // 写入特征值(底层通过ATT协议写属性)
    func writeValue(to peripheral: CBPeripheral, characteristic: CBCharacteristic, value: String) {
        guard let data = value.data(using: .utf8) else { return }
        // 写入特征值(withResponse:是否需要响应,确保写入成功)
        peripheral.writeValue(data, for: characteristic, type: .withResponse)
    }
    
    // 断开连接
    func disconnectPeripheral() {
        guard let peripheral = targetPeripheral else { return }
        centralManager.cancelPeripheralConnection(peripheral)
    }
}

// 使用示例
let bleManager = BLECentralManager()

2. 安卓(Kotlin)实战代码(基于BluetoothGatt框架)

安卓中使用BluetoothGatt框架操作BLE,核心是BluetoothAdapter(蓝牙适配器)、BluetoothDevice(蓝牙设备)、BluetoothGatt(GATT连接),以下是完整代码(需在AndroidManifest中添加蓝牙权限):

import android.Manifest
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCallback
import android.bluetooth.BluetoothProfile
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat

class BLEActivity : AppCompatActivity() {
    private lateinit var bluetoothAdapter: BluetoothAdapter
    private var bluetoothGatt: BluetoothGatt? = null
    // 目标服务和特征值UUID(根据实际设备修改)
    private val targetServiceUUID = "0000180A-0000-1000-8000-00805F9B34FB" // 设备信息服务
    private val targetCharUUID = "00002A00-0000-1000-8000-00805F9B34FB" // 设备名称特征值
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_ble)
        
        // 初始化蓝牙适配器(GAP扫描的核心)
        val bluetoothManager = getSystemService(BLUETOOTH_SERVICE) as android.bluetooth.BluetoothManager
        bluetoothAdapter = bluetoothManager.adapter
        
        // 检查蓝牙是否可用
        if (!bluetoothAdapter.isEnabled) {
            bluetoothAdapter.enable() // 开启蓝牙
            Toast.makeText(this, "正在开启蓝牙...", Toast.LENGTH_SHORT).show()
        }
        
        // 检查权限(安卓12+需额外申请BLUETOOTH_SCAN、BLUETOOTH_CONNECT权限)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            if (ActivityCompat.checkSelfPermission(
                    this,
                    Manifest.permission.BLUETOOTH_SCAN
                ) != PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(
                    this,
                    Manifest.permission.BLUETOOTH_CONNECT
                ) != PackageManager.PERMISSION_GRANTED
            ) {
                ActivityCompat.requestPermissions(
                    this,
                    arrayOf(Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT),
                    1001
                )
                return
            }
        }
        
        // 开始扫描GAP广播的设备
        startScan()
    }
    
    // 开始扫描BLE设备(GAP扫描)
    private fun startScan() {
        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.BLUETOOTH_SCAN
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            return
        }
        // 扫描回调,获取GAP广播的设备信息
        bluetoothAdapter.startLeScan { device, rssi, scanRecord ->
            device?.let {
                // 过滤目标设备(根据设备名称、UUID过滤)
                if (it.name == "Smart Sensor") {
                    Toast.makeText(this, "发现设备:${it.name}", Toast.LENGTH_SHORT).show()
                    // 停止扫描,发起GAP连接
                    bluetoothAdapter.stopLeScan()
                    connectDevice(it)
                }
            }
        }
    }
    
    // 连接BLE设备(GAP连接)
    private fun connectDevice(device: BluetoothDevice) {
        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.BLUETOOTH_CONNECT
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            return
        }
        // 建立GATT连接,获取GATT客户端
        bluetoothGatt = device.connectGatt(this, false, gattCallback)
    }
    
    // GATT回调(处理GATT连接、服务发现、特征值读写)
    private val gattCallback = object : BluetoothGattCallback() {
        // GATT连接状态变化
        override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {
            super.onConnectionStateChange(gatt, status, newState)
            when (newState) {
                BluetoothProfile.STATE_CONNECTED -> {
                    Toast.makeText(this@BLEActivity, "设备连接成功", Toast.LENGTH_SHORT).show()
                    // 发现GATT服务(ATT属性的组织)
                    gatt?.discoverServices()
                }
                BluetoothProfile.STATE_DISCONNECTED -> {
                    Toast.makeText(this@BLEActivity, "设备断开连接", Toast.LENGTH_SHORT).show()
                }
            }
        }
        
        // 发现GATT服务
        override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
            super.onServicesDiscovered(gatt, status)
            if (status != BluetoothGatt.GATT_SUCCESS) return
            // 获取所有GATT服务
            gatt?.services?.forEach { service ->
                if (service.uuid.toString() == targetServiceUUID) {
                    Toast.makeText(this@BLEActivity, "发现目标服务:${service.uuid}", Toast.LENGTH_SHORT).show()
                    // 发现服务下的GATT特征值
                    service.characteristics.forEach { char ->
                        if (char.uuid.toString() == targetCharUUID) {
                            // 读取特征值(底层通过ATT协议读属性)
                            gatt.readCharacteristic(char)
                            // 开启特征值通知(实时接收数据)
                            if (char.properties and BluetoothGattCharacteristic.PROPERTY_NOTIFY != 0) {
                                gatt.setCharacteristicNotification(char, true)
                            }
                        }
                    }
                }
            }
        }
        
        // 读取特征值成功(获取ATT属性值)
        override fun onCharacteristicRead(
            gatt: BluetoothGatt?,
            characteristic: BluetoothGattCharacteristic?,
            status: Int
        ) {
            super.onCharacteristicRead(gatt, characteristic, status)
            if (status == BluetoothGatt.GATT_SUCCESS) {
                characteristic?.value?.let { data ->
                    val value = String(data, Charsets.UTF_8)
                    Toast.makeText(this@BLEActivity, "读取特征值:$value", Toast.LENGTH_SHORT).show()
                }
            }
        }
        
        // 写入特征值成功
        override fun onCharacteristicWrite(
            gatt: BluetoothGatt?,
            characteristic: BluetoothGattCharacteristic?,
            status: Int
        ) {
            super.onCharacteristicWrite(gatt, characteristic, status)
            if (status == BluetoothGatt.GATT_SUCCESS) {
                Toast.makeText(this@BLEActivity, "写入特征值成功", Toast.LENGTH_SHORT).show()
            }
        }
    }
    
    // 写入特征值(底层通过ATT协议写属性)
    fun writeCharacteristic(value: String) {
        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.BLUETOOTH_CONNECT
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            return
        }
        bluetoothGatt?.services?.forEach { service ->
            if (service.uuid.toString() == targetServiceUUID) {
                service.characteristics.forEach { char ->
                    if (char.uuid.toString() == targetCharUUID) {
                        char.value = value.toByteArray(Charsets.UTF_8)
                        bluetoothGatt?.writeCharacteristic(char)
                    }
                }
            }
        }
    }
    
    // 断开连接
    override fun onDestroy() {
        super.onDestroy()
        if (ActivityCompat.checkSelfPermission(
                this,
                Manifest.permission.BLUETOOTH_CONNECT
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            return
        }
        bluetoothGatt?.disconnect()
        bluetoothGatt?.close()
    }
}

注意:安卓端需在AndroidManifest.xml中添加以下权限(根据系统版本适配):

<!-- 蓝牙基础权限 -->
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
<!-- 安卓12+权限 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<!-- 蓝牙低功耗权限 -->
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true" />

3. Flutter实战代码(基于flutter_blue_plus插件)

Flutter中操作BLE需依赖第三方插件(推荐flutter_blue_plus,兼容iOS和安卓),以下是完整代码,实现跨平台的BLE扫描、连接、读写特征值:

第一步:添加依赖(pubspec.yaml)

dependencies:
  flutter:
    sdk: flutter
  flutter_blue_plus: ^1.13.3 # 最新版本可在pub.dev查询

第二步:平台配置(iOS/安卓)

  • iOS:在Info.plist中添加蓝牙权限 NSBluetoothAlwaysUsageDescription(蓝牙使用说明) NSBluetoothPeripheralUsageDescription(兼容旧版本)

  • 安卓:在AndroidManifest.xml中添加上述安卓权限

第三步:核心代码

import 'package:flutter/material.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';

class BLEPage extends StatefulWidget {
  const BLEPage({super.key});

  @override
  State<BLEPage> createState() => _BLEPageState();
}

class _BLEPageState extends State<BLEPage> {
  FlutterBluePlus flutterBlue = FlutterBluePlus.instance;
  BluetoothDevice? targetDevice; // 目标设备
  BluetoothCharacteristic? targetChar; // 目标特征值
  // 目标服务和特征值UUID(根据实际设备修改)
  final Guid targetServiceGuid = Guid("0000180A-0000-1000-8000-00805F9B34FB"); // 设备信息服务
  final Guid targetCharGuid = Guid("00002A00-0000-1000-8000-00805F9B34FB"); // 设备名称特征值

  @override
  void initState() {
    super.initState();
    // 初始化蓝牙,监听蓝牙状态
    initBLE();
  }

  // 初始化BLE,检查蓝牙状态
  void initBLE() {
    // 监听蓝牙状态变化
    flutterBlue.state.listen((BluetoothState state) {
      switch (state) {
        case BluetoothState.on:
          print("蓝牙已开启,开始扫描设备(GAP扫描)");
          startScan(); // 开启扫描
          break;
        case BluetoothState.off:
          print("蓝牙已关闭,请开启蓝牙");
          break;
        default:
          break;
      }
    });
  }

  // 开始扫描GAP广播的设备
  void startScan() {
    // 停止之前的扫描(避免重复扫描)
    flutterBlue.stopScan();
    // 开始扫描,过滤目标服务UUID,扫描时长4秒
    flutterBlue.startScan(
      withServices: [targetServiceGuid],
      timeout: const Duration(seconds: 4),
    );

    // 监听扫描结果(GAP广播数据)
    flutterBlue.scanResults.listen((List<ScanResult> results) {
      for (ScanResult result in results) {
        // 过滤目标设备(根据设备名称过滤)
        if (result.device.name == "Smart Sensor") {
          setState(() {
            targetDevice = result.device;
          });
          print("发现设备:${result.device.name},RSSI:${result.rssi}");
          // 停止扫描,发起GAP连接
          flutterBlue.stopScan();
          connectDevice();
        }
      }
    });
  }

  // 连接BLE设备(GAP连接)
  void connectDevice() async {
    if (targetDevice == null) return;
    try {
      // 发起连接
      await targetDevice!.connect();
      print("设备连接成功,开始发现GATT服务");
      // 发现GATT服务(ATT属性的组织)
      discoverServices();
    } catch (e) {
      print("连接失败:$e");
    }
  }

  // 发现GATT服务和特征值
  void discoverServices() async {
    if (targetDevice == null) return;
    // 获取设备的所有GATT服务
    List<BluetoothService> services = await targetDevice!.discoverServices();
    for (BluetoothService service in services) {
      if (service.uuid == targetServiceGuid) {
        print("发现目标服务:${service.uuid}");
        // 获取服务下的所有GATT特征值
        for (BluetoothCharacteristic char in service.characteristics) {
          if (char.uuid == targetCharGuid) {
            setState(() {
              targetChar = char;
            });
            print("发现目标特征值:${char.uuid}");
            // 读取特征值(底层通过ATT协议读属性)
            readCharacteristic();
            // 开启特征值通知(实时接收数据)
            if (char.properties.contains(BluetoothCharacteristicProperty.notify)) {
              await char.setNotifyValue(true);
              // 监听特征值变化
              char.value.listen((value) {
                String data = String.fromCharCodes(value);
                print("实时接收特征值:$data");
              });
            }
          }
        }
      }
    }
  }

  // 读取特征值
  void readCharacteristic() async {
    if (targetChar == null) return;
    try {
      // 读取特征值(底层通过ATT协议读属性)
      await targetChar!.read();
      String value = String.fromCharCodes(targetChar!.value);
      print("读取特征值成功:$value");
    } catch (e) {
      print("读取特征值失败:$e");
    }
  }

  // 写入特征值(底层通过ATT协议写属性)
  void writeCharacteristic(String value) async {
    if (targetChar == null) return;
    try {
      // 写入特征值
      await targetChar!.write(utf8.encode(value), withoutResponse: false);
      print("写入特征值成功:$value");
    } catch (e) {
      print("写入特征值失败:$e");
    }
  }

  // 断开连接
  void disconnectDevice() async {
    if (targetDevice == null) return;
    await targetDevice!.disconnect();
    print("设备断开连接");
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("BLE实战")),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(targetDevice?.name ?? "未发现设备"),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: startScan,
              child: const Text("扫描设备"),
            ),
            const SizedBox(height: 10),
            ElevatedButton(
              onPressed: targetDevice != null ? disconnectDevice : null,
              child: const Text("断开连接"),
            ),
            const SizedBox(height: 10),
            ElevatedButton(
              onPressed: targetChar != null ? () => writeCharacteristic("测试写入") : null,
              child: const Text("写入特征值"),
            ),
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    // 页面销毁时断开连接
    disconnectDevice();
    super.dispose();
  }
}

四、核心总结:层级关系与开发注意事项

1. 层级关系梳理(必记)

从底层到上层:HCI(硬件衔接)→ L2CAP(数据运输)→ ATT(属性定义)→ GATT(数据组织)→ GAP(设备交互),每层的核心作用可总结为:

  • HCI:翻译指令,衔接硬件与软件;

  • L2CAP:分片重组,保障数据传输;

  • ATT:定义属性,规范数据格式;

  • GATT:组织数据,提供交互接口;

  • GAP:管理连接,实现设备发现。

2. 开发注意事项(避坑重点)

  • 权限适配:iOS需在Info.plist添加蓝牙权限说明,安卓需根据系统版本申请BLUETOOTH_SCAN、BLUETOOTH_CONNECT等权限,否则会导致扫描失败、连接失败;

  • 数据长度限制:BLE默认单次传输27字节,若需传输更长数据,需开启长包传输(BLE 4.2+),否则会导致数据丢失;

  • 连接稳定性:BLE连接容易受距离、干扰影响,需添加重连机制(如断开连接后自动扫描重连);

  • UUID规范:GATT服务和特征值的UUID需与硬件设备一致,否则无法发现服务、读写特征值;

  • 资源释放:开发中需及时断开GATT连接、停止扫描,避免内存泄漏(尤其是Flutter跨平台开发,需注意原生资源的释放)。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐