Launching an Mac App with Objective-C/Cocoa - objective-c

When launching Path Finder app with command line, I use open -a Path Finder.app /Users/.
Based on this idea, I use the following code to launch Path Finder.
Can I have launch app without using open command line?
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: #"/usr/bin/open"];
NSArray *arguments;
arguments = [NSArray arrayWithObjects: #"-a", #"Path Finder.app", #"/Users/", nil];
[task setArguments: arguments];
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
NSFileHandle *file;
file = [pipe fileHandleForReading];
[task launch];

if(![[NSWorkspace sharedWorkspace] launchApplication:#"Path Finder"])
NSLog(#"Path Finder failed to launch");
With Parameters:
NSWorkspace *workspace = [NSWorkspace sharedWorkspace];
NSURL *url = [NSURL fileURLWithPath:[workspace fullPathForApplication:#"Path Finder"]];
//Handle url==nil
NSError *error = nil;
NSArray *arguments = [NSArray arrayWithObjects:#"Argument1", #"Argument2", nil];
[workspace launchApplicationAtURL:url options:0 configuration:[NSDictionary dictionaryWithObject:arguments forKey:NSWorkspaceLaunchConfigurationArguments] error:&error];
//Handle error
You could also use NSTask to pass arguments:
NSTask *task = [[NSTask alloc] init];
NSBundle *bundle = [NSBundle bundleWithPath:[[NSWorkspace sharedWorkspace] fullPathForApplication:#"Path Finder"]]];
[task setLaunchPath:[bundle executablePath]];
NSArray *arguments = [NSArray arrayWithObjects:#"Argument1", #"Argument2", nil];
[task setArguments:arguments];
[task launch];

Based on yuji's answer in different posting, NSWorkspace is the tool to use, and I could get the same result with only two lines of code.
The openFile can be used for passing the parameter to Path Finder, which is normally the directory, not a file. However, it works fine.
[[NSWorkspace sharedWorkspace] openFile:string2 withApplication:#"Path Finder"];
[[NSApplication sharedApplication] terminate:nil];

Related

How to read macOS desktop file in cocoa app

I want to make cocoa app execute .sh file or other Operation,
this my code:
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"%#",[self cmd:#"cd Desktop;ls;"]);
}
- (NSString *)cmd:(NSString *)cmd
{
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath: #"/bin/bash"];
NSArray *arguments = [NSArray arrayWithObjects: #"-c", cmd, nil];
[task setArguments: arguments];
NSPipe *pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
NSFileHandle *file = [pipe fileHandleForReading];
[task launch];
NSData *data = [file readDataToEndOfFile];
return [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
}
but log error:
ls: .: Operation not permitted
how to do that?I search about macOS permit,Do I need use SMJobBless ?
Sandbox applications aren't allowed to read outside the application folder. So in order for your script to work you need to turn off Sandbox.
Also you need to change the path like Sangram S. mentioned or set the current directory to the home folder:
[task setCurrentDirectoryPath:NSHomeDirectory()];
change
NSLog(#"%#",[self cmd:#"cd Desktop;ls;"]);
with
NSLog(#"%#",[self cmd:#"cd ~/Desktop; ls;"]);

How to include and call an executable in a Cocoa app?

I can run an executable from a known local directory within a Cocoa app like this:
// Run the server.
NSTask *task = [[NSTask alloc] init];
NSPipe *pipe = [NSPipe pipe];
NSString* scriptPath = #"/Users/example/Server/runServerExecutable.sh";
[task setLaunchPath: #"/bin/sh"];
[task setArguments: [NSArray arrayWithObjects: scriptPath, nil]];
[task setStandardOutput: pipe];
[task launch];
Could anyone help me on these questions?
Where should I include the executable/script/text files in the app bundle?
How to modify scriptPath to run the script programmatically?
Thanks a lot!
Drag and drop the script/text files to your xcode project -> Project Navigator, so that it will get added to your project. Build the project. Open the Bundle, you will be able to see the added file in Resources directory.
Now, the code given below will help you get the file from the resources. For the sake of example, I have added a script by the name "OpenSafari.sh"
NSTask *temp = [[NSTask alloc] init];
[temp setLaunchPath:#"/bin/sh"];
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"OpenSafari" ofType:#"sh"];
NSArray *tempargs = [NSArray arrayWithObjects:filePath,nil];
[temp setArguments:tempargs];
NSPipe *temppipe = [NSPipe pipe];
[temp setStandardOutput:temppipe];
NSPipe *errorPipe = [NSPipe pipe];
[temp setStandardError:errorPipe];
[temp launch];
NSData *data = [[temppipe fileHandleForReading] readDataToEndOfFile];
NSString *result = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSData *dataErr = [[errorPipe fileHandleForReading] readDataToEndOfFile];
NSString *resultErr = [[NSString alloc] initWithData:dataErr encoding:NSUTF8StringEncoding];
Hope this helps!

Cocoa application - NSTask

How can I programmatically run terminal command?
Now I'm doing like this:
-(IBAction)proceedTapped:(id)sender
{
NSLog(#"%#",[self runCommand:#"cd ~"]);
NSLog(#"%#",[self runCommand:#"ls"]);
}
-(NSString *)runCommand:(NSString *)commandToRun
{
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath: #"/bin/sh"];
NSArray *arguments = [NSArray arrayWithObjects:
#"-c" ,
[NSString stringWithFormat:#"%#", commandToRun],
nil];
[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;
}
For single commands this code works well, but in my case, when I want to change directory
to ~(home) and then do 'ls' this doesn't work well (it looks like to run two commands in two different terminal windows).
So how to run multiple commands like in one terminal window ?
Thank you.
In one of my applications I have:-
- (IBAction)openDirInTerminal:(id)sender { // context only
DirectoryItem *item = (DirectoryItem *)[self.dirTree focusedItem];
NSString *s = [NSString stringWithFormat:
#"tell application \"Terminal\" to do script \"cd \'%#\'\"", item.fullPath];
NSAppleScript *as = [[NSAppleScript alloc] initWithSource: s];
[as executeAndReturnError:nil];
}
DirectoryItem *item = (DirectoryItem *)[self.dirTree focusedItem]; is my method, but replace item.fullPath with a Path.
You could add the 2nd command to the script string (followed by a newline).

NSTask crashes when used in function

In my program I currently use NSTask 5 times, and it all works very well, but I'm tired of having to repeat so much code when it's all so similar, so I tried putting it in a function. Unfortunately it results in a crash on the line: [task launch]. Other than that I can't figure out what's causing the crash as if I use this code outside the function it works perfectly.
The method I am using is as follows:
- (NSString *)performTask: (NSString *)launchPath: (NSString *)argument1: (NSString *)argument2: (NSString *)argument3: (NSString *)argument4: (NSString *)argument5
{
NSString *resPath = [[NSBundle mainBundle] resourcePath];
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath: [NSString stringWithFormat: launchPath, resPath]];
NSArray *arguments = [NSArray arrayWithObjects: argument1, argument2, argument3, argument4, argument5, nil];
[task setArguments: arguments];
NSPipe *pipe = [NSPipe pipe];
[task setStandardInput:[NSPipe pipe]];
[task setStandardOutput: pipe];
NSFileHandle *file = [pipe fileHandleForReading];
[task launch];
NSData *data = [file readDataToEndOfFile];
NSString *status = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
return status;
}
I really hope this can be fixed, I really cannot see why this crashes.
Thanks in advance everyone.
Check this out it's pretty cool I use it:
https://gist.github.com/1875386
It's also much easier than using arrayWithObjects: for NSTask...
rc

NSTask and FFMpeg losing output

I'm trying to call ffmpeg from NSTask in objective-c. I execute the ffmpeg command in terminal and it works flawlessly every time. I make the same command using NSTask, and it never gives me the whole output. It cuts it off half way through the output, at a seemingly random spot every time. Here is my code.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSString* ffmpegPath = [[NSBundle mainBundle] pathForResource:#"ffmpeg" ofType:#""];
NSString* path = #"test.mov";
NSTask *task = [[NSTask alloc] init];
NSArray *arguments = [NSArray arrayWithObjects: #"-i", path, nil];
NSPipe *pipe = [NSPipe pipe];
NSFileHandle * read = [pipe fileHandleForReading];
[task setLaunchPath: ffmpegPath];
[task setArguments: arguments];
[task setStandardOutput: pipe];
[task launch];
[task waitUntilExit];
NSData* data = [read readDataToEndOfFile];
NSString* stringOutput = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(#"%#", stringOutput);
NSLog(#"%i", [task terminationStatus]);
NSLog(#"DONE");
}
And just like that I figured it out. Apparently the output had non UTF8Characters in it. Switched it over to NSASCIIStringEncoding and voila. Magic.