Flutter串口通信插件libserialport的使用
Flutter串口通信插件 libserialport
的使用
概述
libserialport
是一个基于 Dart FFI(Foreign Function Interface)的库,用于与 libserialport
C 库进行交互。libserialport
是由 sigrok 项目创建的一个最小化的 C 库,适用于 Linux、macOS、Windows 和 Android 平台。
对于 Flutter 应用程序,推荐使用 flutter_libserialport
插件,它能够自动构建和部署 libserialport
到所有支持的平台。
使用步骤
添加依赖
首先,在你的 pubspec.yaml
文件中添加 libserialport
或者 flutter_libserialport
作为依赖:
dependencies:
flutter_libserialport: ^latest_version
确保替换 ^latest_version
为实际的最新版本号。
示例代码
以下是一个简单的示例,展示了如何列出可用的串口设备,并打开其中一个端口进行读写操作。
列出所有可用串口
import 'package:libserialport/libserialport.dart';
void main() {
print('Available ports:');
var i = 0;
for (final name in SerialPort.availablePorts) {
final sp = SerialPort(name);
print('${++i}) $name');
print('\tDescription: ${sp.description}');
print('\tManufacturer: ${sp.manufacturer}');
print('\tSerial Number: ${sp.serialNumber}');
print('\tProduct ID: 0x${sp.productId!.toRadixString(16)}');
print('\tVendor ID: 0x${sp.vendorId!.toRadixString(16)}');
sp.dispose();
}
}
打开并使用串口
下面的例子展示了如何打开第一个可用的串口,并设置为读写模式,然后发送数据并监听接收的数据。
import 'dart:io';
import 'package:libserialport/libserialport.dart';
void main() async {
// 获取第一个可用串口名称
final name = SerialPort.availablePorts.firstOrNull;
if (name == null) {
print("No serial ports available.");
exit(-1);
}
// 创建 SerialPort 实例
final port = SerialPort(name);
// 尝试以读写模式打开串口
if (!port.openReadWrite()) {
print(SerialPort.lastError);
exit(-1);
}
// 写入一些数据到串口
port.write([0x48, 0x65, 0x6c, 0x6c, 0x6f]); // 发送 "Hello"
// 设置监听器来接收数据
final reader = SerialPortReader(port);
reader.stream.listen((data) {
print('Received: ${String.fromCharCodes(data)}');
});
// 等待一段时间以便接收数据
await Future.delayed(Duration(seconds: 5));
// 关闭串口
port.close();
}
更多关于Flutter串口通信插件libserialport的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter串口通信插件libserialport的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
在Flutter应用中实现串口通信,你可以使用libserialport
插件。libserialport
是一个强大的C库,用于跨平台的串口通信。虽然Flutter本身并不直接支持C库,但你可以通过调用原生代码(如Android的Java/Kotlin或iOS的Objective-C/Swift)来实现这一功能。
以下是一个基本的步骤和代码示例,展示如何在Flutter项目中集成和使用libserialport
进行串口通信。由于libserialport
是一个C库,我们需要在原生代码中进行封装,然后通过MethodChannel与Flutter进行通信。
步骤 1: 设置Flutter项目
首先,创建一个新的Flutter项目(如果你还没有的话):
flutter create serial_port_app
cd serial_port_app
步骤 2: 添加原生依赖
Android
- 在
android/app/src/main/cpp/
目录下创建一个CMakeLists.txt文件(如果不存在),并添加以下内容:
cmake_minimum_required(VERSION 3.4.1)
add_library(libserialport SHARED
src/main/cpp/libserialport/libserialport.c)
find_library(log-lib log)
target_link_libraries(libserialport ${log-lib})
注意:你需要将libserialport
的源代码放在src/main/cpp/libserialport/
目录下。
- 在
android/app/build.gradle
中添加对CMake的支持:
android {
...
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
}
}
}
- 创建一个Java类来封装对
libserialport
的调用。在android/app/src/main/java/com/yourappid/
目录下创建一个名为SerialPortHelper.java
的文件,并添加以下内容:
package com.yourappid;
import android.content.Context;
import androidx.annotation.NonNull;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
public class SerialPortHelper implements FlutterPlugin, MethodCallHandler, ActivityAware {
private MethodChannel channel;
private Context applicationContext;
// Native method declarations
public native void openPort(String path, int baudrate);
public native void closePort();
public native byte[] readPort(int size);
public native void writePort(byte[] data);
static {
System.loadLibrary("serialport");
}
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
applicationContext = flutterPluginBinding.getApplicationContext();
channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "serial_port_channel");
channel.setMethodCallHandler(this);
}
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
if (call.method.equals("openPort")) {
String path = call.argument("path");
int baudrate = call.argument("baudrate");
openPort(path, baudrate);
result.success(null);
} else if (call.method.equals("closePort")) {
closePort();
result.success(null);
} else if (call.method.equals("readPort")) {
int size = call.argument("size");
byte[] data = readPort(size);
result.success(data);
} else if (call.method.equals("writePort")) {
byte[] data = call.argument("data");
writePort(data);
result.success(null);
} else {
result.notImplemented();
}
}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
channel.setMethodCallHandler(null);
}
@Override
public void onAttachedToActivity(ActivityPluginBinding binding) {
// No-op
}
@Override
public void onDetachedFromActivityForConfigChanges() {
// No-op
}
@Override
public void onReattachedToActivityForConfigChanges(ActivityPluginBinding binding) {
// No-op
}
@Override
public void onDetachedFromActivity() {
// No-op
}
}
注意:你需要将libserialport
的C代码进行适当的封装,以提供上述的openPort
、closePort
、readPort
和writePort
方法。
iOS
对于iOS,你需要使用Objective-C或Swift封装对libserialport
的调用,但这个过程相对复杂,因为iOS通常不直接支持串口通信。你可能需要寻找一个现有的iOS串口通信库,或者使用外部硬件(如USB转串口适配器)并通过IOKit进行访问。
步骤 3: 在Flutter中调用原生方法
在你的Flutter项目中,创建一个Dart文件来与原生代码进行通信。例如,在lib/
目录下创建一个名为serial_port.dart
的文件,并添加以下内容:
import 'package:flutter/services.dart';
class SerialPort {
static const MethodChannel _channel = MethodChannel('serial_port_channel');
static Future<void> openPort(String path, int baudrate) async {
try {
await _channel.invokeMethod('openPort', {'path': path, 'baudrate': baudrate});
} on PlatformException catch (e) {
throw e;
}
}
static Future<void> closePort() async {
try {
await _channel.invokeMethod('closePort');
} on PlatformException catch (e) {
throw e;
}
}
static Future<Uint8List> readPort(int size) async {
try {
final Uint8List result = await _channel.invokeMethod('readPort', {'size': size});
return result;
} on PlatformException catch (e) {
throw e;
}
}
static Future<void> writePort(Uint8List data) async {
try {
await _channel.invokeMethod('writePort', {'data': data});
} on PlatformException catch (e) {
throw e;
}
}
}
步骤 4: 使用SerialPort类
现在,你可以在你的Flutter应用中使用SerialPort
类来进行串口通信。例如:
import 'package:flutter/material.dart';
import 'serial_port.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
// 打开串口
SerialPort.openPort('/dev/ttyUSB0', 9600);
// 读取数据(在实际应用中,你可能需要在另一个线程或定时器中执行此操作)
SerialPort.readPort(10).then((data) {
print('Received data: ${data.map((byte) => byte.toRadixString(16)).join(', ')}');
});
// 写入数据
SerialPort.writePort(Uint8List.fromList([0x01, 0x02, 0x03]));
// 关闭串口(在适当的时机调用)
// SerialPort.closePort();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Serial Port Communication'),
),
body: Center(
child: Text('Check console for serial port communication output'),
),
),
);
}
}
注意
- 权限:在Android上,你需要请求USB权限或使用特定的串口权限。
- 线程:串口通信是阻塞操作,因此你应该在单独的线程或Isolate中执行这些操作。
- 错误处理:在实际应用中,添加更多的错误处理和日志记录。
- iOS:iOS上的串口通信需要更多的工作,因为iOS没有内置的串口API。你可能需要使用