Flutter配件设置插件flutter_accessorysetup的使用

Flutter配件设置插件flutter_accessorysetup的使用

目前库支持的功能包括:

  • ✅ BLE(低功耗蓝牙)
  • ✅ WiFi
  • ✅ 迁移

重要提示:根据Apple的设计,该库仅适用于 iOS 18及以上版本

如何使用

通过命令行安装库:

flutter pub get flutter_accessorysetup

设置

详细信息可参考 Apple文档

Info.plist配置

你需要在iOS应用的Info.plist文件中添加相应的键以使其正常工作。如果缺少必要的键,应用在显示选择器时会崩溃。

始终需要配置的键

<key>NSAccessorySetupKitSupports</key>
<array>
  <string>Bluetooth</string>
  <string>WiFi</string>
</array>

使用ASDiscoveryDescriptor配置bluetoothServiceUUID

<key>NSAccessorySetupBluetoothServices</key>
<array>
  <string>149E9E42-33AD-41AD-8665-70D153533EC1</string>
</array>

注意:这里的UUID字符串必须大写。

使用ASDiscoveryDescriptor配置bluetoothNameSubstring

<key>NSAccessorySetupBluetoothNames</key>
<array>
  <string>DeviceName</string>
</array>

注意:此功能在iOS 18开发者预览版2中无法使用。

其他制造商ID选项未在此处覆盖。

使用FlutterAccessorySetup

参考完整的代码示例,可以在示例应用中查看。

final _accessorySetup = FlutterAccessorySetup();

void activate() {
  _accessorySetup.eventStream.listen((event) {
    debugPrint('Got event: ${event.eventType}');
    // 处理会话事件
  });
  await _accessorySetup.activate();
  try {
    _accessorySetup.showPickerForDevice(
      'My Ble', 
      Assets.images.ble.path, 
      '4013ABDE-11C0-49E7-9939-4B4567C26ADA'
    );
  } on PlatformException {
    debugPrint('Failed to show the picker');
  }
}

void deactivate() {
  _accessorySetup.dispose();
  super.deactivate();
}

我们知道什么

  • 应用在使用选择器与蓝牙设备交互时,无需请求蓝牙权限。
  • 用户从选择器中选择设备非常方便。
  • 如果想在同一类型设备中显示多个设备,每个设备应广播一个唯一的名称。选择器只会显示每种唯一名称的一个设备。如果设备暴露了0x1800服务,则该服务中的设备名称也应唯一。
  • 当用户点击关闭按钮退出选择器时,showPicker闭包将发出错误(ASErrorDomain, code 700)。请注意处理这种情况。
  • 如果用户选择了一个BLE配件,选择器将发送一个类型为ASAccessoryEventType.accessoryChanged的事件。但据观察,选择器应发送ASAccessoryEventType.accessoryAdded类型的事件,这可能是一个bug。
  • 如果设备之前已连接过,它会在会话激活后出现在session.accessories数组中。
  • 如果设备已被其他应用连接过,选择器将显示由其他应用装饰过的设备——即图像和名称来自那个应用,而不是你提供的。要更改装饰,用户应该将设备添加到你的应用中。
  • 当用户通过选择器选择设备时:
    • 设备将在移动应用设置中的Settings/Apps/YourApp下的Accessories部分显示。
    • 设备将在Settings/Bluetooth下的My Devices部分显示。
    • 设备的信息屏幕将显示在发现过程中提供的图像和名称(即用户在选择器中看到的内容)。
  • 如果用户删除了应用,设备将自动断开连接。它将不再显示在Settings/Bluetooth屏幕的My Devices部分。

请注意:AccessorySetup在模拟器上不工作。

参考资料


示例代码

以下是从示例应用中摘录的代码:

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

import 'package:flutter_accessorysetup/flutter_accessorysetup.dart';
import 'package:flutter_accessorysetup/gen/ios/accessory_setup_bindings.dart';
import 'package:flutter_accessorysetup_example/gen/assets.gen.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';

