webview 中文文档 下载 App

WebView 里相机 / 麦克风 / 定位权限的正确处理姿势

权限请求的完整链路

网页 JS 调 getUserMedia() / navigator.geolocation
        ↓
WebView 拦截
        ↓
调用 WebChromeClient.onPermissionRequest()
        ↓
App 自己弹授权框 + 调用 ActivityCompat.requestPermissions()
        ↓
用户确认 → PermissionRequest.grant(permissions)
        ↓
网页 JS 收到成功回调

代码模板

声明 Manifest 权限

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

WebChromeClient 实现

webView.setWebChromeClient(new WebChromeClient() {
    @Override
    public void onPermissionRequest(PermissionRequest request) {
        // 1. 拿到网页请求的权限列表
        String[] resources = request.getResources();

        // 2. 检查 Android 运行时权限(API 23+)
        if (needsRuntimePermission(resources)) {
            // 3. 请求 Android 运行时权限
            ActivityCompat.requestPermissions(
                MainActivity.this,
                toManifestPermissions(resources),
                1001
            );
            // 4. 保存 request,等 onRequestPermissionsResult 里处理
            pendingPermissionRequest = request;
        } else {
            // 5. 直接允许
            request.grant(resources);
        }
    }
});

onRequestPermissionsResult 回调

@Override
public void onRequestPermissionsResult(int rc, String[] perms, int[] results) {
    if (rc == 1001 && pendingPermissionRequest != null) {
        if (allGranted(results)) {
            pendingPermissionRequest.grant(pendingPermissionRequest.getResources());
        } else {
            pendingPermissionRequest.deny();
        }
        pendingPermissionRequest = null;
    }
}

容易踩的坑

漏了 WebChromeClient —— 只实现了 WebViewClient,权限请求会被默认拒绝,网页 JS 拿不到任何反馈。

只做 Android 运行时权限、不处理 PermissionRequest —— Android 弹窗用户点了"允许",但 onPermissionRequest 没调 request.grant(),网页 JS 还是收不到。

永久拒绝 —— 用户选了"以后不再问"后,ActivityCompat.requestPermissions 不再弹窗,必须引导用户去系统设置里手动打开。

其他需要 WebChromeClient 的场景

场景回调方法
相机 / 麦克风 / 定位onPermissionRequest
<input type=file> 文件上传onShowFileChooser
alert() / confirm() JS 对话框onJsAlert / onJsConfirm
视频全屏播放onShowCustomView / onHideCustomView
弹窗打开新窗口onCreateWindow

→ 下一页:常见坑与性能优化