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