Flutter POSIX接口访问插件posix_sdk的使用
Flutter POSIX接口访问插件posix_sdk的使用
简介
Posix SDK 是一个为 Flutter 设计的蓝牙插件,帮助开发者构建现代多平台应用程序。 示例应用的 GitHub 链接:GitHub
跨平台低功耗蓝牙
Posix SDK 的目标是同时提供 iOS 和 Android 平台的最佳功能。
通过 Posix SDK 实例,您可以扫描并检查附近设备的 LED(通过 BluetoothDevice
API)。
使用方法
获取实例
PosixSdk posixSdk = PosixSdk.instance;
检查设备的 LED
// 开始扫描
posixSdk.connect(device: result.device);
入门指南
更改 Android 的 minSdkVersion
Posix SDK 只兼容 Android SDK 版本 19 及以上。因此,您需要在 android/app/build.gradle
文件中更改此设置:
Android {
defaultConfig {
minSdkVersion 19
}
}
添加蓝牙权限
我们需要添加使用蓝牙和访问位置的权限。
Android
在 android/app/src/main/AndroidManifest.xml
文件中添加以下内容:
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
iOS
在 ios/Runner/Info.plist
文件中添加以下内容:
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Need BLE permission</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>Need BLE permission</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Need Location permission</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Need Location permission</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Need Location permission</string>
更多关于 iOS 位置权限的信息,请参阅 Apple 文档。
完整示例代码
以下是完整的示例代码,位于 example/lib/main.dart
:
import 'package:flutter/material.dart';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:posix_sdk/posix_sdk.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
color: Colors.lightBlue,
home: StreamBuilder<BluetoothState>(
stream: FlutterBlue.instance.state,
initialData: BluetoothState.unknown,
builder: (c, snapshot) {
final state = snapshot.data;
if (state == BluetoothState.on) {
return ListDevicesScreen();
}
return BluetoothOffScreen(state: state);
}),
);
}
}
class ListDevicesScreen extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
PosixSdk posixSdk = PosixSdk.instance;
return Scaffold(
appBar: AppBar(
title: const Text('Find Devices'),
),
body: RefreshIndicator(
onRefresh: () =>
FlutterBlue.instance.startScan(scanMode: ScanMode.opportunistic, timeout: const Duration(seconds: 30)),
child: SingleChildScrollView(
child: Column(
children: <Widget>[
StreamBuilder<List<ScanResult>>(
stream: FlutterBlue.instance.scanResults,
initialData: [],
builder: (c, snapshot) => Column(
children: snapshot.data!
.map(
(r) => ScanResultTile(
result: r,
onTap: () => {
FlutterBlue.instance.stopScan(),
posixSdk.connect(device: r.device)
},
),
)
.toList(),
),
),
],
),
),
),
floatingActionButton: StreamBuilder<bool>(
stream: FlutterBlue.instance.isScanning,
initialData: false,
builder: (c, snapshot) {
if (snapshot.data!) {
return FloatingActionButton(
child: const Icon(Icons.stop),
onPressed: () => FlutterBlue.instance.stopScan(),
backgroundColor: Colors.red,
);
} else {
return FloatingActionButton(
child: const Icon(Icons.search),
onPressed: () => FlutterBlue.instance
.startScan(timeout: const Duration(seconds: 60)));
}
},
),
);
}
}
class ScanResultTile extends StatelessWidget {
const ScanResultTile({Key? key, required this.result, this.onTap})
: super(key: key);
final ScanResult result;
final VoidCallback? onTap;
Widget _buildTitle(BuildContext context) {
if (result.device.name.length > 0) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
result.device.name,
overflow: TextOverflow.ellipsis,
),
Text(
result.device.id.toString(),
style: Theme.of(context).textTheme.caption,
)
],
);
} else {
return Text(result.device.id.toString());
}
}
Widget _buildAdvRow(BuildContext context, String title, String value) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 4.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(title, style: Theme.of(context).textTheme.caption),
const SizedBox(
width: 12.0,
),
Expanded(
child: Text(
value,
style: Theme.of(context)
.textTheme
.caption
?.apply(color: Colors.black),
softWrap: true,
),
),
],
),
);
}
String getNiceHexArray(List<int> bytes) {
return '[${bytes.map((i) => i.toRadixString(16).padLeft(2, '0')).join(', ')}]'
.toUpperCase();
}
String getNiceManufacturerData(Map<int, List<int>> data) {
if (data.isEmpty) {
return 'N/A';
}
List<String> res = [];
data.forEach((id, bytes) {
res.add(
'${id.toRadixString(16).toUpperCase()}: ${getNiceHexArray(bytes)}');
});
return res.join(', ');
}
String getNiceServiceData(Map<String, List<int>> data) {
if (data.isEmpty) {
return 'N/A';
}
List<String> res = [];
data.forEach((id, bytes) {
res.add('${id.toUpperCase()}: ${getNiceHexArray(bytes)}');
});
return res.join(', ');
}
[@override](/user/override)
Widget build(BuildContext context) {
return ExpansionTile(
title: _buildTitle(context),
leading: Text(result.rssi.toString()),
trailing: RaisedButton(
child: const Text('LED'),
color: Colors.black,
textColor: Colors.white,
onPressed: (result.advertisementData.connectable) ? onTap : null,
),
children: <Widget>[
_buildAdvRow(
context, 'Complete Local Name', result.advertisementData.localName),
_buildAdvRow(context, 'Tx Power Level',
'${result.advertisementData.txPowerLevel ?? 'N/A'}'),
_buildAdvRow(context, 'Manufacturer Data',
getNiceManufacturerData(result.advertisementData.manufacturerData)),
_buildAdvRow(
context,
'Service UUIDs',
(result.advertisementData.serviceUuids.isNotEmpty)
? result.advertisementData.serviceUuids.join(', ').toUpperCase()
: 'N/A'),
_buildAdvRow(context, 'Service Data',
getNiceServiceData(result.advertisementData.serviceData)),
],
);
}
}
class BluetoothOffScreen extends StatelessWidget {
const BluetoothOffScreen({Key? key, this.state}) : super(key: key);
final BluetoothState? state;
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.lightBlue,
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Icon(
Icons.bluetooth_disabled,
size: 200.0,
color: Colors.white54,
),
Text(
'Bluetooth Adapter is ${state != null ? state.toString().substring(15) : 'not available'}.',
style: Theme.of(context)
.primaryTextTheme
.subtitle1
?.copyWith(color: Colors.white),
),
],
),
),
);
}
}
更多关于Flutter POSIX接口访问插件posix_sdk的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
1 回复