# Phase V2-5: macOS 빌드 / 실행 / 배포 가이드 > 본인 Mac에서 D3RO Voice를 dev 실행하거나 dist(.dmg/.zip) 빌드하기 위한 단계별 가이드. > Windows에서 작성된 코드는 V2-5에서 모든 플랫폼 분기를 추가했습니다 — Mac에서는 별도 코드 수정 없이 아래 단계만 따르면 됩니다. --- ## 0. 사전 조건 - **macOS 12 (Monterey) 이상** 권장 - **Apple Silicon(M1/M2/M3) 또는 Intel** 둘 다 지원 - Xcode Command Line Tools (`xcode-select --install`) - Homebrew 설치 (`brew --version`으로 확인) ## 1. 시스템 의존성 설치 ```bash # 기본 도구 brew install node@22 python@3.11 git # 오디오 캡처 (필수) brew install sox # Ollama (로컬 LLM, 선택) brew install ollama ollama serve & # 백그라운드 실행 ollama pull gemma4:e4b ``` ## 2. 프로젝트 클론 + 설치 ```bash git clone https://github.com/yunchan8804/d3ro-voice.git cd d3ro-voice # npm workspace 설치 (모든 패키지 한 번에) npm install # native 모듈 재빌드 (electron 33 ABI에 맞게) npx @electron/rebuild@3 --version=33.4.11 ``` ## 3. SoX 바이너리 번들 (선택, dev에서는 PATH로 충분) dev 실행만 할 거라면 `brew install sox`만으로 충분합니다. `paths.ts`가 `sox` 시스템 명령을 자동 fallback으로 사용합니다. dist 빌드를 할 거라면 `resources/sox/`에 바이너리를 미리 복사: ```bash cd apps/desktop bash scripts/install-sox.sh ``` 이 스크립트는: 1. `command -v sox`로 시스템 sox 위치 찾기 2. `apps/desktop/resources/sox/`에 복사 3. `otool -L`로 dylib 의존성 확인 후 함께 복사 4. `install_name_tool`로 rpath를 `@loader_path`로 변경 (앱 번들 내부에서도 동작) ## 4. Python sidecar 빌드 (faster-whisper) dev에서도 sidecar는 Python 직접 실행. dist에서는 PyInstaller로 묶어야 함. ```bash cd apps/desktop # 가상 환경 (선택, 권장) python3.11 -m venv .venv-sidecar source .venv-sidecar/bin/activate pip install pyinstaller pip install -r sidecar/requirements.txt # 빌드 (sidecar-dist/sidecar/sidecar 생성) python scripts/build-sidecar.py ``` 빌드 결과: `apps/desktop/sidecar-dist/sidecar/sidecar` (실행 파일) `electron-builder.yml`이 이 경로를 `extraResources`로 번들합니다. ## 5. 아이콘 준비 (dist 빌드 전) `apps/desktop/resources/icons/`는 placeholder 디렉토리입니다. ```bash cd apps/desktop/resources/icons # 1024x1024 PNG 원본을 icon.png로 저장한 뒤: mkdir -p icon.iconset sips -z 16 16 icon.png --out icon.iconset/icon_16x16.png sips -z 32 32 icon.png --out icon.iconset/icon_16x16@2x.png sips -z 32 32 icon.png --out icon.iconset/icon_32x32.png sips -z 64 64 icon.png --out icon.iconset/icon_32x32@2x.png sips -z 128 128 icon.png --out icon.iconset/icon_128x128.png sips -z 256 256 icon.png --out icon.iconset/icon_128x128@2x.png sips -z 256 256 icon.png --out icon.iconset/icon_256x256.png sips -z 512 512 icon.png --out icon.iconset/icon_256x256@2x.png sips -z 512 512 icon.png --out icon.iconset/icon_512x512.png sips -z 1024 1024 icon.png --out icon.iconset/icon_512x512@2x.png iconutil -c icns icon.iconset rm -r icon.iconset ``` 자세한 내용: `apps/desktop/resources/icons/README.md` ## 6. dev 실행 ```bash # 루트에서 (npm workspace가 자동으로 apps/desktop 호출) npm run dev ``` 처음 실행 시 macOS가 다음 권한을 요구합니다: | 권한 | 사용처 | 거부 시 영향 | |---|---|---| | 마이크 | 음성 인식 (필수) | 녹음 불가 | | Accessibility | 전역 핫키 (uiohook-napi), 활성 윈도우 조회 (AppleScript) | 핫키/스크린 컨텍스트 동작 안 함 | | 화면 녹화 | 스크린 컨텍스트 캡처 (선택) | OCR/LLM 컨텍스트 비어있음 | | Apple Events | 활성 앱 이름 조회 (osascript) | appName이 null | 권한은 **시스템 설정 → 개인 정보 보호 및 보안**에서 수동으로도 조정 가능합니다. ## 7. dist 빌드 (DMG/ZIP) ```bash cd apps/desktop # Apple Silicon만 npx electron-builder --mac --arm64 # Intel만 npx electron-builder --mac --x64 # 둘 다 npx electron-builder --mac ``` 결과: `apps/desktop/release//` - `D3RO Voice-1.0.0-arm64.dmg` - `D3RO Voice-1.0.0-arm64.zip` - `D3RO Voice-1.0.0.dmg` (intel) - `D3RO Voice-1.0.0.zip` (intel) ## 8. Code Signing + Notarization (배포용) ### 8.1 Apple Developer 인증서 준비 1. https://developer.apple.com → Account → Certificates 2. `+` → `Developer ID Application` (배포용) 생성 3. 다운로드한 `.cer`을 키체인에 추가 4. 키체인에서 **인증서 + 개인 키**를 함께 export → `.p12` 파일 (암호 설정) ### 8.2 환경 변수 ```bash # Code signing export CSC_LINK="$(base64 -i path/to/cert.p12)" export CSC_KEY_PASSWORD="" # Notarization (App-specific password 필요) export APPLE_ID="your-apple-id@example.com" export APPLE_APP_SPECIFIC_PASSWORD="abcd-efgh-ijkl-mnop" # appleid.apple.com에서 생성 export APPLE_TEAM_ID="ABCDE12345" ``` App-specific password 생성: https://appleid.apple.com → Sign-In and Security → App-Specific Passwords ### 8.3 서명+공증 빌드 ```bash cd apps/desktop npx electron-builder --mac -c.mac.notarize=true ``` 공증은 보통 5~30분 걸립니다. 완료되면 자동으로 staple됩니다. 검증: ```bash spctl --assess --verbose=4 release//D3RO\ Voice.app # accepted source=Notarized Developer ID ``` ## 9. CI 빌드 (GitHub Actions) `.github/workflows/build-mac.yml` 워크플로우를 사용하여 자동 빌드: ```bash # 태그 푸시 시 자동 트리거 git tag v1.0.0 git push origin v1.0.0 ``` 또는 GitHub UI에서 `Actions → Build macOS → Run workflow`. ### 필요한 GitHub Secrets | Secret | 설명 | |---|---| | `APPLE_ID` | Apple 계정 이메일 | | `APPLE_APP_SPECIFIC_PASSWORD` | App-specific password | | `APPLE_TEAM_ID` | 10자리 팀 ID | | `MAC_CERT_P12_BASE64` | `.p12` 인증서를 base64 인코딩한 문자열 | | `MAC_CERT_P12_PASSWORD` | `.p12` 암호 | `workflow_dispatch`로 수동 실행 시 `notarize=true`를 선택하면 공증까지 진행. ## 10. 트러블슈팅 ### "App is damaged and can't be opened" (서명 없는 dmg) ```bash xattr -cr /Applications/D3RO\ Voice.app ``` 또는 시스템 설정 → 보안 → "확인 없이 열기" ### `sox: command not found` (dev 모드) ```bash brew install sox ``` ### `ImportError: dlopen failed` (sidecar 실행 시) PyInstaller 빌드가 현재 Mac 아키텍처와 다를 가능성. arm64 Mac에서 `arch -x86_64 python` 같은 cross 빌드는 권장하지 않음. ### Electron 앱이 즉시 종료 ```bash # 콘솔 로그 확인 ~/Library/Logs/d3ro-voice/main.log # 또는 dev 모드로 직접 실행 npm run dev ``` ### Accessibility 권한 거부 후 재요청 시스템 설정 → 개인정보보호 → 손쉬운 사용 → 좌하단 자물쇠 해제 → D3RO Voice 체크 권한 변경 후 앱 재시작.