You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用flutter_blue_plus检测Apple及Feasycom(0x0A2D)iBeacon?

解决方案

1. 基于flutter_blue_plus的可靠iBeacon检测与解析

你的现有代码仅通过厂商ID过滤,容易误判同厂商的非iBeacon设备。要准确检测,必须验证iBeacon的标准数据结构:

  • Apple iBeacon:厂商ID为0x004C,厂商数据前2字节为0x0215(iBeacon广告帧类型),数据总长度需达23字节(包含类型、UUID、major、minor、发射功率)。
  • Feasycom iBeacon:厂商ID为0x0A2D,多数型号遵循标准iBeacon规范,同样需验证数据长度和类型字段。

修改检测逻辑并添加数据解析:

// 定义Beacon数据模型
class BeaconData {
  final int manufacturerId;
  final String uuid;
  final int major;
  final int minor;
  final int txPower;

  BeaconData({
    required this.manufacturerId,
    required this.uuid,
    required this.major,
    required this.minor,
    required this.txPower,
  });
}

// 解析iBeacon原始数据
BeaconData? parseBeaconData(List<int> data, int manufacturerId) {
  // 标准iBeacon数据长度要求:2字节类型+16字节UUID+2字节major+2字节minor+1字节txPower = 23字节
  if (data.length < 23) return null;
  // 验证iBeacon类型标识
  if (data[0] != 0x02 || data[1] != 0x15) return null;

  // 解析UUID(小端转大端处理)
  final uuidBytes = data.sublist(2, 18);
  final uuidStr = [
    ...uuidBytes.sublist(0,4).reversed,
    ...uuidBytes.sublist(4,6).reversed,
    ...uuidBytes.sublist(6,8).reversed,
    ...uuidBytes.sublist(8,16)
  ].map((b) => b.toRadixString(16).padLeft(2, '0')).join();
  final uuid = '$uuidStr.substring(0,8)-${uuidStr.substring(8,12)}-${uuidStr.substring(12,16)}-${uuidStr.substring(16,20)}-${uuidStr.substring(20)}';

  // 解析major/minor(大端字节序)
  final major = (data[18] << 8) | data[19];
  final minor = (data[20] << 8) | data[21];
  final txPower = data[22];

  return BeaconData(
    manufacturerId: manufacturerId,
    uuid: uuid,
    major: major,
    minor: minor,
    txPower: txPower,
  );
}

// 修改目标信标检测方法
bool isTargetBeacon(ScanResult result) {
  final manufacturerData = result.advertisementData.manufacturerData;
  if (manufacturerData.isEmpty) return false;

  const feasycomId = 0x0A2D;
  const appleId = 0x004C;

  // 检测Apple iBeacon
  if (manufacturerData.containsKey(appleId)) {
    final data = manufacturerData[appleId];
    if (data != null) {
      final beaconData = parseBeaconData(data, appleId);
      if (beaconData != null) {
        debugPrint('Apple iBeacon: UUID=${beaconData.uuid}, Major=${beaconData.major}, Minor=${beaconData.minor}');
        return true;
      }
    }
  }

  // 检测Feasycom iBeacon
  if (manufacturerData.containsKey(feasycomId)) {
    final data = manufacturerData[feasycomId];
    if (data != null) {
      final beaconData = parseBeaconData(data, feasycomId);
      if (beaconData != null) {
        debugPrint('Feasycom iBeacon: UUID=${beaconData.uuid}, Major=${beaconData.major}, Minor=${beaconData.minor}');
        return true;
      }
    }
  }

  return false;
}

2. 厂商特定数据过滤的正确方式

方式一:扫描阶段直接过滤(推荐)

利用flutterBlue.startScan的withManufacturers参数,只扫描指定厂商ID的设备,减少无关数据干扰:

void startScan() {
  setState(() {
    isScanning = true;
    beaconResults.clear();
  });

  // 仅扫描Apple和Feasycom厂商的设备
  flutterBlue.startScan(
    withManufacturers: [0x004C, 0x0A2D],
    timeout: const Duration(seconds: 10),
  );

  // 后续监听逻辑保持不变
}

方式二:回调中二次验证

即使扫描时过滤,仍需在回调中验证数据结构,避免同厂商的非iBeacon设备被误判(即上述修改后的isTargetBeacon方法)。

3. 更适合的跨平台iBeacon检测包:flutter_beacon

如果核心需求是iBeacon检测,推荐使用flutter_beacon包。它封装了Android的AltBeacon库和iOS的CoreLocation原生API,无需手动解析BLE原始数据,直接获取标准化的iBeacon信息,稳定性和兼容性更强。

基本使用示例

  1. 添加依赖到pubspec.yaml:
dependencies:
  flutter_beacon: ^0.5.0
  1. 核心代码:
import 'package:flutter/material.dart';
import 'package:flutter_beacon/flutter_beacon.dart';
import 'package:permission_handler/permission_handler.dart';

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

  @override
  State<BeaconScanner> createState() => _BeaconScannerState();
}

class _BeaconScannerState extends State<BeaconScanner> {
  final regions = <Region>[
    // 监听所有Apple iBeacon(可指定具体UUID缩小范围)
    Region(identifier: 'Apple Beacons', proximityUUID: '00000000-0000-0000-0000-000000000000'),
    // 监听Feasycom iBeacon(替换为设备实际UUID)
    Region(identifier: 'Feasycom Beacons', proximityUUID: '00000000-0000-0000-0000-000000000000'),
  ];

  StreamSubscription<RangingResult>? _rangingStream;
  List<Beacon> detectedBeacons = [];

  @override
  void initState() {
    super.initState();
    _initScanner();
  }

  Future<void> _initScanner() async {
    // 初始化扫描并请求权限
    await flutterBeacon.initializeScanning;
    await [
      Permission.locationWhenInUse,
      Permission.bluetoothScan,
      Permission.bluetoothConnect,
    ].request();

    // 开始监听iBeacon
    _rangingStream = flutterBeacon.ranging(regions).listen((result) {
      setState(() {
        detectedBeacons = result.beacons;
      });
      for (var beacon in result.beacons) {
        debugPrint('Beacon: ${beacon.proximityUUID}, Major=${beacon.major}, Minor=${beacon.minor}, RSSI=${beacon.rssi}');
      }
    });
  }

  @override
  void dispose() {
    _rangingStream?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('iBeacon Scanner')),
      body: detectedBeacons.isEmpty
          ? const Center(child: Text('Scanning for beacons...'))
          : ListView.builder(
              itemCount: detectedBeacons.length,
              itemBuilder: (context, index) {
                final beacon = detectedBeacons[index];
                return ListTile(
                  title: Text('UUID: ${beacon.proximityUUID}'),
                  subtitle: Text('Major: ${beacon.major}, Minor: ${beacon.minor}, RSSI: ${beacon.rssi}'),
                );
              },
            ),
    );
  }
}

平台配置注意

  • Android:在AndroidManifest.xml添加权限
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
  • iOS:在Info.plist添加权限描述
<key>NSLocationWhenInUseUsageDescription</key>
<string>需要位置权限扫描iBeacon</string>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>需要蓝牙权限扫描iBeacon</string>

内容的提问来源于stack exchange,提问作者nima alihosseini

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 15:43:09