更新记录
1.0(2026-09-20)
处理 Android WebView 的 onPermissionRequest,确保 web-view 内嵌网页(如 RTC 音视频页面)能正常获取摄像头、麦克风权限。
解决的问题
Android 系统 WebView 在网页调用 navigator.mediaDevices.getUserMedia() 时,会直接拒绝
网页的权限请求,表现为:App 级权限已授权,但 H5 页面仍无法打开摄像头/麦克风。
适用环境
| 项目类型 | uni-app x(App-Android) |
|---|---|
| HBuilderX | 4.25+(需 getAndroidView 能力) |
| Vapor 蒸汽模式 | 5.21+(Android(Vapor) UTS 插件支持原生调用) |
| 注意 | Android 蒸汽模式下页面运行在 JS 环境,无法直接获取原生 View,原生调用必须在 UTS 插件内完成 |
平台兼容性
uni-app x(4.26)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| × | × | 5.0 | × | × | × |
outlove-webview
uni-app x 原生 UTS 插件:处理 Android WebView 的 onPermissionRequest,确保 web-view 内嵌网页(如 RTC 音视频页面)能正常获取摄像头、麦克风权限。
解决的问题
Android 系统 WebView 在网页调用 navigator.mediaDevices.getUserMedia() 时,会回调
WebChromeClient.onPermissionRequest。宿主 App 若不覆写该方法,系统会直接拒绝
网页的权限请求,表现为:App 级权限已授权,但 H5 页面仍无法打开摄像头/麦克风。
本插件通过 uni-app x 提供的 UniElement.getAndroidView<WebView>()(HBuilderX 4.25+)拿到
web-view 对应的原生 WebView,注入自定义 WebChromeClient:
适用环境
| 项目类型 | uni-app x(App-Android) |
|---|---|
| HBuilderX | 4.25+(需 getAndroidView 能力) |
| Vapor 蒸汽模式 | 5.21+(Android(Vapor) UTS 插件支持原生调用) |
| 注意 | Android 蒸汽模式下页面运行在 JS 环境,无法直接获取原生 View,原生调用必须在 UTS 插件内完成 |
安装
将 outlove-webview 文件夹放入项目的 uni_modules 目录即可,HBuilderX 会自动识别并参与编译。
使用
建议分两步:
① 申请系统权限(可提前) —— 放在任意页面/组件即可,如登录成功回调、
web-view 所在组件的 onMounted、App.vue 的 onLaunch 等:
权限请求不依赖任何 UI 元素,越早授权,RTC 页面加载时越稳妥。
// #ifdef APP-ANDROID
import {
checkMediaPermission,
requestMediaPermission,
checkLocationPermission,
requestLocationPermission
} from '@/uni_modules/outlove-webview'
// 摄像头/麦克风
if (!checkMediaPermission()) {
requestMediaPermission(
() => console.log('摄像头/麦克风权限已授予'),
(errMsg) => console.warn('权限申请失败:', errMsg)
)
}
// 定位(web-view 内网页地理位置请求需要)
if (!checkLocationPermission()) {
requestLocationPermission(
() => console.log('定位权限已授予'),
(errMsg) => console.warn('定位权限申请失败:', errMsg)
)
}
// #endif
② 注入 WebChromeClient(必须在 web-view 组件内) —— 在承载 <web-view> 的
页面/组件中,拿到 web-view 的 UniElement 后注入:
// #ifdef APP-ANDROID
import { enableWebViewMediaPermission } from '@/uni_modules/outlove-webview'
// 页面 onReady / 组件 onMounted 后调用
onMounted(() => {
const element = uni.getElementById('web-view')
enableWebViewMediaPermission(element)
})
// #endif
模板中给 web-view 添加 id:
<web-view id="web-view" :src="src" />
提示:元素渲染完成前
getAndroidView可能返回 null,建议在onReady/onMounted之后调用;如返回 false,可做有限次延时重试(如每 250ms 一次,最多 20 次)。建议:发起系统授权前先弹业务确认框,说明所需权限,用户确认后再调用
requestMediaPermission/requestLocationPermission;用户取消则调用uni.exit()退出 App(uni-app x 中uni.exit()替代了 plus.runtime.quit,App-Android 支持)。
导出的 API
| 函数 | 说明 |
|---|---|
checkMediaPermission(): boolean |
检查 CAMERA、RECORD_AUDIO 是否均已授权 |
requestMediaPermission(success, fail) |
申请 CAMERA、RECORD_AUDIO 系统权限;fail 的 errMsg 区分“被拒绝”和“被永久拒绝” |
checkLocationPermission(): boolean |
检查 ACCESS_FINE_LOCATION、ACCESS_COARSE_LOCATION 是否均已授权 |
requestLocationPermission(success, fail) |
申请定位权限;fail 的 errMsg 区分“被拒绝”和“被永久拒绝” |
enableWebViewMediaPermission(element: UniElement \| null): boolean |
为指定 web-view 注入 onPermissionRequest 授权处理,返回是否成功 |
enableWebViewRequestInterceptor(element: UniElement \| null, rules: RequestRule[]): boolean |
注入静态资源请求拦截:URL 命中 urlPrefix 的请求改从本地 assets 返回文件,未命中走网络 |
本地静态资源替换(可选)
把网页的部分静态资源(JS/CSS/图片/字体等)替换为随 App 打包的本地文件,
用于加载加速、离线可用。通过 enableWebViewRequestInterceptor 注入:
// #ifdef APP-ANDROID
import { enableWebViewRequestInterceptor } from '@/uni_modules/outlove-webview'
const requestRules = [
// URL 以 urlPrefix 开头时,urlPrefix 之后的路径映射到 assets/localDir 下读取
{ urlPrefix: 'https://www.example.com/rtc/', localDir: 'web/rtc' },
// 首页(主框架文档)也替换成本地 html:加 mainFrame: true
// 包含了一条默认的规则,无需配置即可生效。默认规则是
// { urlPrefix: 'https://app.local/', localDir: 'local', mainFrame: true },
]
onMounted(() => {
const element = uni.getElementById('web-view')
enableWebViewRequestInterceptor(element, requestRules)
})
// #endif
本地文件放置位置(随 App 打包):
项目目录/
└── static/
└── local/ ← localDir 对应目录
└── js/app.js ← 命中 https://app.local/js/app.js
说明:
- 默认主页面导航不拦截,仅拦截子资源请求(JS/CSS/图片/字体/fetch 等);WebSocket 无法拦截
- 规则设置
mainFrame: true后也拦截主框架文档(首页);拦截不改变 WebView 的 URL,查询参数保留 - 目录请求自动补
index.html(如https://app.local/→local/index.html),适配整站离线包入口 - 离线包方案:URL 使用无 DNS 的假域名(如
https://app.local/),规则urlPrefix指向该假域名,localDir指向离线包目录;未命中或本地缺失的请求仍会走网络,假域名会解析失败,因此需保证离线包文件齐全且使用自定义基座/正式包(标准基座不含插件 assets) - 命中规则但本地文件不存在时自动回退到网络加载,不会导致页面资源缺失
- MIME 按扩展名自动识别;无法识别的扩展名不拦截(走网络)
- URL 中的查询参数/锚点映射时自动去除
- 本地文件更新需重新打包安装 App
前置配置## 前置配置
manifest.json 的 app-android.distribute.permissions 需声明(本项目已包含):
"<uses-permission android:name=\"android.permission.CAMERA\"/>",
"<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
"<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>"
"<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
"<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>"
其中 MODIFY_AUDIO_SETTINGS 为普通权限(免运行时弹窗),部分机型上
WebView getUserMedia 录音报 NotReadableError 时补充该权限可解决。
常见问题
- 页面已调用但返回 false:web-view 原生 View 尚未构建,请延后调用或重试;
确认
uni.getElementById传入的 id 与模板中 web-view 的 id 一致。 - 授权弹窗被永久拒绝:
requestMediaPermission的 fail 回调会返回对应提示, 此时需引导用户到系统设置中手动开启摄像头/麦克风权限。 - iOS 端:
onPermissionRequest是 Android 专有机制;iOS WKWebView 使用系统 权限弹窗,需在 manifest 中配置NSCameraUsageDescription、NSMicrophoneUsageDescription隐私描述,本插件不处理 iOS。

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