在使用 Electron 开发桌面应用时,有音视频聊天相关的业务,在 Mac 中,应用默认是没有摄像头和麦克风的权限的,我们在需要获取摄像头和麦克风权限时,需要判断是否已经获取了权限,如果没有,则需要引导用户去系统设置中打开权限。
1. 配置要获取的权限 #
首先是在对应用打包时,要先声明可能要使用的权限。先创建一个 entitlements.mac.plist
文件,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
<key>com.apple.security.device.audio-input</key>
<true/>
<key>com.apple.security.device.camera</key>
<true/>
</dict>
</plist>
我的 Electron 应用是使用的 electron-builder 构建的,我在 electron-builder.json 中添加了如下配置:
{
"mac": {
"hardenedRuntime": true,
"gatekeeperAssess": false,
"entitlementsInherit": "build/entitlements.mac.plist",
"extendInfo": {
"NSDocumentsFolderUsageDescription": "需要访问您的文档目录以展示相关文件",
"NSDownloadsFolderUsageDescription": "需要访问您的下载目录以展示相关文件",
"NSMicrophoneUsageDescription": "请允许访问您的麦克风",
"NSCameraUsageDescription": "请允许访问您的摄像头"
}
}
}
配置完成后,就可以在程序中索取需要的权限了。
注意:若我们在 VSCode 中开发正常,只是因为我们使用的是操作系统赋予的
VSCode
的媒体权限,而不是我们应用本身获取到的权限。
2. 获取权限 #
进行音视频通话前,需要先判断下是否已经获取了权限。若没有获取权限,则需要索取权限,并最好跳转到设置页面,让用户去手动打开权限。
在 electron 中,获取权限的代码如下:
import { ipcMain, systemPreferences } from "electron";
// 判断是否有相关的权限
ipcMain.handle("getMediaAccess", (_, mediaType: "microphone" | "camera" | "screen") => {
const access = systemPreferences.getMediaAccessStatus(mediaType) === "granted";
logger.info(`get ${mediaType} access: ${access}`);
return access;
});
// 索取权限
ipcMain.handle("askForMediaAccess", (_, mediaType: "microphone" | "camera") => {
return systemPreferences.askForMediaAccess(mediaType);
});
// 打开设置页
ipcMain.handle(
"openSystemPreferences",
(_, security: "Privacy_ScreenCapture" | "Privacy_Camera" | "Privacy_Microphone") => {
if (os.platform() === "darwin") {
const pane = "security";
exec(`open "x-apple.systempreferences:com.apple.preference.${pane}?${security}"`);
}
}
);
在前端页面中:
const handleClick = async (mediaType: "screen" | "camera" | "microphone") => {
const access = await window.electronAPI?.ipcInvoke("getMediaAccess", mediaType);
if (!access) {
message.warning("暂无权限");
const result = await window.electronAPI?.ipcInvoke("askForMediaAccess", mediaType);
if (result) {
return;
}
window.electronAPI?.ipcInvoke("openSystemPreferences", mapping[mediaType].system);
}
};
3. 总结 #
Mac 的操作系统通常对权限的管理比较严格,比如访问摄像头、麦克风、定位权限等等。因此我们在使用时,要考虑到授权的问题。