#!/bin/bash # ============================================================ # macOS 开发环境权限设置脚本 # 用途:为 Electron 开发模式配置摄像头/麦克风权限 # 使用:npm run setup:macos # ============================================================ set -e E="node_modules/electron/dist/Electron.app" FW="$E/Contents/Frameworks" ELECTRON_PLIST="$E/Contents/Info.plist" ENTITLEMENTS_FILE="assets/entitlements.plist" BUNDLE_ID="com.github.Electron" HELPER_BUNDLE_ID="com.github.Electron.helper" echo "==========================================" echo " CamTalk macOS 开发权限配置" echo "==========================================" # 检查是否在正确的目录 if [ ! -f "$ELECTRON_PLIST" ]; then echo "[ERROR] 未找到 Electron: $ELECTRON_PLIST" echo " 请在 desktop/ 目录下运行此脚本" exit 1 fi echo "" echo "[1/4] 检查 Info.plist 中的权限描述..." if /usr/libexec/PlistBuddy -c "Print :NSCameraUsageDescription" "$ELECTRON_PLIST" >/dev/null 2>&1; then echo " NSCameraUsageDescription 已存在" else echo " 添加 NSCameraUsageDescription..." /usr/libexec/PlistBuddy -c "Add :NSCameraUsageDescription string 'CamTalk 需要使用摄像头进行实时 AI 视觉对话'" "$ELECTRON_PLIST" fi if /usr/libexec/PlistBuddy -c "Print :NSMicrophoneUsageDescription" "$ELECTRON_PLIST" >/dev/null 2>&1; then echo " NSMicrophoneUsageDescription 已存在" else echo " 添加 NSMicrophoneUsageDescription..." /usr/libexec/PlistBuddy -c "Add :NSMicrophoneUsageDescription string 'CamTalk 需要使用麦克风进行语音对话'" "$ELECTRON_PLIST" fi echo "" echo "[2/4] 对 Electron 所有组件进行签名(含 entitlements + hardened runtime)..." if [ -f "$ENTITLEMENTS_FILE" ] && [ -d "$E" ]; then # 先移除所有签名 echo " 移除旧签名..." codesign --remove-signature "$E" 2>/dev/null || true for fw in "$FW"/*.framework; do codesign --remove-signature "$fw" 2>/dev/null || true done for h in "$FW"/*.app; do codesign --remove-signature "$h" 2>/dev/null || true done # 签名所有 Framework echo " 签名 Frameworks..." for fw in "$FW"/*.framework; do codesign --force --sign - --entitlements "$ENTITLEMENTS_FILE" --options runtime "$fw" 2>/dev/null done # 签名所有 Helper Apps(关键:renderer helper 需要 camera entitlement) echo " 签名 Helper Apps..." for h in "$FW"/*.app; do codesign --force --sign - --entitlements "$ENTITLEMENTS_FILE" --options runtime "$h" 2>/dev/null done # 签名主 App echo " 签名主 App..." codesign --force --sign - --entitlements "$ENTITLEMENTS_FILE" --options runtime "$E" 2>/dev/null # 验证 if codesign --verify --deep --strict "$E" 2>/dev/null; then echo " ✅ 签名验证通过" else echo " ⚠️ 签名验证有警告(通常不影响运行)" fi else echo " 跳过签名(文件不存在)" fi echo "" echo "[3/4] 重置 TCC 权限..." echo " 清除旧的摄像头/麦克风权限记录,使下次启动时重新请求。" tccutil reset Camera "$BUNDLE_ID" 2>/dev/null && echo " Camera ($BUNDLE_ID) 已重置" || true tccutil reset Microphone "$BUNDLE_ID" 2>/dev/null && echo " Microphone ($BUNDLE_ID) 已重置" || true tccutil reset Camera "$HELPER_BUNDLE_ID" 2>/dev/null && echo " Camera ($HELPER_BUNDLE_ID) 已重置" || true tccutil reset Microphone "$HELPER_BUNDLE_ID" 2>/dev/null && echo " Microphone ($HELPER_BUNDLE_ID) 已重置" || true echo "" echo "[4/4] 验证签名状态..." echo " Main App: $(codesign -dvvv "$E" 2>&1 | grep '^flags=' | head -1)" RENDERER_HELPER="$FW/Electron Helper (Renderer).app" if [ -d "$RENDERER_HELPER" ]; then echo " Renderer Helper: $(codesign -dvvv "$RENDERER_HELPER" 2>&1 | grep '^flags=' | head -1)" fi echo "" echo "==========================================" echo " 配置完成!" echo "==========================================" echo "" echo "下一步:" echo " npm run dev" echo "" echo "启动后应用会自动请求摄像头/麦克风权限。" echo "如果 macOS 系统弹窗未出现,应用会弹出引导对话框," echo "点击按钮一键打开系统设置,授权后应用会自动检测并启用摄像头。" echo ""