更新记录

1.0.0(2026-10-13) 下载此版本

初始版本


平台兼容性

uni-app(3.96)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android Android插件版本 iOS 鸿蒙
- - - - - - 7.0 1.0.0 × ×
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
- - - - - - - - - - - -

uni-app x(5.31)

Chrome Safari Android Android插件版本 iOS 鸿蒙 微信小程序
- - 7.0 1.0.0 × × -

其他

多语言 暗黑模式 宽屏模式 蒸汽模式
× × × √

ep-uts-serial-port

串口通信 UTS 插件,支持 Android / iOS / 鸿蒙 (HarmonyOS) 三端,提供统一的串口读写、设备枚举 API。

核心特性:

  • 所有读/写/打开操作均在后台线程执行,不阻塞主线程不会卡死 UI
  • 内置端口互斥:同一路径重复构造实例会自动关闭旧端口,避免占用冲突

平台支持

平台 支持情况 底层机制
Android ✅ UsbManager USB Host API + CDC-ACM 协议
iOS ✅ TCP Socket 连接串口服务器(如 USR-TCP232)
鸿蒙 (HarmonyOS) ✅ @kit.BasicServicesKit serialManager API

注意: iOS 不支持直接访问硬件串口,需配合串口服务器使用,path 填写 host:port 格式。


快速开始

安装

将本插件目录放入项目的 uni_modules/ 下即可,或通过 HBuilderX 插件市场导入。

基本用法

import { SerialPort } from '@/uni_modules/ep-uts-serial-port'

// 1. 枚举可用设备
const devices = SerialPort.getDeviceList()
console.log(devices) // [{ name: "CP210x (10C4:EA60)", path: "/dev/bus/usb/001/003", driver: "CP210x", vid: 4292, pid: 60000 }]

// 2. 创建并打开串口(path 支持 VID:PID 格式或设备名)
const sp = new SerialPort(devices[0]?.path ?? '10C4:EA60', {
    baudRate: 9600,
    dataBits: 8,
    stopBits: 1,
    parity: 'none',
    timeout: 1000
})

sp.open({
    success: () => {
        console.log('串口已打开')
        // 开始监听数据
        sp.onData(data => console.log('收到:', data))
    },
    fail: e => console.error('打开失败:', e)
})

// 3. 发送数据
sp.send('POWER ON\r\n', {
    success: () => console.log('发送成功'),
    fail: e => console.error('发送失败:', e)
})

// 4. 发送二进制数据
sp.sendBinary('\x01\x02\xff', {
    success: () => console.log('二进制发送成功')
})

// 5. 同步读取指定长度数据
const result = sp.read(1024, 2000) // 读1024字节,2秒超时

// 6. 停止监听 & 关闭
sp.offData()  // 停止接收监听
sp.close()    // 关闭串口

API 参考

new SerialPort(path, config?)

创建串口实例。

参数 类型 必填 说明
path string ✅ 设备路径。Android 填 getDeviceList() 返回的 USB 设备名或 VID:PID 格式(如 "10C4:EA60");鸿蒙填设备名如 "ttySAC0";iOS 填 "host:port"
config SerialConfig ❌ 串口配置,不传则使用默认值

SerialConfig 类型

字段 类型 默认值 说明
baudRate number 9600 波特率
dataBits number 8 数据位(5/6/7/8)
stopBits number 1 停止位(1/2)
parity string "none" 校验位:"none" / "odd" / "even" / "mark" / "space"
timeout number 1000 读超时,单位毫秒

实例方法


open(options?)

打开串口。

sp.open({
    success: () => {},
    fail: (error: string) => {}
})

onData(callback)

注册数据接收监听,打开后会启动后台读取。

sp.onData((data: string) => {
    console.log('收到数据:', data)
})

offData()

取消数据接收监听,停止后台读取。

sp.offData()

send(data, options?)

发送文本数据。

sp.send('AT\r\n', {
    success: () => console.log('已发送'),
    fail: (e) => console.error(e)
})

sendBinary(binaryString, options?)

发送二进制数据,每个字符的 charCode 作为一个字节。

// 发送字节 0x01 0x02 0xFF
sp.sendBinary('\x01\x02\xff', {
    success: () => console.log('已发送'),
    fail: (e) => console.error(e)
})

read(length?, timeoutMs?)

同步读取指定长度的数据,返回读取到的字符串。

参数 类型 默认值 说明
length number 1024 期望读取的字节数
timeoutMs number 1000 超时时间(毫秒)
const data = sp.read(512, 2000)
if (data) {
    console.log('读到:', data)
}

close()

关闭串口,释放资源。

sp.close()

isOpen()

返回串口是否已打开。

if (sp.isOpen()) {
    sp.send('OK')
}

getConfig()

返回当前串口的实际配置(鸿蒙端实际配置可能与传入参数不同)。

const cfg = sp.getConfig()
console.log(cfg.baudRate, cfg.dataBits)

静态方法

SerialPort.getDeviceList()

获取可用串口设备列表,返回 SerialPortInfo[]。

const list = SerialPort.getDeviceList()
// [{ name: "ttyUSB0", path: "/dev/ttyUSB0", driver: "USB" }]
平台 行为
Android 扫描 USB Host 设备,识别 CP210x / CH340 / FTDI / PL2303 / Arduino 等 CDC-ACM 设备
iOS 返回空数组 [](无直接串口)
鸿蒙 调用 serialManager.getPortList()

SerialPortInfo 类型

