How to use NSWorkspace launchApplicationAtURL? - objective-c

I tried to run equivalent of "TextMate foo.txt" using launchApplicationAtURL. The name of binary is "TextMate", and I have one parameter.
I tried the following code, but it doesn't seem to work.
// find the textmate
NSURL * bURL = [[NSWorkspace sharedWorkspace] URLForApplicationWithBundleIdentifier:#"com.macromates.textmate"];
NSWorkspace * ws = [NSWorkspace sharedWorkspace];
// find the parameter
NSString * f = #"foo.txt";
NSArray * myArray2 = [NSArray arrayWithObjects:f,nil];
NSMutableDictionary* dict = [[NSMutableDictionary alloc] init];
[dict setObject:myArray2 forKey:NSWorkspaceLaunchConfigurationArguments];
[ws launchApplicationAtURL:bURL options:NSWorkspaceLaunchDefault configuration:dict error:nil];
What's wrong with this?
Added
I checked this code actually works, I got something wrong with how 'TextMate.app' deals with the parameters.

Most apps don't use command line parameters. If you want to open a particular file with a particular app, use -[NSWorkspace openFile:withApplication:].

Related

Verify that the directory is a bundle

ALL,
I'm trying to rewrite some old code with the new OSX Cocoa API.
I got a suggestion to use
-[NSWorkspace openApplicationAtURL:configuration:completionHandler:]
to open and execute a bundle, however I'd like to do some sanity check first.
So my code will look like this:
NSURL *url = [NSURL fileURLWithPath:myPath isDirectory:YES];
NSBundle *bundle = [NSBundle bundleWithURL:url];
if( bundle == nil )
{
printf( "Not a bundle!!";
return -1;
}
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
NSRunningApplication *app = [ws ...];
Am I right? Or there is a better way to do that?
Also, I think I don't need to delete NSBundle object, right?
TIA!
[EDIT]
I tried to produce the following code:
NSWorkspace *ws = [NSWorkspace sharedWorkspace];
NSRunningApplication *app = [ws launchApplicationAtURL:url options:NSWorkspaceLaunchAsync
configuration:[NSDictionary dictionaryWithObject:params forKey:NSWorkspaceLaunchConfigurationArguments]
error:&error];
[params release];
if( app != nil )
pid = [app processIdentifier];
However when I tried to supply /bin/ls I git pid as -1.
Can I successfully rely on the fact that this method will return -1 on non-bundle application?
[/EDIT]
If you want to know that a given URL is an application, get and check the NSURLIsApplicationKey resource of the NSURL.
However, there's really no need to do this: -openApplicationAtURL:configuration:completionHandler: will perform whatever sanity checks are appropriate and fail if there's a problem. So pre-flighting it will just do this preliminary work twice.

How would I get the other app's version from mac app

How would I get the other app's version.
I can use [NSWorkspace fullPathForApplication:(NSString *)appName] to get app's path, can I get the app's info?
There's several ways you can accomplish this — I usually take the shortest route using NSBundle in addition to CFBundleversion:
NSBundle *appBundle = [NSBundle bundleWithPath:appPath];
NSString *bundleVersion = [appBundle objectForInfoDictionaryKey:#"CFBundleVersion"];
Once you have the full path to the Application, you can read the Contents/Info.plist file and look at the CFBundleShortVersionString value.
Something like this:
NSString *appPath = [NSWorkspace fullPathForApplication:appName];
NSString *plistPath = [appPath stringByAppendingPathComponent:#"Contents/Info.plist"];
NSDictionary *plist = [NSDictionary dictionaryWithContentsOfFile:plistPath];
NSString *version = plist[#"CFBundleShortVersionString"];

LSCopyApplicationURLsForURL always returns null

When I try to log all available editors on my system for my temporary file (which is "toString" in this code) it always returns null, although I have many applications installed on my system.
NSArray *appUrls = (NSArray*)LSCopyApplicationURLsForURL((CFURLRef)[NSURL URLWithString:toString], kLSRolesViewer | kLSRolesEditor);
toString is containing the following file path:
/var/folders/pl/tcc5k3fd6tj2__9dprg9dm1m0000gp/T/tempFile
What should be the problem here?
[NSURL URLWithString:toString]
expects a complete URL string including scheme, such as "file://var/folders/...".
Use
[NSURL fileURLWithPath:toString]
instead to get a file URL with the specified path.
Another problem could be that your file name does not have any file extension (e.g. ".txt"), because Launch Services uses the extension (or file type/creator) to find a suitable application.
I was struggling with the this and I wanted to get all Bundles that could open a determined path/file extension.
If you have a file extension, you can get all bundles that can edit it by the following:
//All Bundle Ids
NSString *pathExtension = #"docx";
CFArrayRef utisRef = UTTypeCreateAllIdentifiersForTag(kUTTagClassFilenameExtension,(__bridge CFStringRef) pathExtension,nil);
NSLog( #"UTI: utisRef %#", utisRef);
NSArray *utis = CFBridgingRelease(utisRef);
NSMutableSet *mutableSet = [[NSMutableSet alloc] init];
for (NSString *uti in utis) {
CFArrayRef bundleIDsRef = LSCopyAllRoleHandlersForContentType((__bridge CFStringRef) uti,kLSRolesEditor);
[mutableSet addObjectsFromArray:CFBridgingRelease(bundleIDsRef)];
}
NSLog( #"bundleIDs: %#", mutableSet);
If you have a path of file and you want to get all apps location that can edit it, you can use the following:
//Location of apps
NSString *str = #"/Users/ricardoanjos/Library/Developer/Xcode/DerivedData/EgnyteDrive-hforbniifiojczefbnwanzxakvlr/Build/Products/Debug/1.pdf";
NSURL* url = [[NSURL alloc] initFileURLWithPath:str];
CFURLRef urlRef = (__bridge CFURLRef)url;
CFArrayRef appUrlsRef = LSCopyApplicationURLsForURL(urlRef, kLSRolesEditor);
NSArray *appUrls = CFBridgingRelease(appUrlsRef);
NSLog(#"appUrls: %#", appUrls);
I hope it will help.

NSRegularExpression not working

I'm try to parse a photo id out of a facebook url, e.g.,
https://www.facebook.com/photo.php?fbid=267217740038587&set=a.207272412699787.48907.100002510899673&type=1
My regex is #"https?:\/\/(www\.)?facebook\.com\/photo\.php\?fbid=([0-9]+)"
I tested this with an external tool RegExhibit - http://homepage.mac.com/roger_jolly/software/ and it seems to work fine.
However it does not work in XCode. I tried to debug and the problem seems to be the \? after photo\.php. When I change it to
#"https?:\/\/(www\.)?facebook\.com\/photo\.php.fbid=([0-9]+)" (notice I change \? to .)
it works perfectly.
While this is acceptable I would like to know why \? doesn't work here. Any expert? :-)
I'm not sure, but perhaps the back slashes \ are escaping the relevant following character in the NSString itself when it is parsed. For instance,
NSLog(#"https?:\/\/(www\.)?facebook\.com\/photo\.php\?fbid=([0-9]+)");
actually prints https?://(www.)?facebook.com/photo.php?fbid=([0-9]+) which if then treated as its own regex would execute the way you describe it (and does execute semi-properly if you replace the ? with a .)
So, I'm guessing for it to work properly, you'd need #"https?:\\/\\/(www\\.)?facebook\\.com\\/photo\\.php\\?fbid=([0-9]+)" instead.
You can try this:
NSString *query = #"parameter=2&secondparameter=3"; // replace this with [url query];
NSArray *components = [query componentsSeparatedByString:#"&"];
NSMutableDictionary *parameters = [[NSMutableDictionary alloc] init];
for (NSString *component in components) {
[parameters setObject:[[component componentsSeparatedByString:#"="] objectAtIndex:0] forKey:[[component componentsSeparatedByString:#"="] objectAtIndex:1]];
}

ScriptingBridge Finder POSIX path

is it possible to get the POSIX path or target to the frontmost window using the Scripting Bridge framework?
I'm using
FinderApplication *theFinder = [SBApplication aplicationWithBundleIdentifier:#"com.apple.Finder";
but I can't find anything in "Finder.h" that could work.
This might be what you are after using ScriptingBridge and NSURL
FinderApplication *finder = [SBApplication applicationWithBundleIdentifier:#"com.apple.finder"];
SBElementArray *windows = [finder windows ]; // array of finder windows
NSArray *targetArray = [windows arrayByApplyingSelector:#selector(target)];// array of targets of the windows
//gets the first object from the targetArray,gets its URL, and converts it to a posix path
NSString * newURLString = [[NSURL URLWithString: (id) [[targetArray objectAtIndex:0]URL]] path];
NSLog(#"newURLString %# ", newURLString);
Running drawnonward's code through appscript's ASTranslate tool gives me this:
#import "FNGlue/FNGlue.h"
FNApplication *finder = [FNApplication applicationWithName: #"Finder"];
FNReference *ref = [[[finder windows] at: 1] target];
FNGetCommand *cmd = [[ref get] requestedType: [ASConstant alias]];
id result = [cmd send];
The result will be an ASAlias instance; use -[ASAlias path] to get the POSIX path.
You can't do it in SB short of resorting to raw Apple event codes as that's one of the features the Apple engineers forgot/didn't bother to put into SB's less than stellar API.
I have not used ScriptingBridge. As part of an NSAppleScript it would be:
get POSIX path of (target of window 1 as alias)
Hopefully that helps. I think the POSIX part is from the StandardAdditions ScriptingAddition, not the Finder itself.