Skip to content

Commit f1d6a88

Browse files
authored
Add compile script and .gitignore; remove legacy Swift scripts
1 parent 4481114 commit f1d6a88

6 files changed

Lines changed: 339 additions & 250 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
bin/

README.md

Lines changed: 75 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,110 @@
11
# macOS Default App Setter Scripts
22

3-
Simple Swift scripts to set default mail and browser applications on macOS.
3+
Simple scripts to set default mail and browser applications on macOS.
44

5-
## Prerequisites
5+
## Option 1: Pre-compiled Executables (Recommended)
66

7-
### Terminal Accessibility Permissions
8-
The scripts use AppleScript automation to handle system prompts. Terminal.app needs accessibility permissions:
7+
Pre-compiled executables work on any macOS device without requiring developer tools.
98

10-
1. Go to System Settings > Privacy & Security > Accessibility
11-
2. Click the '+' button
12-
3. Navigate to and select Terminal.app
13-
4. Enable the permission
9+
### Installation
1410

15-
## Installation
11+
1. Download the pre-compiled binaries from the releases section
12+
2. Make them executable if needed:
13+
```bash
14+
chmod +x bin/SetDefaultApp
15+
```
1616

17-
1. Clone or download the scripts
18-
2. Make them executable:
17+
### Usage
18+
19+
#### Combined App (Recommended)
1920
```bash
20-
chmod +x SetDefaultMailApp.swift
21-
chmod +x SetDefaultBrowser.swift
21+
./bin/SetDefaultApp [option] [app]
2222
```
2323

24-
## Usage
24+
Options:
25+
- `browser` - Set default web browser
26+
- `mail` - Set default mail application
2527

26-
### Setting Default Mail App
28+
Examples:
2729
```bash
28-
./SetDefaultMailApp.swift [mail-app]
30+
./bin/SetDefaultApp browser chrome
31+
./bin/SetDefaultApp mail outlook
2932
```
3033

31-
Supported mail apps:
32-
- `mail` - Apple Mail
33-
- `outlook` - Microsoft Outlook
34+
#### Individual Executables (Legacy)
35+
If you prefer the separate executables, they are still available:
3436

35-
Example:
37+
Setting Default Mail App:
3638
```bash
37-
./SetDefaultMailApp.swift mail
39+
./bin/SetDefaultMailApp [mail-app]
3840
```
3941

40-
### Setting Default Browser
42+
Setting Default Browser:
4143
```bash
42-
./SetDefaultBrowser.swift [browser]
44+
./bin/SetDefaultBrowser [browser]
4345
```
4446

47+
### Supported Applications
48+
4549
Supported browsers:
4650
- `safari` - Safari
4751
- `chrome` - Google Chrome
4852
- `firefox` - Firefox
4953
- `edge` - Microsoft Edge
5054

51-
Example:
55+
Supported mail apps:
56+
- `mail` - Apple Mail
57+
- `outlook` - Microsoft Outlook
58+
59+
## Option 2: Swift Source Files (For Developers)
60+
61+
### Prerequisites
62+
63+
- Xcode Command Line Tools installed
64+
65+
### Installation
66+
67+
1. Clone or download the Swift scripts
68+
2. Make them executable:
5269
```bash
53-
./SetDefaultBrowser.swift chrome
70+
chmod +x SetDefaultApp.swift
5471
```
5572

73+
### Usage
74+
75+
```bash
76+
./SetDefaultApp.swift browser chrome
77+
./SetDefaultApp.swift mail outlook
78+
```
79+
80+
### Compiling to Standalone Executables
81+
82+
If you have the developer tools and want to distribute binaries to users without them:
83+
84+
1. Make the compile script executable:
85+
```bash
86+
chmod +x compile.sh
87+
```
88+
89+
2. Run the compile script:
90+
```bash
91+
./compile.sh
92+
```
93+
94+
3. Distribute the executables from the `bin` directory
95+
96+
## Terminal Accessibility Permissions
97+
98+
These scripts use system automation to handle prompts. Terminal.app needs accessibility permissions:
99+
100+
1. Go to System Settings > Privacy & Security > Accessibility
101+
2. Click the '+' button
102+
3. Navigate to and select Terminal.app
103+
4. Enable the permission
104+
56105
## Notes
57106