void main() {
  runApp(const MyApp());
}

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

  [@override](/user/override)
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  String _deviceStatus = 'Disconnected';
  String _events = "";
  ASAccessory? _pickedAccessory;
  StreamSubscription<BluetoothAdapterState>? _adapterStateSubscription;
  StreamSubscription<ASAccessoryEvent>? _eventsSubscription;
  final _accessorySetup = FlutterAccessorySetup();

  [@override](/user/override)
  void initState() {
    super.initState();
    _activateAccessorySession();
  }

  [@override](/user/override)
  void deactivate() {
    _adapterStateSubscription?.cancel();
    _eventsSubscription?.cancel();
    _accessorySetup.dispose();
    super.deactivate();
  }

  Future<void> _activateAccessorySession() async {
    _accessorySetup.eventStream.listen((event) {
      debugPrint('Got event: ${event.eventType}');
      setState(() {
        _events += '\n\r${event.dartDescription};\n\r';
      });
      if (event.eventType == ASAccessoryEventType.ASAccessoryEventTypeActivated) {
        connect();
      } else if (event.eventType == ASAccessoryEventType.ASAccessoryEventTypeAccessoryAdded || event.eventType == ASAccessoryEventType.ASAccessoryEventTypeAccessoryChanged) {
        setState(() {
          _pickedAccessory = event.accessory;
        });
      } else if (event.eventType == ASAccessoryEventType.ASAccessoryEventTypePickerDidDismiss) {
        debugPrint('user picked accessory: $_pickedAccessory)');
        final accessory = _pickedAccessory;
        setState(() {
          _pickedAccessory = null;
        });
        final id = accessory?.dartBluetoothIdentifier;
        if (accessory != null && id != null && accessory.state == ASAccessoryState.ASAccessoryStateAuthorized) {
          _connectWithoutScanning(id);
        } else {
          throw Exception('added accessory should have identifier and be authorized');
        }
      }
    });
    _accessorySetup.activate();
  }

  Future<void> connect() async {
    final firstAccessoryId = _accessorySetup.accessories.firstOrNull?.dartBluetoothIdentifier;
    if (firstAccessoryId != null) {
      debugPrint('Got an accessory, will try to connect: $firstAccessoryId');
      await _connectWithoutScanning(firstAccessoryId);
      return;
    }

    try {
      // 为了使其正常工作,需要设置info.plist键
      // NSAccessorySetupBluetoothServices -> UUID
      // 和 NSAccessorySetupKitSupports -> Bluetooth
      _accessorySetup.showPickerForDevice('My Ble', Assets.images.ble.path, '4013ABDE-11C0-49E7-9939-4B4567C26ADA');
    } catch (e) {
      if (e is NativeCodeError) {
        debugPrint('Got native code error: $e');
      } else {
        debugPrint('Got error: $e');
      }
    }
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Accessory Setup App'),
        ),
        body: Center(
          child: Column(
            children: [
              Text('Device Status: $_deviceStatus'),
              const SizedBox(height: 15),
              Text('Setup Session Events: \n$_events'),
            ],
          ),
        ),
      ),
    );
  }

  // 连接设备部分

  Future<void> _connectWithoutScanning(String id) async {
    debugPrint('_connectWithoutScanning: $id');
    if (await FlutterBluePlus.isSupported == false) {
      debugPrint('Bluetooth is not supported by this device');
      return;
    }
    if (FlutterBluePlus.adapterStateNow == BluetoothAdapterState.on) {
      _connectDevice(id);
      return;
    }
    _adapterStateSubscription = FlutterBluePlus.adapterState.listen((BluetoothAdapterState state) {
      debugPrint('got adapter state: $state');
      if (state == BluetoothAdapterState.on) {
        _connectDevice(id);
        _adapterStateSubscription?.cancel();
      }
    });
  }

  Future<void> _connectDevice(String id) async {
    var device = BluetoothDevice.fromId(id);
    debugPrint('loaded device: $device');
    try {
      await device.connect();
      setState(() {
        _deviceStatus = 'Connected';
      });
      debugPrint('connected to device $device');
    } catch (e) {
      debugPrint('failed to connect: $e');
    }
  }
}

更多关于Flutter配件设置插件flutter_accessorysetup的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter配件设置插件flutter_accessorysetup的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


