更新记录
1.0.0(2026-05-11)
双网络控制 UTS 插件,支持 TCP 服务端、HTTP 请求、WebSocket 连接按需绑定到指定网卡(网线/WiFi/蜂窝)。
平台兼容性
uni-app(5.05)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | × | × | √ | √ | √ | √ | - |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - | - | - | - |
uni-app x(5.05)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| - | - | - | - | - | - |
其他
| 多语言 | 暗黑模式 | 宽屏模式 |
|---|---|---|
| × | × | √ |
L-DualNetworkPlugin
双网络控制 UTS 插件,支持 TCP 服务端、HTTP 请求、WebSocket 连接按需绑定到指定网卡(网线/WiFi/蜂窝)。
插件开发使用版本5.05,其他版本是否支持请自测。
导入
import {
getAllNetworks,
isEthernetAvailable,
isCellularAvailable,
bindProcessToCellularNetwork,
bindProcessToWiFiNetwork,
bindProcessToEthernetNetwork,
restoreProcessNetwork,
startTcpServer,
stopTcpServer,
isTcpServerRunning,
getBoundNetworkType,
getClientCount,
getClientAddresses,
sendToClient,
sendToAll,
sendHexStrToClient,
sendHexStrToAll,
setOnClientConnect,
setOnClientDisconnect,
setOnClientMessage,
httpGet,
httpPost,
wsConnect,
wsSend,
wsClose,
wsIsConnected,
} from '@/uni_modules/L-DualNetworkPlugin'
networkType 参数
| 值 | 含义 |
|---|---|
"ethernet" |
以太网(网线) |
"wifi" |
WiFi |
"cellular" |
蜂窝数据(流量卡) |
一、网络检测
getAllNetworks()
获取设备当前全部可用网络。
const nets = getAllNetworks()
// {
// success: true,
// msg: "共 2 个网络",
// networks: [
// { type: "ethernet", typeDesc: "以太网(网线)" },
// { type: "wifi", typeDesc: "WiFi" },
// { type: "cellular", typeDesc: "蜂窝网络" }
// ]
// }
isEthernetAvailable()
if (isEthernetAvailable()) { /* 网线可用 */ }
isCellularAvailable()
if (isCellularAvailable()) { /* 蜂窝可用 */ }
二、进程网络强制绑定
以下方法会调用 Android 系统的 ConnectivityManager.bindProcessToNetwork(),强制当前进程中所有网络流量走指定网卡。
⚠️ 重要警告:使用后将全局锁定进程网络。例如绑定到蜂窝后,TCP Server 将无法接收来自 WiFi/Ethernet 的连接。建议仅在明确需要全进程网络切换的场景使用,常规 HTTP/WS 请求请直接用
httpGet/httpPost/wsConnect的networkType参数按连接指定网卡。
bindProcessToCellularNetwork()
const res = bindProcessToCellularNetwork()
// { success: true, msg: "已绑定进程网络到蜂窝数据", networkType: "cellular" }
bindProcessToWiFiNetwork()
const res = bindProcessToWiFiNetwork()
// { success: true, msg: "已绑定进程网络到 WiFi", networkType: "wifi" }
bindProcessToEthernetNetwork()
const res = bindProcessToEthernetNetwork()
// { success: true, msg: "已绑定进程网络到以太网", networkType: "ethernet" }
restoreProcessNetwork()
恢复为系统默认网络:
const res = restoreProcessNetwork()
// { success: true, msg: "已恢复默认网络" }
三、TCP 服务端
启动时自动检测网络,按 网线 > WiFi > 默认 优先级选择,返回绑定 IP。
startTcpServer(port, callback)
startTcpServer(8080, (res) => {
if (res.success) {
// res.networkType: "ethernet" | "wifi" | "default"
// res.ipAddress: 该网络下的 IPv4 地址,如 "192.168.1.100"
console.log('TCP 服务启动成功,端口:', 8080)
} else {
console.log('启动失败:', res.msg)
}
})
监听客户端事件
setOnClientConnect((res) => {
// res.clientKey: 客户端 IP,如 "192.168.1.50"
// res.clientCount: 当前在线客户端数
console.log('客户端连接:', res.clientKey)
})
setOnClientDisconnect((res) => {
console.log('客户端断开:', res.clientKey, '剩余:', res.clientCount)
})
setOnClientMessage((res) => {
console.log('收到来自', res.clientKey, ':', res.data)
// res.dataBinary: 原始 ByteArray
})
发送数据
// 普通文本
sendToClient('192.168.1.100', 'Hello Client') // → boolean
sendToAll('广播消息') // → boolean
// 十六进制
sendHexStrToClient('192.168.1.100', 'AABBCCDD') // → boolean
sendHexStrToAll('AABBCCDD') // → void
查询状态
getClientCount() // → number 在线客户端数量
getClientAddresses() // → string[] 客户端 IP 列表
isTcpServerRunning() // → boolean
getBoundNetworkType() // → "ethernet" | "wifi" | "default"
stopTcpServer(callback)
stopTcpServer((res) => {
console.log(res.success ? '已关闭' : '关闭失败:', res.msg)
})
App 销毁时自动停止服务端,无需手动处理。
四、HTTP(异步回调)
底层使用 Android HttpURLConnection,通过 Network.openConnection() 绑定到指定网卡。
httpGet(networkType, url, callback, params?, headers?)
// 最简调用
httpGet('cellular', 'https://api.example.com/status', (res) => {
if (res.error) {
console.error('请求失败:', res.error)
return
}
console.log('HTTP', res.code, '响应:', res.data)
})
// 带 params(query string 格式)
httpGet('wifi', 'https://api.example.com/list', (res) => {
console.log(res.data)
}, 'pageNum=1&pageSize=10&keyword=测试')
// → URL: https://api.example.com/list?pageNum=1&pageSize=10&keyword=测试
// 带 headers(格式: "key1:val1|key2:val2")
httpGet('wifi', 'https://api.example.com/data', (res) => {},
null,
'Authorization:Bearer xxx|Accept:application/json')
返回值 HttpResult
| 字段 | 类型 | 说明 |
|---|---|---|
code |
number |
HTTP 状态码,-1 表示请求失败 |
data |
string |
响应体字符串 |
error |
string |
错误信息,成功时为空 |
httpPost(networkType, url, body, contentType, callback, headers?)
httpPost('cellular', 'https://api.example.com/submit',
JSON.stringify({ key: 'value' }), // 请求体
'application/json', // Content-Type
(res) => {
console.log('状态码:', res.code, '响应:', res.data)
},
'Authorization:Bearer xxx' // headers(可选)
)
headers 格式
多个 header 用 | 分隔,每个 header 格式为 key:value:
"Authorization:Bearer eyJhbGciOiJ|Content-Type:application/json|X-Custom:haha"
五、WebSocket(异步回调,内置心跳检测)
底层自实现 WebSocket 协议,通过 Network.socketFactory 创建 Socket 绑定到指定网卡。
wsConnect(networkType, url, onOpen, onMessage, onClose, onError)
wsConnect(
'wifi', // 网卡类型
'wss://ws.example.com/socket', // URL(支持 ws:// 和 wss://)
() => {
console.log('WebSocket 已连接')
wsSend(JSON.stringify({ type: 'hello' }))
},
(data) => {
console.log('收到消息:', data)
const msg = JSON.parse(data) // 消息为 JSON 字符串
},
() => {
console.log('WebSocket 已断开')
},
(error) => {
console.error('WebSocket 错误:', error)
}
)
发送/关闭/状态
wsSend(JSON.stringify({ type: 'ping' }))
wsSend('纯文本消息')
wsClose()
wsIsConnected() // → boolean
当前仅支持一个 WS 连接。调用
wsConnect会自动关闭旧连接。
心跳检测(内置,无需配置)
| 参数 | 默认值 | 说明 |
|---|---|---|
| Ping 间隔 | 30 秒 | 客户端定期发送 Ping 帧 |
| Pong 超时 | 10 秒 | 发 Ping 后等待 Pong 回执 |
| 断线判定 | 40 秒 | 累计无响应 → 自动断开 + onError("连接超时,服务器无响应") |
服务端发来的 Ping 自动回复 Pong,不影响上层业务。
六、http请求封装示例
提供了 Promise 风格的 HTTP 封装,集成 baseURL + token 注入 + 响应拦截:
import globalConfig from '@/common/config/config.js'
import store from '@/store/index.js'
import dialog from '@/common/utils/dialog.js'
import router from '@/common/utils/router.js'
// #ifdef APP-PLUS
import {
httpGet,
httpPost
} from '@/uni_modules/L-DualNetworkPlugin'
// #endif
function buildHeaders(customHeaders) {
const parts = []
const token = store.state.token
if (token) {
parts.push('Authorization:' + token)
}
if (customHeaders) {
Object.entries(customHeaders).forEach(([k, v]) => {
parts.push(k + ':' + v)
})
}
return parts.length > 0 ? parts.join('|') : null
}
function handleResponse(res, resolve, reject, options) {
if (res.error) {
dialog.toast(res.error)
reject({
code: -1,
msg: res.error
})
return
}
let data
try {
data = res.data ? JSON.parse(res.data) : {}
} catch (e) {
dialog.toast('数据解析失败')
reject({
code: -1,
msg: '数据解析失败'
})
return
}
if (data.code === 200 || data.success) {
if (data.msg && options?.toast) {
dialog.toast(data.msg)
}
resolve(data)
} else if (data.code === 401) {
store.commit('$CGStore', {
name: 'token',
value: ''
})
store.commit('$CGStore', {
name: '$userInfo',
value: ''
})
dialog.confirm({
content: '登录已过期,请重新登录',
cancelText: '取消',
confirmText: '去登录'
}).then(() => {
router.replace('/pages/login/index')
})
reject(data)
} else {
if (options?.toast !== false) {
dialog.toast(data.msg || '请求失败')
}
if (options?.catch !== false) {
reject(data)
}
}
}
function request(config) {
const {
url,
method = 'GET',
data,
params,
headers,
networkType = globalConfig.networkType, // 网卡类型(wifi/cellular/ethernet)
baseURL = globalConfig.baseURL,
...options
} = config
const fullUrl = baseURL + url
const headerStr = buildHeaders(headers)
return new Promise((resolve, reject) => {
if (method === 'GET') {
let queryStr = null
if (params) {
queryStr = Object.entries(params)
.map(([k, v]) => encodeURIComponent(k) + '=' + encodeURIComponent(String(v)))
.join('&')
}
httpGet(networkType, fullUrl, (res) => {
handleResponse(res, resolve, reject, options)
}, queryStr, headerStr)
} else {
const body = data ? JSON.stringify(data) : '{}'
httpPost(networkType, fullUrl, body, 'application/json', (res) => {
handleResponse(res, resolve, reject, options)
}, headerStr)
}
})
}
const http = {
get(url, config) {
return request({
...config,
url,
method: 'GET'
})
},
post(url, data, config) {
return request({
...config,
url,
method: 'POST',
data
})
}
}
export default http
// ==================== 业务接口 ====================
export function getList(data) {
return http.get('/api/list', {
params: data
})
}
export function add(data) {
return http.post('/api/add', data)
}
import http, { getList } from '@/api/api.js'
// Promise 风格
getList({ cur: '1', date: '2026-05-11' })
.then(res => console.log('成功:', res))
.catch(err => console.error('失败:', err))
// 指定网卡
http.get('/api/list', { params: { date: '2026-05-11' }, networkType: 'cellular' })
http.post('/api/add', data, { networkType: 'cellular' })
七、API 速查表
| API | 签名 | 说明 |
|---|---|---|
getAllNetworks |
() → AllNetworksResult |
获取全部可用网络 |
isEthernetAvailable |
() → boolean |
网线是否可用 |
isCellularAvailable |
() → boolean |
蜂窝是否可用 |
bindProcessToCellularNetwork |
() → DualNetworkResult |
进程绑定到蜂窝(全局) |
bindProcessToWiFiNetwork |
() → DualNetworkResult |
进程绑定到 WiFi(全局) |
bindProcessToEthernetNetwork |
() → DualNetworkResult |
进程绑定到以太网(全局) |
restoreProcessNetwork |
() → DualNetworkResult |
恢复进程默认网络 |
startTcpServer |
(port, callback) |
启动 TCP 服务端 |
stopTcpServer |
(callback) |
关闭 TCP 服务端 |
isTcpServerRunning |
() → boolean |
服务是否运行中 |
getBoundNetworkType |
() → string |
绑定网络类型 |
getClientCount |
() → number |
在线客户端数 |
getClientAddresses |
() → string[] |
客户端 IP 列表 |
sendToClient |
(key, msg) → boolean |
发文本给客户端 |
sendToAll |
(msg) → boolean |
广播文本 |
sendHexStrToClient |
(key, hex) → boolean |
发十六进制给客户端 |
sendHexStrToAll |
(hex) → void |
广播十六进制 |
setOnClientConnect |
(cb) |
客户端连接回调 |
setOnClientDisconnect |
(cb) |
客户端断开回调 |
setOnClientMessage |
(cb) |
客户端消息回调 |
httpGet |
(net, url, cb, params?, headers?) |
HTTP GET |
httpPost |
(net, url, body, ct, cb, headers?) |
HTTP POST |
wsConnect |
(net, url, onOpen, onMsg, onClose, onErr) |
WebSocket 连接 |
wsSend |
(msg) |
WS 发送消息 |
wsClose |
() |
WS 关闭连接 |
wsIsConnected |
() → boolean |
WS 连接状态 |
八、类型定义
type NetworkInfo = { type: string, typeDesc: string }
type AllNetworksResult = {
success: boolean, msg: string, networks: NetworkInfo[]
}
type DualNetworkResult = {
success: boolean, msg: string, networkType?: string
}
type TcpServerResult = {
success: boolean, msg: string, networkType?: string, ipAddress?: string
}
type ClientConnectResult = {
clientKey: string, clientCount: number
}
type ClientMessageResult = {
clientKey: string, data: string, dataBinary?: ByteArray
}
type HttpResult = {
code: number, data: string, error: string
}
九、注意事项
- 需要自定义基座调试:插件包含 Kotlin 原生代码,修改
.uts/.kt文件后需重新打包自定义基座 - Android 6.0+ (API 23):
bindProcessToNetwork需要 API 23,config.json已设置minSdkVersion: 23 - 进程网络绑定会全局生效:调用
bindProcessToCellularNetwork/bindProcessToWiFiNetwork/bindProcessToEthernetNetwork后,进程中所有网络流量都将走指定网卡,包括 TCP Server。如需恢复默认网络,调用restoreProcessNetwork() - HTTP 是异步回调:请求在后台线程执行,不影响 UI
- WebSocket 仅支持一个连接:
wsConnect会自动关闭旧连接 - HTTPS 自签名证书:插件内置 TrustAll 策略,生产环境建议替换

收藏人数:
购买普通授权版(
试用
赞赏(0)
下载 0
赞赏 0
下载 11858947
赞赏 1912
赞赏
京公网安备:11010802035340号