Reputation: 622
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?
Upvotes: 5
Views: 1085
Reputation: 4391
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>
Upvotes: 3