前面 01~07,我们把 ArkWeb 生命周期、JS 通信、静态资源、调试缓存、请求拦截、页面新开窗口、文件上传全部过了一遍。
这一期解决混合项目另一个高频难题:H5 页面请求相机、地理位置权限的时候。
在浏览器打开 H5,会直接弹出浏览器授权窗口;但放到 ArkWeb 里面,默认不会自动弹出权限申请,H5 直接拿不到设备能力,接口返回失败。
核心误区:ArkWeb 不会自动处理 H5 的权限申请。H5 发起权限请求后,会触发onPermissionRequest回调,必须在这里手动判断权限类型,调用鸿蒙原生权限申请,再把结果回传给 ArkWeb。

核心概念一句话讲清
onPermissionRequest 是 H5 申请设备权限的回调。H5 调用 navigator.geolocation、getUserMedia 这些 API 时触发。
我们在回调里拿到请求的权限类型,手动拉起鸿蒙系统权限弹窗;用户同意 / 拒绝后,把结果回传给 ArkWeb,H5 才能继续执行逻辑。
类比:H5 只是提交权限申请单,真正能不能拿到相机、定位,决定权在鸿蒙原生层。
前置条件:HarmonyOS7,DevEco Studio,沿用前面工程,需要在 module.json5 声明对应权限。
第一步:module.json5 权限声明
"requestPermissions": [
{
"name": "ohos.permission.CAMERA",
"reason": "H5网页调用相机",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.LOCATION",
"reason": "H5网页获取地理位置",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
]
第二步:ArkTS 完整实现代码
import { ArkWeb, ArkWebController, WebPermissionRequest, WebPermissionType } from '@kit.ArkWeb';
import { permissionManager } from '@kit.AbilityKit';
@Entry
@Component
struct WebPermissionDemo {
controller: ArkWebController = new ArkWebController();
aboutToAppear() {
this.controller.javascriptEnabled = true;
// 接管H5的权限申请
this.controller.onPermissionRequest = async (req: WebPermissionRequest) => {
// 遍历H5申请的权限类型
for (const permType of req.permissionTypes) {
if (permType === WebPermissionType.CAMERA) {
// 申请相机原生权限
const result = await permissionManager.requestPermissions("EntryAbility", ["ohos.permission.CAMERA"]);
if (result.grantResults[0] === 0) {
// 用户同意,授予权限
req.grant(permType);
} else {
// 用户拒绝,拒绝授权
req.deny(permType);
}
} else if (permType === WebPermissionType.GEOLOCATION) {
// 申请定位原生权限
const result = await permissionManager.requestPermissions("EntryAbility", ["ohos.permission.LOCATION"]);
if (result.grantResults[0] === 0) {
req.grant(permType);
} else {
req.deny(permType);
}
}
}
}
}
build() {
Column() {
ArkWeb({
src: $rawfile("index.html"),
controller: this.controller
})
.width('100%')
.layoutWeight(1)
}
}
}
配套 H5 index.html 测试代码
<button onclick="getLocation()">获取定位</button>
<button onclick="openCamera()">调用相机</button>
<script>
// 获取定位
function getLocation(){
navigator.geolocation.getCurrentPosition((pos)=>{
alert(`经度:${pos.coords.longitude},纬度:${pos.coords.latitude}`)
},err=>{
alert("定位失败:"+err.message)
})
}
// 调用相机
async function openCamera(){
try{
const stream = await navigator.mediaDevices.getUserMedia({video:true})
alert("相机打开成功")
}catch(e){
alert("相机授权失败:"+e.message)
}
}
</script>
关键语句拆解:
onPermissionRequest接收 WebPermissionRequest 对象,用grant()授予权限、deny()拒绝权限。- WebPermissionType 枚举区分权限:CAMERA 相机、GEOLOCATION 定位,还有 MICROPHONE 麦克风。
- 必须先在 module.json5 静态声明权限,否则
requestPermissions直接申请失败。

第三步:权限状态预判断(优化用户体验)
每次 H5 触发申请都弹窗,体验不好。可以先检查是否已经授权,避免重复弹窗:
// 检查权限是否已授权
const status = await permissionManager.checkPermission("ohos.permission.CAMERA");
if(status === permissionManager.GRANTED){
req.grant(WebPermissionType.CAMERA);
}

高频踩坑清单(重点)
- ❌ H5 调用定位 / 相机,没有任何授权弹窗,直接报错
✅ 没有实现onPermissionRequest回调,ArkWeb 不会处理 H5 权限请求。 - ❌ 代码写了 grant (),H5 依旧拿不到权限
✅ module.json5 没有声明对应权限;或者真机没有弹窗手动允许,模拟器部分权限存在限制。 - ❌ 一次性申请多个权限,只处理了其中一个
✅ 权限类型放在 permissionTypes 数组,要用循环逐个判断、逐个 grant/deny,不能只处理第一项。 - ❌ 页面销毁之后,还保留权限回调引用,引发内存泄漏
✅ 页面退出时,不要保留 controller 的 onPermissionRequest 引用,简单置空即可。

小扩展:全局拒绝某些权限(安全管控)
业务需求,直接禁止 H5 使用相机,不需要弹窗,直接 deny
this.controller.onPermissionRequest = async (req: WebPermissionRequest) => {
for (const permType of req.permissionTypes) {
// 直接拒绝相机
if (permType === WebPermissionType.CAMERA) {
req.deny(permType);
}
}
}
