Services menu launches wrong application bundle

2019-08-30 10:12发布

问题:

I have implemented a MacOS Service based on the 'simpleEncrypt' example from the Apple documentation. I'm running 10.9 and Xcode 6.2.

I can build the application bundle, copy it to /Applications, run it once, and my service will appear in other applications' Services menu as expected.

If I run 'pbs -dump_pboard', the correct path to my application bundle appears as NSBundlePath, as expected.

However, when I select my service from a Services menu, MacOS will launch an old copy of my application that resides in ~/Library/Developer/Xcode/Archives.

If I delete that old copy, it will run another copy from someplace else. Only after I delete every other application bundle on the filesystem that has the same CFBundleName as my service's NSPortName will MacOS launch the right one from /Applications. And when it does, the service works properly.

How can I get MacOS to reliably invoke the correct application bundle for my service?

回答1:

In OS X, applications are registered with Launch Services, which is responsible for executing an application when requested, either by double-clicking on its app bundle, via spotlight, or in your case, running from the Services menu.

Registration is automatic and happens, for example, when an application is copied to the /Applications folder (which does more than just copy the files) or even by just running the process.

The list of registered applications can be viewed by running the lsregister command with the -dump argument. On OS X 10.10, it would be this: -

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

As you have multiple copies of the same application, their registration details are identical, so Launch Services will not update its database and simply executes the first seen application matching the registration details.

In the Apple docs, it suggests that you can either register the application in code with the functions LSRegisterFSRef and LSRegisterURL, using the inUpdate boolean parameter, or alternatively:

update the modification time of the application to ensure that it will be updated by the automatic registration utilities

I expect you'll still have to run the application directly, to ensure Launch Services updates its database. In the case of a bundle, you can navigate directly to the application's binary. Using Caculator.app as an example you'd execute:-

/Applications/Calculator.app/Contents/MacOS/Calculator

Another option I've found is to update the application's Info.plist by incrementing the version number, or more radically, changing its CFBundleIdentifier.