English | 简体中文
Developer guide for building and extending Voyager for Safari.
Tip
Looking to install? You can now download the pre-signed app directly from the latest release. Simply download the .dmg and follow the prompts to install.
# Install dependencies
bun install
# Build for Safari
bun run build:safariThis creates a dist_safari/ folder with the extension files.
# Convert to Safari format
xcrun safari-web-extension-converter dist_safari --macos-only --app-name "Gemini Voyager"
# Open in Xcode
open "Gemini Voyager/Gemini Voyager.xcodeproj"In Xcode:
- Select Signing & Capabilities → Choose your Team
- Set target to My Mac
- Press ⌘R to build and run
bun run dev:safariThis watches for file changes and rebuilds automatically. After each rebuild:
- Press ⌘R in Xcode to reload
- Safari will refresh the extension
# After code changes
bun run build:safari
# Then rebuild in Xcode (⌘R)This project includes Swift code for native macOS features. Adding it is optional but recommended.
safari/
├── App/
│ └── SafariWebExtensionHandler.swift # Native message handler
└── Models/
└── SafariMessage.swift # Message definitions
- Open the Xcode project
- Right-click "Gemini Voyager Extension" target
- Select Add Files to "Gemini Voyager Extension"...
- Navigate to
safari/App/andsafari/Models/ - Check "Copy items if needed"
- Ensure target is "Gemini Voyager Extension"
Once added, you can:
- Access macOS Keychain (future)
- Use native notifications
- Access file system with native pickers
- Sync via iCloud (future)
- Enhanced debugging logs
From JavaScript:
// Health check
browser.runtime.sendNativeMessage({ action: 'ping' }, (response) => {
console.log(response); // { success: true, data: { status: "ok", message: "pong" } }
});
// Get version
browser.runtime.sendNativeMessage({ action: 'getVersion' }, (response) => {
console.log(response.data); // { version: "1.0.0", platform: "macOS" }
});Available Actions:
ping- Health checkgetVersion- Get extension version infosyncStorage- Sync storage (placeholder for future)
Web Console:
- Safari → Develop → Web Extension Background Pages → Gemini Voyager
Native Logs:
log stream --predicate 'subsystem == "com.gemini-voyager.safari"' --level debug"Module 'SafariServices' not found"
- Ensure Swift files are added to "Gemini Voyager Extension" target, not the main app
Native messaging not working
- Check
Info.plisthasSafariWebExtensionHandleras principal class
Swift files not compiling
- Verify Target Membership in Xcode file inspector
- Product → Archive in Xcode
- Window → Organizer
- Select archive → Distribute App
- Follow prompts to export
Requires:
- Apple Developer account ($99/year)
- App Store Connect setup
- App review submission
See Apple's official guide for details.
├── dist_safari/ # Built extension (gitignored)
├── safari/ # Native Swift code
│ ├── App/ # Extension handlers
│ ├── Models/ # Data models
│ └── Resources/ # Example code
├── src/ # Main extension source
└── vite.config.safari.ts # Safari build config
bun run build:safari # Production build
bun run dev:safari # Development with auto-reload
bun run build:all # Build for all browsersBy default, update reminders are disabled for Safari builds to avoid conflicts with App Store auto-updates.
To enable update reminders (for manual distribution):
ENABLE_SAFARI_UPDATE_CHECK=true bun run build:safariNote: Only enable this if you're distributing the extension manually (not via App Store). App Store versions should use the default (disabled) to rely on automatic updates.
Due to Safari's technical architecture and security restrictions, the following features are currently unavailable in the Safari version:
- (a) Nano Banana Watermark Removal: Watermark detection and removal for Gemini™-generated images is not supported.
- (b) Image Export: Direct export to image format is not supported (including in Chat Export). Recommendation: Use PDF Export instead.
See CONTRIBUTING.md for contribution guidelines.
When adding native features:
- Define action in
SafariMessage.swift - Implement handler in
SafariWebExtensionHandler.swift - Add JavaScript API in web extension
- Document in this README