Shell script as default browser
macos
Solution
I couldn't find any already option (but still, some may exist) so I ended up writing one. Basically what it does is telling the system that the app IS a browser, eventually set itself as default browser (see `#define SET_AS_DEFAULT_BROWSER`) and finally manages the url when it receives the right event by sending the url to a script called `my_link_opener` located in the app's bundle (that is, inside the .app directory). The bash command called is:
`nohup /path/to/my_link_opener "_an_url_" >& /dev/null &`
#import "ZFTAppDelegate.h"
NSString *runCommand(NSString *commandToRun)
{
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: @"/bin/sh"];
NSArray *arguments = @[@"-c" ,[NSString stringWithFormat:@"%@", commandToRun]];
[task setArguments: arguments];
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
NSFileHandle *file;
file = [pipe fileHandleForReading];
[task launch];
NSData *data;
data = [file readDataToEndOfFile];
NSString *output;
output = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
return output;
}
#define SET_AS_DEFAULT_BROWSER
@implementation ZFTAppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSAppleEventManager *em = [NSAppleEventManager sharedAppleEventManager];
[em setEventHandler:self
andSelector:@selector(getUrl:withReplyEvent:)
forEventClass:kInternetEventClass
andEventID:kAEGetURL];
[em setEventHandler:self
andSelector:@selector(getUrl:withReplyEvent:)
forEventClass:'WWW!'
andEventID:'OURL'];
#ifdef SET_AS_DEFAULT_BROWSER
CFStringRef bundleID = (__bridge CFStringRef)[[NSBundle mainBundle] bundleIdentifier];
LSSetDefaultHandlerForURLScheme(CFSTR("http"), bundleID);
LSSetDefaultHandlerForURLScheme(CFSTR("https"), bundleID);
#endif
}
- (void)getUrl:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
{
NSString *url = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
NSString* scriptPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"my_link_opener"];
runCommand([NSString stringWithFormat:@"nohup %@ \"%@\" >& /dev/null &", scriptPath, url]);
}
@end
Remember that in the app's info.plist you should have this (needed to inform the OS about the capability of your app to handle http/s urls):
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>https</string>
</array>
<key>CFBundleURLName</key>
<string>Secure http URL</string>
</dict>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>http</string>
</array>
<key>CFBundleURLName</key>
<string>http URL</string>
</dict>
</array>
Problem
Let's say I have an executable file called `my_link_opener`, how do I set it as the default browser? I have tried the following already, without success: Wrapping it as an .app I tried using Appify and then setting the generated .app as my default browser in Safari. However, because OS X expects programs to only have one "instance" that opens many links in its lifetime, this doesn't work out. Instead of passing the URL on the command-line, it sends a `-psn_xxxxx` argument. Wrapping it with Automator Turns out, if you add it as a workflow in Automator you can make it take opened files as arguments. However, that only works for files and folders. As far I see, there is no way to make URLs valid input for the Automator workflow. So, I'm out of luck. Is there any other kind of wrapping magic I could do?