flutter_accessorysetup 是一个用于在 Flutter 应用中与配件(如智能家居设备)进行设置和配对的插件。这个插件通常用于简化与配件的连接和配置过程,使其更容易集成到 Flutter 应用中。

以下是一个基本的使用指南,帮助你开始使用 flutter_accessorysetup 插件。

1. 添加依赖

首先,你需要在 pubspec.yaml 文件中添加 flutter_accessorysetup 插件的依赖。

dependencies:
  flutter:
    sdk: flutter
  flutter_accessorysetup: ^0.1.0  # 请使用最新版本

然后运行 flutter pub get 来安装依赖。

2. 导入插件

在你的 Dart 文件中导入 flutter_accessorysetup 插件。

import 'package:flutter_accessorysetup/flutter_accessorysetup.dart';

3. 初始化插件

在使用插件之前,通常需要先初始化它。

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await FlutterAccessorySetup.initialize();
  runApp(MyApp());
}

4. 使用插件

flutter_accessorysetup 插件通常提供了一些方法来发现、连接和配置配件。以下是一些常见的使用场景:

4.1 发现配件

你可以使用插件来发现附近的配件。

void discoverAccessories() async {
  List<Accessory> accessories = await FlutterAccessorySetup.discoverAccessories();
  accessories.forEach((accessory) {
    print('Found accessory: ${accessory.name}');
  });
}

4.2 连接配件

发现配件后,你可以尝试连接到它。

void connectToAccessory(Accessory accessory) async {
  bool isConnected = await FlutterAccessorySetup.connect(accessory);
  if (isConnected) {
    print('Successfully connected to ${accessory.name}');
  } else {
    print('Failed to connect to ${accessory.name}');
  }
}

4.3 配置配件

连接成功后,你可以对配件进行配置。

void configureAccessory(Accessory accessory, Map<String, dynamic> config) async {
  bool isConfigured = await FlutterAccessorySetup.configure(accessory, config);
  if (isConfigured) {
    print('Successfully configured ${accessory.name}');
  } else {
    print('Failed to configure ${accessory.name}');
  }
}

5. 处理错误

在使用插件时,可能会遇到各种错误。你可以使用 try-catch 来捕获和处理这些错误。

void tryConnect(Accessory accessory) async {
  try {
    bool isConnected = await FlutterAccessorySetup.connect(accessory);
    if (isConnected) {
      print('Connected to ${accessory.name}');
    } else {
      print('Failed to connect to ${accessory.name}');
    }
  } catch (e) {
    print('Error connecting to accessory: $e');
  }
}

6. 监听状态变化

你可能还需要监听配件的状态变化,例如连接状态或配置状态。

void listenToAccessoryState(Accessory accessory) {
  FlutterAccessorySetup.listenToState(accessory, (state) {
    print('Accessory state changed: $state');
  });
}

7. 清理资源

在应用退出或不再需要插件时,记得清理资源。

void dispose() {
  FlutterAccessorySetup.dispose();
}

8. 示例应用

以下是一个简单的示例应用,展示如何发现、连接和配置配件。

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

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await FlutterAccessorySetup.initialize();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: AccessorySetupScreen(),
    );
  }
}

class AccessorySetupScreen extends StatefulWidget {
  [@override](/user/override)
  _AccessorySetupScreenState createState() => _AccessorySetupScreenState();
}

class _AccessorySetupScreenState extends State<AccessorySetupScreen> {
  List<Accessory> accessories = [];

  [@override](/user/override)
  void initState() {
    super.initState();
    discoverAccessories();
  }

  void discoverAccessories() async {
    accessories = await FlutterAccessorySetup.discoverAccessories();
    setState(() {});
  }

  void connectToAccessory(Accessory accessory) async {
    bool isConnected = await FlutterAccessorySetup.connect(accessory);
    if (isConnected) {
      print('Connected to ${accessory.name}');
    } else {
      print('Failed to connect to ${accessory.name}');
    }
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Accessory Setup'),
      ),
      body: ListView.builder(
        itemCount: accessories.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(accessories[index].name),
            onTap: () => connectToAccessory(accessories[index]),
          );
        },
      ),
    );
  }
}
回到顶部