更新记录
1.0.0(2026-10-02) 下载此版本
1.0.0(2026-10-02)
- Android、iOS、鸿蒙三端统一的投屏接口。
- DLNA 设备搜索、连接、推流播放与全套控制。
- iOS 支持 AirPlay 接收端。
- 支持网络地址与手机本地文件投屏。
- 统一回调结构与错误码。
平台兼容性
uni-app(5.26)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| × | √ | × | × | √ | - | - | - | - |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| × | × | × | × | × | × | × | × | × | × | × | × |
其他
| 多语言 | 暗黑模式 | 宽屏模式 | 蒸汽模式 |
|---|---|---|---|
| × | × | √ | × |
msh-dlna-cast 投屏插件
把手机上的媒体推到同一局域网内的电视、盒子或音箱播放的 uni-app 原生插件。
手机负责发现设备、下发播放地址和控制指令,画面与声音都在接收端输出。同一套 JavaScript 接口,同时支持 Android、iOS、鸿蒙 NEXT。
- 插件 ID:
msh-dlna-cast(单个 UTS 插件,同时覆盖 Android、iOS、鸿蒙) - 支持协议:DLNA(UPnP AV);iOS 额外支持 AirPlay
- 媒体来源:网络地址(
http/https)、手机本地文件 - 当前版本:1.0.0
概述
功能
| 能力 | 说明 |
|---|---|
| 设备发现 | SSDP 组播搜索局域网内的投屏设备,持续上报;iOS 同时搜索 AirPlay 接收端 |
| 设备连接 | 同一时间保持一台设备,可随时切换 |
| 推流播放 | 推送 http / https 地址,或手机本地文件(插件自建临时 HTTP 服务) |
| 播放控制 | 播放、暂停、继续、从头播放、停止 |
| 进度控制 | 查询时长与进度,拖动跳转,快进 / 快退 10 秒 |
| 音量控制 | 绝对音量 0–100、静音与取消静音 |
| 状态上报 | 状态、进度、时长、音量变化实时回调 |
| 网络信息 | 读取本机 Wi-Fi IPv4 |
特点
- 三端一套 API。方法名、参数、回调结构、错误码完全一致,业务代码只写一份,用设备的
protocol字段区分DLNA与AIRPLAY,不需要按平台写分支。 - 统一回调格式。所有方法都返回
{ code, message, data },成功code === 0,失败给出中文message和明确的错误码。 - 本地文件不用先上传。插件在手机上起临时 HTTP 服务,把终端可访问的地址推给设备,播放结束或页面销毁时自动停止。
- iOS 同时覆盖两类设备。DLNA 设备插件直连;AirPlay 设备通过系统投屏路由连接。
不支持
- 不支持屏幕镜像、投屏画面录制。
- 不支持 Miracast、Chromecast。
- 不支持字幕、播放列表、多设备同时播放、倍速播放。
- 不支持小程序、H5、uni-app x。
平台兼容性
| 平台 | 最低版本 | 引擎实现 | 协议 |
|---|---|---|---|
| Android | Android 5.0(API 21)及以上 | 纯 Java,无 native 库,不区分 CPU 架构 | DLNA |
| iOS | iOS 15.0 及以上 | Swift(arm64 真机,不含模拟器切片) | DLNA、AirPlay |
| 鸿蒙 NEXT | API 12 及以上 | ArkTS(arm64) | DLNA |
三端共用同一个 uni_modules/msh-dlna-cast 插件。Android 侧引擎编译为 jar、iOS 与鸿蒙侧为源码混编,对使用者都是透明的。
- 仅支持 App(Vue 3 的
App-vue)。小程序、H5、nvue、uni-app x 不适用。需要 HBuilderX 4.25 及以上。 - 插件带原生配置(Android 权限、iOS 本地网络说明、引擎依赖),必须制作自定义调试基座,标准基座不含这些。HBuilderX 编译时会提示。
- 模拟器收不到局域网组播,请用真机调试。
快速开始
1. 引入插件
把 uni_modules/msh-dlna-cast 整个目录放入你的工程(三端都用这一个目录,插件内部按平台分目录)。无需在 manifest.json 里勾选本地插件,uni_modules 会被自动识别。
引入模块:
// common/dlna.js —— 三端统一入口
import * as DlnaCast from '@/uni_modules/msh-dlna-cast'
let cached = null
export function getDlnaPlugin() {
if (cached) return cached
cached = DlnaCast
return cached
}
插件导出的是顶层函数(startSearch、play、onDeviceFound 等),用 import * as 整体引入。三端方法名相同,不需要按平台写条件编译。也可以不经这层封装,直接 import * as dlna from '@/uni_modules/msh-dlna-cast'。
2. 制作自定义基座
- 在 HBuilderX 中打开工程。
- 运行 → 运行到手机或模拟器 → 制作自定义调试基座。
- 制作完成后,用该基座真机运行。
3. 最小可用流程
import { getDlnaPlugin } from '@/common/dlna.js'
const dlna = getDlnaPlugin()
// 先注册事件
dlna.onDeviceFound((res) => {
if (res.code !== 0) return
console.log('发现设备', res.data.name, res.data.protocol)
})
dlna.onStateChange((res) => {
if (res.code !== 0) return
console.log(res.data.state, res.data.position, res.data.duration)
})
// 搜索
dlna.startSearch({ timeout: 8000 }, (res) => {
if (res.code === 0) console.log('搜索已启动')
if (res.code === 1001) console.log('未发现设备')
})
// 选择设备(id 来自 onDeviceFound)
dlna.selectDevice({ id: deviceId }, (res) => {
if (res.code !== 0) return
// 播放
dlna.play({
url: 'https://player.alicdn.com/video/aliyunmedia.mp4',
title: '示例视频',
mimeType: 'video/mp4'
}, (playRes) => {
console.log('播放', playRes.code, playRes.data.url)
})
})
// 控制
dlna.pause((res) => {})
dlna.resume((res) => {})
dlna.seek({ position: 30000 }, (res) => {})
dlna.setVolume({ volume: 30 }, (res) => {})
dlna.stop((res) => {})
4. 使用前检查
手机与电视必须在同一个 Wi-Fi,路由器未开启 AP 隔离,电视已开启 DLNA / 媒体渲染功能。
Android 需在 manifest.json 中允许明文 HTTP。电视的描述地址和控制地址是 HTTP,未开启时选设备或播放会失败:
{
"app-plus": {
"android": {
"usesCleartextTraffic": true
}
}
}
iOS 访问 HTTP 所需的 ATS 已写在插件的 Info.plist 里,打包时会合并进 App。
完整的环境配置、权限配置、Demo 验证清单和排查方法,见 docs/使用手册.md。
接口
回调统一为 { code, message, data }。code === 0 表示成功;成功时 message 为 "";无数据时 data 为 {}。
普通方法为 method(options, callback);无参数时为 method(callback);事件监听为 onXxx(callback),后一次注册覆盖前一次。
除搜索、getLocalIp 和事件注册外,未连接设备时返回 1003。
startSearch 的 callback 保持不释放,最多回调两次:搜索启动成功立刻返回 { code: 0, message: "", data: {} };本次搜索在 timeout 内一台设备都没有时,再返回 { code: 1001, message: "未发现设备", data: {} }。已经发现过至少一台,则超时不再返回 1001。搜索进行中再次调用 startSearch,重新计时并继续搜索。
| 方法 | 作用 | 参数 | 成功时 data |
|---|---|---|---|
startSearch |
开始搜索,设备只从 onDeviceFound 上报 |
{ timeout } 可空,毫秒,默认 8000 |
{} |
stopSearch |
停止搜索。停止后不再回调本次的 1001 |
无 | {} |
onDeviceFound |
发现设备 | 回调 | 设备对象 |
onDeviceLost |
设备离线 | 回调 | { id } |
selectDevice |
连接设备,替换当前连接 | { id } 必填 |
设备对象 |
play |
开始播放,替换当前媒体 | { url } 必填,{ title, mimeType } 可空 |
{ url } |
pause |
暂停,保留进度 | 无 | {} |
resume |
从当前进度继续 | 无 | {} |
replay |
从头播放 | 无 | {} |
stop |
结束播放,设备选择保留 | 无 | {} |
getState |
播放状态 | 无 | { state } |
getDuration |
总时长 | 无 | { duration } 毫秒 |
getPosition |
当前进度 | 无 | { position, duration } 毫秒 |
getVolume |
当前音量 | 无 | { volume, mute } |
setVolume |
音量调节 | { volume } 必填,0–100 整数 |
{ volume } |
setMute |
静音开关 | { mute } 必填,布尔 |
{ mute, volume } |
seek |
跳到指定位置 | { position } 必填,毫秒 |
{ position } |
fastForward |
快进 10 秒 | 无 | { position } |
rewind |
快退 10 秒 | 无 | { position } |
getLocalIp |
本机 Wi-Fi IPv4 | 无 | { ip } |
onStateChange |
状态、进度、音量变化 | 回调 | { state, position, duration, volume, mute } |
设备对象
onDeviceFound 与 selectDevice 成功时的 data:
{
"id": "设备 UUID",
"name": "客厅电视",
"protocol": "DLNA",
"location": "设备描述地址",
"manufacturer": "厂商",
"model": "型号"
}
| 字段 | 类型 | 说明 |
|---|---|---|
id |
string | 设备唯一标识,selectDevice 用它连接。AirPlay 设备的 id 以 airplay: 开头 |
name |
string | 显示名 |
protocol |
string | DLNA 或 AIRPLAY。Android / 鸿蒙只有 DLNA |
location |
string | 设备描述地址,AirPlay 设备可能为空 |
manufacturer |
string | 厂商,取不到为 "" |
model |
string | 型号,取不到为 "" |
播放状态
PLAYING、PAUSED、STOPPED、TRANSITIONING、NO_MEDIA、ERROR。
错误码
| code | 含义 |
|---|---|
0 |
成功 |
1001 |
搜索超时,未发现设备 |
1002 |
设备离线或无响应 |
1003 |
尚未选择设备 |
1004 |
播放失败 |
1005 |
缺少必填字段、地址无效,或本地文件不存在 |
1007 |
未连接 Wi-Fi,无法取得 IPv4 |
1008 |
缺少本地网络或组播权限 |
1009 |
当前媒体不支持该操作 |
1010 |
网络已切换,连接失效 |
本地文件投屏
play 的 url 传手机本地文件的绝对路径(以 / 开头,不带 file://)。插件会在手机上启动临时 HTTP 服务,回调里的 data.url 是终端可访问的 http 地址。
uni.chooseVideo({
sourceType: ['album'],
compressed: false,
success: (res) => {
let path = res.tempFilePath || ''
if (typeof plus !== 'undefined' && plus.io && plus.io.convertLocalFileSystemURL) {
path = plus.io.convertLocalFileSystemURL(path)
}
if (path.indexOf('file://') === 0) path = path.substring(7)
dlna.play({ url: path, title: '本地视频' }, (playRes) => {
if (playRes.code === 0) console.log('终端地址', playRes.data.url)
})
}
})
content:// 和其他相对路径返回 1005。
iOS 说明
两类设备的用法差异
| DLNA 设备 | AIRPLAY 设备 | |
|---|---|---|
protocol |
DLNA |
AIRPLAY |
| 选中后 | 插件直接连接 | 只完成选中,画面不出本机。插件会在当前窗口底部挂上系统投屏按钮 |
| 播放前 | 直接 play |
先点该按钮,在系统列表里选定接收端,再 play |
| 音量 | 可用 setVolume |
走系统音量,接收端不跟随时返回 1009 |
AirPlay 是把视频推到接收端,不是屏幕镜像。投到 Mac 等不跟随系统音量的接收端时,中间音量返回 1009,请用接收端自身的音量控制;0 音量仍通过播放器静音保证生效。
权限与配置
插件已在 uni_modules/msh-dlna-cast/utssdk/app-ios/Info.plist 写入本地网络说明、Bonjour 和 ATS。云端打包时合并进 App,不用在 manifest.json 里再写一遍。
| 键 | 作用 |
|---|---|
NSLocalNetworkUsageDescription |
本地网络用途说明。缺少时系统不弹授权框,搜索失败 |
NSBonjourServices(_airplay._tcp) |
发现 AirPlay 接收端 |
NSAppTransportSecurity |
允许访问 HTTP 地址 |
首次运行会弹出「允许访问本地网络」,必须点允许。若曾拒绝,到系统设置里重新打开。
组播权限 com.apple.developer.networking.multicast 当前没有写进 UTS.entitlements。插件把 M-SEARCH 发往 239.255.255.250:1900,iOS 16 及以上搜不到设备时,常见原因是描述文件里没有这项能力。描述文件尚未包含它时写进 entitlements,制作基座或云打包会因签名不一致失败。
本机 IPv4 用 getifaddrs 读取,不使用 com.apple.developer.networking.wifi-info(该权限只用于读取 SSID/BSSID,需另行申请)。
组播权限配置步骤
第 1 步:申请组播权限(一次性,需 Apple 审核)
用开发者主账号访问 Apple 组播权限申请页 提交申请。审核通过后(通常约 3 天):
- 进入 Apple Developer 账号的 Certificates, Identifiers & Profiles;
- 账号下会多出一项
Additional Capabilities,勾选Multicast Networking; - 重新生成并下载描述文件(Provisioning Profile)。
第 2 步:描述文件包含该能力后,再写入插件
在 uni_modules/msh-dlna-cast/utssdk/app-ios/UTS.entitlements 中加入:
<key>com.apple.developer.networking.multicast</key>
<true/>
插件的 entitlements 必须与 App 描述文件一致。描述文件里还没有这项时,保持 UTS.entitlements 为空。
第 3 步:重新制作自定义调试基座
旧基座不带新的描述文件。改完后重新制作基座,再用该基座真机运行。
隐私、权限声明
1. 本插件需要申请的系统权限列表
Android
| 权限 | 用途 |
|---|---|
android.permission.INTERNET |
发现设备、下发播放地址、发送控制指令 |
android.permission.ACCESS_NETWORK_STATE |
判断当前网络状态 |
android.permission.ACCESS_WIFI_STATE |
读取 Wi-Fi 信息与本机 IPv4 |
android.permission.CHANGE_WIFI_MULTICAST_STATE |
SSDP 组播搜索设备 |
iOS
| 权限 | 用途 |
|---|---|
本地网络(NSLocalNetworkUsageDescription) |
搜索并连接局域网内的投屏设备 |
组播(com.apple.developer.networking.multicast) |
收发 SSDP 组播。需向 Apple 申请;描述文件包含该能力后再写入 UTS.entitlements,当前插件文件里没有这项 |
Bonjour(NSBonjourServices: _airplay._tcp) |
发现 AirPlay 接收端 |
不使用
com.apple.developer.networking.wifi-info:本插件用getifaddrs读取本机 IPv4,不读取 SSID/BSSID。
鸿蒙
| 权限 | 用途 |
|---|---|
ohos.permission.INTERNET |
网络访问 |
ohos.permission.GET_NETWORK_INFO |
网络状态 |
ohos.permission.GET_WIFI_INFO |
Wi-Fi 信息与本机 IPv4 |
2. 本插件采集的数据、发送的服务器地址、以及数据用途说明
无。插件不采集、不上传任何个人数据,不包含统计或埋点。所有网络行为都发生在局域网内:向局域网发送 SSDP 搜索广播、访问设备描述地址、向设备下发播放与控制指令。播放本地文件时,插件在本机启动的临时 HTTP 服务只监听局域网,并随页面销毁停止。
3. 本插件是否包含广告
否。不包含任何广告。
常见问题
| 现象 | 原因与处理 |
|---|---|
搜索一台都没有,返回 1001 |
手机与电视不在同一 Wi-Fi,或路由器开启了 AP 隔离 |
| 列表里没有电视 | 电视未开启 DLNA / 媒体渲染 |
| 提示「基座里没有 msh-dlna-cast 方法」或「插件未生效」 | 使用了标准基座。插件带原生配置,必须制作自定义调试基座 |
返回 1008 |
iOS 未授权本地网络,或未申请组播权限;Android 缺组播权限 |
iOS 上 startSearch 返回成功,但始终搜不到设备 |
先确认已允许本地网络;仍不行再按 iOS 权限与配置 补组播 entitlement 并重做基座 |
| 云打包报错,提示与某个原生 SDK 冲突 | 逐个取消勾选可能冲突的第三方原生插件或广告联盟 SDK 后重新打包,定位具体冲突项 |
返回 1007 |
手机未连接 Wi-Fi |
| 选设备或播放失败,提示未允许明文 HTTP | Android 需开启 usesCleartextTraffic |
部分电视静音返回 1009 |
该电视不支持静音指令 |
AirPlay 调中间音量返回 1009 |
接收端不跟随手机音量,请用接收端音量控制 |
| 播放中切换 Wi-Fi 后失效 | 返回 1010,需重新搜索并选择设备 |
| 切到后台不再发现设备 | 搜索只在应用前台进行,回到前台需重新搜索 |
| 本地文件投屏后电视打不开 | 手机与电视不在同一 Wi-Fi,电视访问不到临时 HTTP 服务 |
| 离线打包后启动报「未配置appkey或配置错误」 | 离线SDK 强制要求 AppKey(云打包不需要)。到 dev.dcloud.net.cn → 应用管理 → 各平台信息 → 创建 Android 离线AppKey,填包名 + 签名SHA1;AppKey 绑定 appid + 包名 + 签名SHA1 三者,换证书或换包名都要重新申请 |
更新记录
1.0.0
- Android、iOS、鸿蒙三端统一的投屏接口。
- DLNA 设备搜索、连接、推流播放与全套控制。
- iOS 支持 AirPlay 接收端。
- 支持网络地址与手机本地文件投屏。
- 统一回调结构与错误码。
目录结构
| 目录 | 内容 |
|---|---|
dlna-cast-demo/uni_modules/msh-dlna-cast/ |
UTS 插件本体(三端实现都在这) |
android/ |
Android 引擎源码,编译出引擎 jar 供插件调用 |
ios/ |
iOS 引擎源码(Swift),直接混编进插件 |
harmony/ |
鸿蒙 NEXT 引擎源码(ArkTS),直接混编进插件 |
dlna-cast-demo/ |
uni-app 接入示例 |
docs/ |
使用手册与接入文档 |
scripts/ |
源码同步与本地构建脚本 |
三端源码的真源在 android/、ios/、harmony/,用 ./scripts/sync-demo-plugins.sh 同步进插件。改原生代码改源码目录,不要直接改插件里的副本。
相关文档
- 使用手册:完整的环境配置、权限配置、接口详解、Demo 运行步骤与排查方法。
技术支持
使用中遇到问题,请一并提供以下信息,便于快速定位:
- 平台与系统版本(Android / iOS / 鸿蒙的具体版本)
- 手机型号与接收端设备的品牌型号
- 调用方法与完整的
{ code, message, data }回调内容 - 是否已确认手机与电视处于同一 Wi-Fi

收藏人数:
下载插件并导入HBuilderX
下载示例项目ZIP
赞赏(0)
下载 3
赞赏 0
下载 12650710
赞赏 1953
赞赏
京公网安备:11010802035340号