唯一可靠路径是原生层锁屏+视频组件干预+全屏状态重置:ios需配置info.plist的uisupportedinterfaceorientations,android需在androidmanifest.xml中设置android:screenorientation="landscape",并清空unpackage重新打包。

App 端无法靠 uni.setScreenOrientation 或 CSS 旋转实现真正可用的强制横屏视频播放——它要么静默失败,要么导致触摸错乱、Canvas 尺寸异常、键盘不弹出。唯一可靠路径是:原生层锁屏 + 视频组件轻量干预 + 全屏状态精准重置。
必须改原生配置,否则 JS 层所有调用都白费
iOS 和 Android 都不认 JS 层的横屏指令,uni.setScreenOrientation 在 iOS 真机返回 { result: 'fail', errMsg: 'not supported' };Android 12+(targetSdkVersion ≥ 31)也普遍被系统拦截。生效前提是原生容器从启动就声明横屏:
- iOS:编辑
unpackage/res/ios/Info.plist,确保UISupportedInterfaceOrientations是数组:["UIInterfaceOrientationLandscapeLeft", "UIInterfaceOrientationLandscapeRight"] - Android:编辑
unpackage/res/android/AndroidManifest.xml,在主<activity></activity>标签加属性:android:screenOrientation="landscape" - 改完必须删掉整个
unpackage目录,重新云打包或生成自定义基座——“运行到手机”热重载完全不触发原生配置更新
video 组件要关 controls 和 enable-danmu 才能交出方向控制权
iOS 的原生 video 播放器(WKWebView 内部实现)默认锁定竖屏,即使你调了 uni.setScreenOrientation,它也大概率无视。根本解法是削弱它的控制权:
-
controls设为false:关闭系统控件,避免原生全屏按钮接管方向 -
enable-danmu设为false:iOS 下弹幕会触发专用渲染路径,绕过 JS 层 orientation 设置 - 自行实现播放/暂停按钮,用
videoContext.play()/.pause()控制 - 在页面
onReady中调用uni.setScreenOrientation({orientation: 'landscape'}),不要放onLoad—— 此时 native view 还没创建,必 fail
全屏退出后方向卡住?得手动重置,不能等自动恢复
plus.video 或原生 video 全屏退出后,App 容器仍保持横屏状态,返回上一页会发现整个 UI 被拉伸或错位。这不是 bug,是系统行为:
- 监听
@fullscreen-change事件,当detail.fullscreen === false时,立即调用uni.setScreenOrientation({orientation: 'portrait'}) - 若用
videoContext.requestFullScreen(),则在其 Promise resolve 后立刻重置方向,比事件更可靠 - Android 部分机型还需额外调
plus.navigator.setFullscreen(false)配合 - 别依赖
onUnload:全屏播放器生命周期独立于 Vue 页面,onUnload可能根本没触发
横屏后 UI 尺寸和触摸坐标全乱了?别信 uni.getSystemInfo 的返回值
uni.getSystemInfoSync() 返回的 screenWidth/screenHeight 是设备物理方向下的尺寸,不是横屏后的视口尺寸。比如 iPhone 14 Pro 物理分辨率是 1179×2556,横屏后可用宽度其实是 2556px,但该 API 仍返回 1179。
- 布局适配优先用 CSS 媒体查询:
@media (orientation: landscape)或@media (min-width: 1024px) - Canvas、Camera 等原生渲染组件,必须用
plus.screen.getScreenSize()获取当前屏幕实际宽高 - 触摸坐标计算要以
event.touches[0].clientX/clientY为准,别用screenWidth做归一化
真正麻烦的从来不是“怎么写代码”,而是 iOS Info.plist 字符串大小写是否严格匹配、AndroidManifest.xml 里有没有漏掉 subNVue 页面的 activity、云打包前有没有清空 unpackage——这些细节一错,前面所有 JS 都在演独角戏。