字段 类型 说明
name string 设备展示名称
path string 用于 SerialPort 构造函数的路径
driver string 驱动类型如 "USB" / "UART" / "CDC-ACM" / "CP210x" / "CH340"
vid number USB Vendor ID(仅 Android USB 设备有值)
pid number USB Product ID(仅 Android USB 设备有值)

线程模型

为防止 IO 操作阻塞主线程导致 UI 卡死,各平台读写均在独立线程执行:

操作 Android iOS 鸿蒙
open() ✅ 后台线程 ✅ NSThread ✅ 原生异步
send() ✅ 后台线程 ✅ NSThread ✅ Promise 异步
sendBinary() ✅ 后台线程 ✅ NSThread ✅ Promise 异步
onData 回调 ✅ 守护线程循环读 ✅ RunLoop 非阻塞 ✅ setTimeout 轮询
read() ✅ 后台线程 + 等待 ⚠️ 主线程等待 ⚠️ 同步阻塞调用

read() 为同步方法,内部虽然在 Android/iOS 上使用后台线程,但调用方仍需等待返回。如需纯异步获取数据,请使用 onData 回调方式。

端口互斥

插件内部维护一个全局 openedPorts 注册表。当构造新实例时,如果发现同一路径(如 /dev/ttyUSB0)已有旧实例在使用,会自动关闭旧的再注册新的,避免端口被多个实例抢占导致通信异常。

const sp1 = new SerialPort('/dev/ttyUSB0')
sp1.open()

// 后续另一个地方又创建了同端口实例
const sp2 = new SerialPort('/dev/ttyUSB0') // 自动调用 sp1.close()
sp2.open() // sp1 已被释放,sp2 正常使用

错误码

所有错误通过 SerialError 类抛出,包含 errCode 和 errMsg。

错误码 说明
9011001 串口未打开,请先调用 open()
9011002 串口已被占用
9011003 串口设备不存在或无法访问
9011004 权限不足,无法访问串口
9011005 串口配置参数无效
9011006 数据读取超时
9011007 数据写入失败
9011008 串口通信异常
9011009 操作被中断

各平台注意事项

Android

  • 基于 Android USB Host API(UsbManager),无需 Root 权限
  • 首次打开设备时系统会弹出 USB 权限授权对话框,用户同意后即可通信
  • 使用 CDC-ACM 协议(USB Communications Device Class),兼容主流串口芯片: CP210x (Silicon Labs)、CH340 (QinHeng)、FTDI、PL2303 (Prolific)、Arduino、STM32 等
  • open() 成功后自动通过 CDC-ACM SET_LINE_CODING 控制传输配置波特率/数据位/停止位/校验位
  • send / sendBinary / open 均在独立 Thread 中执行,不阻塞主线程
  • onData 在守护线程中通过 bulkTransfer 循环读取,不消耗主线程资源
  • read() 内部起线程执行 IO,等待返回时用 5ms 间隔轮询
  • 需要在 AndroidManifest.xml 中声明 android.hardware.usb.host feature

iOS

  • 不支持直接访问硬件串口,path 需填写串口服务器的 "host:port" 格式
  • 常见串口服务器:USR-TCP232、有人 USR-W610 等
  • 底层使用 CFStream 创建 TCP Socket 连接
  • 波特率等参数需在串口服务器端配置,本插件仅透传
  • send / sendBinary / open 使用 NSThread.detachNewThreadSelector 异步执行
  • 数据接收基于 RunLoop 的 Stream 事件循环,运行在独立线程上
  • read() 在主线程等待底层流数据,建议优先使用 onData 异步回调

鸿蒙 (HarmonyOS)

  • 最低系统版本 HarmonyOS 5.1 / API 19
  • 依赖 @kit.BasicServicesKit 的 serialManager 模块
  • 打开串口时自动检查并请求权限(requestSerialRight)
  • open() / send() / sendBinary() 均为原生异步 API,不阻塞主线程
  • 后台读取采用 setTimeout 轮询方式,10ms 间隔,非阻塞
  • read() 调用 readSync 为同步阻塞,建议仅在可接受阻塞的场景使用
  • 支持 21 种波特率(50 ~ 1152000)
  • open() 成功后 getConfig() 返回硬件实际参数

综合示例

import { SerialPort } from '@/uni_modules/ep-uts-serial-port'

// Android 路径示例:getDeviceList() 返回的 USB 设备名
// const devices = SerialPort.getDeviceList()
// const androidPath = devices[0].path  // "/dev/bus/usb/001/003"
// 或直接用 VID:PID 格式
const androidPath = '10C4:EA60' // CP210x 常用 PID

// 鸿蒙 路径示例
const harmonyPath = 'ttySAC0'

// iOS 路径示例(串口服务器)
const iosPath = '192.168.1.100:8899'

// 初始化
const sp = new SerialPort(androidPath, {
    baudRate: 115200,
    dataBits: 8,
    stopBits: 1,
    parity: 'none',
    timeout: 2000
})

sp.open({
    success: () => {
        uni.showToast({ title: '串口已连接', icon: 'success' })

        // 监听回复
        sp.onData(data => {
            console.log('设备返回:', data)
            if (data.includes('OK')) {
                console.log('指令执行成功')
            }
        })

        // 发送指令
        sp.send('POWER ON\r\n')
    },
    fail: e => {
        uni.showToast({ title: '连接失败: ' + e, icon: 'error' })
    }
})

// 应用退出时关闭
// 在 onUnload / onHide 等生命周期中
sp.offData()
sp.close()

隐私、权限声明

1. 本插件需要申请的系统权限列表:

无

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

无

许可协议

MIT协议

暂无用户评论。