6

I'm implementing a custom URL scheme for one of my apps and can't get it to work.

I added these lines to my Info.plist:

<key>CFBundleURLTypes</key>
<array>
    <dict>
        <key>CFBundleURLName</key>
        <string>MyApp URL</string>
        <key>CFBundleURLSchemes</key>
        <array>
            <string>myscheme</string>
        </array>
    </dict>
</array>

In my application delegate I install the event handler in ApplicationDidFinishedLaunching:

NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager];
[appleEventManager setEventHandler:self andSelector:@selector(handleGetURLEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];

but the method isn't called when I click on a link with the URL eg. "myscheme://test"

- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event
           withReplyEvent:(NSAppleEventDescriptor *)replyEvent {

    // Extract the URL from the Apple event and handle it here.
    NSString* url = [[event paramDescriptorForKeyword:keyDirectObject] stringValue];
    NSLog(@"%@", url);
}

What did I miss?

tamasgal
  • 24,826
  • 18
  • 96
  • 135
  • Does the `Info.plist` in your actual app bundle (not in Xcode) contain the `CFBundleURLSchemes` key? – Rob Keniger Apr 17 '12 at 10:56
  • I added to the original posting the App-Info.plist source of CFBundleURLTypes. What do you mean with "not in Xcode"? – tamasgal Apr 18 '12 at 06:12
  • I mean in the built product, the actual `Productname.app` bundle that you double-click in the Finder to launch your app. Does the `Info.plist` file inside the .app bundle contain your changes? – Rob Keniger Apr 18 '12 at 06:39
  • Ah OK, got it. I checked it, it's exactly the same as in the Xcode project. – tamasgal Apr 18 '12 at 07:03
  • Well now it works, maybe that was the solution (I cleared the project several times and deleted the whole product also manually). Thanks ;-) Could you write an answer, so I can give you the bounty? – tamasgal Apr 18 '12 at 07:06
  • Done. I'm glad you got it working. – Rob Keniger Apr 18 '12 at 12:32

4 Answers4

9

It sounds like you may need to clean your project. Sometimes the Launch Services database (which handles URL associations) is not updated correctly when Xcode builds an app. Cleaning the project should delete the built app entirely, so the next time you build the project it is created from scratch, in the process updating the Launch Services database.

You might also want to try copying the app into the /Applications folder, which should make Launch Services re-parse the app's Info.plist file.

You can force Launch Services to rebuild its database by running the following command in Terminal:

/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -kill -r -domain local -domain system -domain user
Rob Keniger
  • 45,830
  • 6
  • 101
  • 134
  • 1
    Note that for me the `lsregister` binary could be found at `/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister` instead. – Douwe Maan Jul 14 '12 at 20:11
  • Thanks for saving me another hour of frustration – OthmanT Apr 13 '20 at 19:09
4

Move the event handler code to the init method:

- (id) init
{   
    if ((self = [super init]))
    {
        NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager];
        [appleEventManager setEventHandler:self andSelector:@selector(handleGetURLEvent:withReplyEvent:) forEventClass:kInternetEventClass andEventID:kAEGetURL];

        // Add the following to set your app as the default for this scheme
        NSString * bundleID = [[NSBundle mainBundle] bundleIdentifier];
        LSSetDefaultHandlerForURLScheme((CFStringRef)@"myscheme", (CFStringRef)bundleID 
    }
return self;
}

Note: myscheme should take the form x-com-companyname-appname so that it never clashes with any other scheme out there.

See Also: For more information on this topic see How do you set your Cocoa application as the default web browser?

Community
  • 1
  • 1
  • It doesn't work either… I did it exactly the same way as described in you "How do you set your Cocoa…" – tamasgal Feb 16 '12 at 08:45
  • You could try placing an NSLog statement in your init method to check that it is being called... – David Kennedy of Zenopolis Feb 16 '12 at 09:02
  • I just tried creating a new project with the above code and it works as expected. After running the test app at least once, I tested it with the AppleScript code: `open location "myscheme://test"`. The following text appeared in Xcode's output window: `2012-02-16 14:45:52.945 SchemeTest[3820:707] myscheme://test`. Try to do the same - create a new test project and see if you can get it working. If you can, compare project settings and connections to see if you can find where the problem is. P.S. I've updated the code, there was some characters missing at the end of one of the lines. – David Kennedy of Zenopolis Feb 16 '12 at 14:56
  • Just to clarify - I copied and pasted your info.plist code, my init code and your event handler into the new project to get everything working. – David Kennedy of Zenopolis Feb 16 '12 at 14:59
  • OK I'll try it. However, this should also work with a link on a webpage, shouldn't it? Because I didn't tested it with Apple Script, but with a .html-file containing a link with bar. – tamasgal Feb 17 '12 at 12:52
  • You have an extra space in there - it works for me with `bar` in a HTML file. – David Kennedy of Zenopolis Feb 17 '12 at 16:04
  • The extra space came from lions autocorrection, when I typed the comment ;) – tamasgal Feb 17 '12 at 16:25
2

Update database OS10.8 Mountain Lion

/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -f

-kill Reset the Launch Services database before doing anything else -seed If database isn't seeded, scan default locations for applications and libraries to register -lint Print information about plist errors while registering bundles -convert Register apps found in older LS database files -lazy n Sleep for n seconds before registering/scanning -r Recursive directory scan, do not recurse into packages or invisible directories -R Recursive directory scan, descending into packages and invisible directories

-f force-update registration even if mod date is unchanged

-u unregister instead of register -v Display progress information -dump Display full database contents after registration -h Display this help

PaSe
  • 93
  • 1
  • 1
1

Apparently under the sandbox you need to register in applicationWillFinishLaunching:, not applicationDidFinishLaunching:

See Apple's docs.

Andrew-Dufresne
  • 5,464
  • 7
  • 46
  • 68
Wil Shipley
  • 9,343
  • 35
  • 59