58-
- Scripts require macOS and Swift runtime (pre-installed on macOS)
107+
- Pre-compiled executables work without developer tools
59108
- The scripts will automatically handle system prompts if Terminal has proper permissions
60109
- Mail.app is searched for in `/System/Applications`
61110
- Third-party apps are searched in `/Applications` and `~/Applications`

SetDefaultApp.swift

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
#!/usr/bin/swift
2+
import Foundation
3+
import CoreServices
4+
5+
// Function to print usage
6+
func printUsage() {
7+
print("""
8+
Usage: ./SetDefaultApp.swift [option] [app]
9+
10+
Options:
11+
browser - Set default web browser
12+
mail - Set default mail application
13+
14+
Supported browsers:
15+
safari - Set Safari as default browser
16+
chrome - Set Google Chrome as default browser
17+
firefox - Set Firefox as default browser
18+
edge - Set Microsoft Edge as default browser
19+
20+
Supported mail applications:
21+
mail - Set Apple Mail as default mail application
22+
outlook - Set Microsoft Outlook as default mail application
23+
24+
Examples:
25+
./SetDefaultApp.swift browser chrome
26+
./SetDefaultApp.swift mail outlook
27+
""")
28+
exit(1)
29+
}
30+
31+
// Check if arguments were provided
32+
guard CommandLine.arguments.count > 2 else {
33+
printUsage()
34+
exit(1)
35+
}
36+
37+
// Get and normalize the option argument
38+
let option = CommandLine.arguments[1].lowercased()
39+
let app = CommandLine.arguments[2].lowercased()
40+
41+
// Validate the option
42+
guard option == "browser" || option == "mail" else {
43+
print("Error: Invalid option '\(option)'")
44+
printUsage()
45+
exit(1)
46+
}
47+
48+
// Set browser as default
49+
func setBrowserAsDefault(browser: String) {
50+
// Define browser bundle IDs
51+
let bundleID: String
52+
let appName: String
53+
54+
switch browser {
55+
case "safari":
56+
bundleID = "com.apple.Safari"
57+
appName = "Safari"
58+
case "chrome":
59+
bundleID = "com.google.Chrome"
60+
appName = "Google Chrome"
61+
case "firefox":
62+
bundleID = "org.mozilla.firefox"
63+
appName = "Firefox"
64+
case "edge":
65+
bundleID = "com.microsoft.edgemac"
66+
appName = "Microsoft Edge"
67+
default:
68+
print("Error: Unsupported browser '\(browser)'")
69+
printUsage()
70+
exit(1)
71+
}
72+
73+
// Check if the browser is installed
74+
let fileManager = FileManager.default
75+
let appPath = "/Applications/\(appName).app"
76+
let userAppPath = NSHomeDirectory() + "/Applications/\(appName).app"
77+
78+
guard fileManager.fileExists(atPath: appPath) || fileManager.fileExists(atPath: userAppPath) else {
79+
print("Error: \(appName) does not appear to be installed on this system.")
80+
exit(1)
81+
}
82+
83+
print("Setting \(appName) as the default web browser...")
84+
85+
// Set the default handler for HTTP and HTTPS URL schemes
86+
func setDefaultHandler(forURLScheme scheme: String, toBundleID bundleID: String) -> OSStatus {
87+
return LSSetDefaultHandlerForURLScheme(scheme as CFString, bundleID as CFString)
88+
}
89+
90+
// Set for HTTP and HTTPS
91+
let httpStatus = setDefaultHandler(forURLScheme: "http", toBundleID: bundleID)
92+
let httpsStatus = setDefaultHandler(forURLScheme: "https", toBundleID: bundleID)
93+
94+
// A function to run AppleScript to handle the prompt
95+
func runAppleScriptToHandlePrompt(forApp appName: String) -> Bool {
96+
let script = """
97+
try
98+
tell application "\(appName)"
99+
-- Just start the launch process
100+
launch
101+
end tell
102+
103+
tell application "System Events"
104+
if UI elements enabled then
105+
-- Immediately start checking for the prompt
106+
repeat 40 times
107+
if (exists process "CoreServicesUIAgent") then
108+
tell process "CoreServicesUIAgent"
109+
try
110+
if (exists window 1) then
111+
set promptWindow to window 1
112+
set frontmost to true
113+
perform action "AXRaise" of promptWindow
114+
115+
-- Find and click the "Use" button
116+
repeat with btn in (buttons of promptWindow)
117+
if name of btn contains "Use" then
118+
click btn
119+
return true
120+
end if
121+
end repeat
122+
end if
123+
end try
124+
end tell
125+
end if
126+
delay 0.1
127+
end repeat
128+
else
129+
return false
130+
end if
131+
end tell
132+
on error errMsg
133+
return false
134+
end try
135+
return false
136+
"""
137+
138+
let scriptObject = NSAppleScript(source: script)
139+
var errorDict: NSDictionary?
140+
let output = scriptObject?.executeAndReturnError(&errorDict)
141+
142+
if let error = errorDict {
143+
print("AppleScript error occurred. This likely means the script needs accessibility permissions.")
144+
print("Please ensure Terminal (or your current app) has accessibility permissions in:")
145+
print("System Settings → Privacy & Security → Accessibility")
146+
print("Technical error details: \(error)")
147+
return false
148+
}
149+
150+
return output?.booleanValue ?? false
151+
}
152+
153+
// Try to automatically handle the prompt
154+
if httpStatus == noErr && httpsStatus == noErr {
155+
print("Successfully set \(appName) as the default browser.")
156+
} else {
157+
print("Attempting to handle prompt automatically...")
158+
159+
// First, open the browser to trigger the prompt
160+
let process = Process()
161+
process.launchPath = "/usr/bin/open"
162+
process.arguments = ["-a", appName]
163+
process.launch()
164+
165+
// Try to handle the prompt with AppleScript
166+
if runAppleScriptToHandlePrompt(forApp: appName) {
167+
print("Successfully handled prompt and set \(appName) as default browser.")
168+
} else {
169+
print("Could not automatically handle the prompt.")
170+
print("You may need to manually confirm setting \(appName) as the default browser.")
171+
}
172+
}
173+
}
174+
175+
// Set mail app as default
176+
func setMailAppAsDefault(mailApp: String) {
177+
// Define mail app bundle IDs
178+
let bundleID: String
179+
let appName: String
180+
181+
switch mailApp {
182+
case "mail":
183+
bundleID = "com.apple.mail"
184+
appName = "Mail"
185+
case "outlook":
186+
bundleID = "com.microsoft.Outlook"
187+
appName = "Microsoft Outlook"
188+
default:
189+
print("Error: Unsupported mail application '\(mailApp)'")
190+
printUsage()
191+
exit(1)
192+
}
193+
194+
// Check if the mail app is installed
195+
let fileManager = FileManager.default
196+
let systemAppPath = "/System/Applications/\(appName).app" // Add system applications path
197+
let appPath = "/Applications/\(appName).app"
198+
let userAppPath = NSHomeDirectory() + "/Applications/\(appName).app"
199+
200+
// Check all possible locations for the app
201+
guard fileManager.fileExists(atPath: systemAppPath) ||
202+
fileManager.fileExists(atPath: appPath) ||
203+
fileManager.fileExists(atPath: userAppPath) else {
204+
print("Error: \(appName) does not appear to be installed on this system.")
205+
exit(1)
206+
}
207+
208+
print("Setting \(appName) as the default mail application...")
209+
210+
// Set the default handler for mail URL schemes and actions
211+
func setDefaultHandler(forURLScheme scheme: String, toBundleID bundleID: String) -> OSStatus {
212+
return LSSetDefaultHandlerForURLScheme(scheme as CFString, bundleID as CFString)
213+
}
214+
215+
// Set for mailto scheme
216+
let mailtoStatus = setDefaultHandler(forURLScheme: "mailto", toBundleID: bundleID)
217+
218+
// Try to automatically handle the prompt
219+
if mailtoStatus == noErr {
220+
print("Successfully set \(appName) as the default mail application.")
221+
} else {
222+
print("Failed to set \(appName) as the default mail application.")
223+
}
224+
}
225+
226+
// Main execution based on the option
227+
if option == "browser" {
228+
setBrowserAsDefault(browser: app)
229+
} else if option == "mail" {
230+
setMailAppAsDefault(mailApp: app)
231+
}

0 commit comments

Comments
 (0)