十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

UniApp + LiveKit:Android 端为什么要用原生做屏幕共享,以及我们怎么落地的

UniApp + LiveKit:Android 端为什么要用原生做屏幕共享,以及我们怎么落地的 一、背景同一套会议三端能力并不对等项目里会议能力基于 LiveKit。H5 / PC 端用navigator.mediaDevices.getDisplayMedia()就能发起屏幕共享但在 App 内嵌 WebView尤其 Android 上这条路基本走不通。H5 会议室里对「能不能共享」有明确判断原因可以概括成三点API 能力手机浏览器 / WebView 普遍不支持getDisplayMedia即便有也多是桌面 Chrome 那一套。系统权限模型Android 录屏走的是 MediaProjection必须弹系统授权页拿Intent结果才能采屏WebView 拿不到这条系统链路。进程与生命周期投屏在 Android 10 要求mediaProjection类型前台服务 常驻通知纯 H5 很难稳定满足切后台就容易被杀或采集中断。因此产品策略是端会议室实现屏幕共享H5 / PCLiveKit JSgetDisplayMediaiOS Appweb-view加载 hybrid 页基本不支持发起Android AppUTS 原生MeetingActivityMediaProjection LiveKit Android SDK二、整体架构JS 壳 UTS 桥 Kotlin 原生会议室不是「整 App 重写成原生」而是 只把会议室含投屏下沉到 Android 原生业务壳仍在 UniApp。关键模块uni_modules/yn-livekit-meetingUTS 插件依赖livekit-android:2.28.0MeetingActivity.kt会议室 UI、进房、订阅、投屏ScreenShareService.ktmediaProjection前台服务common/livekit/meeting-native.jsVue 侧桥接subpages/meeting/room.vueAndroid 透明壳负责凭证与业务 API进房时壳页拿到 LiveKiturl/token后调用三、为什么必须走 Android 原生MediaProjection 机制Android 从 API 21 起用 MediaProjection 做「用户授权后的屏幕采集」通过MediaProjectionManager.createScreenCaptureIntent()拉起系统授权界面用户同意后ActivityResult带回RESULT_OKdata Intent用这份Intent创建MediaProjection再从 VirtualDisplay 采帧LiveKit Android SDK 封装了后续编码 / 发布业务侧只要把授权结果塞进ScreenCaptureParams对应代码在toggleShare()这就是「必须原生」的核心系统授权页只能由 Activity 发起授权结果也只能由原生拿回。WebView 里的 JS 过不了这道关。四、实现拆解从点击「共享屏幕」到对端看到画面1. Manifest权限 前台服务类型Android 14 对前台服务类型校验更严mediaProjection声明缺失会直接启动失败。2. 授权回调先起前台服务再打开 LiveKit 屏幕轨顺序很重要用户授权成功立刻ScreenShareService.start()前台通知再setScreenShareEnabled(true, ScreenCaptureParams(...))失败则停服务、回滚 UI授权弹窗期间可能有人已经开了共享所以回来后还要再判一次互斥。3. 把系统授权结果交给 LiveKit这里业务代码不自己管 VirtualDisplay / 编码只做两件事把系统Intent交给 SDK在onStop里停掉自己的前台服务LiveKit 会发布Track.Source.SCREEN_SHARE对端H5/PC/原生按屏幕轨订阅即可。4. 前台服务为什么「多写一个 Service」要点Android 10 使用 MediaProjection 时需要符合策略的前台服务否则系统会中断采集通知文案「正在共享屏幕点按返回会议」并PendingIntent回MeetingActivitystartForegroundService/STOP_FOREGROUND_REMOVE成对出现停止共享、离开会议、异常失败都要ScreenShareService.stop()五、业务细节不只是「能采屏」1. 全员互斥同时只允许一路屏幕共享发起前、授权回来后都检查shareFromId远端已有人共享时本端误开会主动停掉H5 侧同样有「已有人在共享屏幕」逻辑两端产品规则一致。2. 识别屏幕轨兼容 source / name这样和 JS 侧判断对齐避免不同端/SDK 版本字段差异导致「共享了但大屏不切」。3. 渲染坑GONE 时不要 init TextureView共享大屏用TextureViewRenderer。注释里写得很实在shareRenderer只 init 一次GONE 时 init 会导致 Surface 黑屏要先把容器设为VISIBLE再post { bindShareRenderer }这是 WebRTC/Android 渲染里的常见坑Surface 还没就绪就绑轨画面会一直黑。4. 停共享后恢复摄像头stopShareView会停服务、清状态若本端之前开着摄像头再restoreLocalCamera()避免「停共享后摄像头再也开不回来」。5. 状态同步回 UniApp 壳原生通过MeetingBridge.emit(media, { screen: true/false })入队room.vue短轮询pollMeetingNativeEvent()再调业务侧apiMeetingMedia让成员列表 / IM 状态和真实媒体轨一致。六、完整时序七、工程侧注意点必须自定义调试基座 / 云打包标准基座不含 LiveKit 原生依赖config.json里声明了io.livekit:livekit-android:2.28.0等 Maven 依赖要由 HBuilderX 编进基座。UTS 分层Vue →meeting-native.js→index.uts→MeetingLauncherJava→MeetingActivityKotlin。Java 入口是为了避免 UTS 直接啃 Kotlin Companion / 类型转换翻车。双端体验策略Android 用原生补齐投屏iOS 仍走 web-view共享提示不支持——先保证主端能力而不是强行一套 Web 通吃。八、总结Android App 里做会议屏幕共享本质不是「LiveKit API 换一个写法」而是系统能力MediaProjection 前台服务只能原生拿到直播推流LiveKit在拿到授权后再发布屏幕轨UniApp 继续做业务壳。若坚持 WebView getDisplayMedia在手机端几乎必然失败把会议室下沉到 UTS/Kotlin用官方ScreenCaptureParams接 MediaProjection再用mediaProjection前台服务保活才是符合 Android 平台约束、且能和对端 H5/PC 互通的做法。效果
返回列表