OSAKit.framework usage for executing scripts - objective-c

I am on XCode 9.2, Objective-C, MacOS
i am looking for any example on using osakit.framework to execute a script file(applescript = .scpt or .applescript) or a method in that file with parameters and how to get the response.
My own implementation of applescript works but leaks too much memory so i want to try osakit.framework but its documentation is bad.
The simple implementation is like this
OSAScript *scriptNAME= [[OSAScript alloc] initWithSource:#"tell application \"Firefox\" to return name of window 1"];
NSDictionary * errorDict = nil;
NSAppleEventDescriptor * returnDescriptor = [scriptNAME executeAndReturnError: &errorDict];
NSLog(#"%#", returnDescriptor);
But instead of the script as source in text form i want to load my script file.
Edit:
I tried it with
OSAScript *scriptNAME= [[OSAScript alloc] initWithContentsOfURL:myScriptURL error:&error];
The script gets loaded but i can't call any method.
I Have two simple methods
on test()
display dialog "Hello World"
end
on testWithArguments:arg
display dialog (arg's item 1)
end
The call for the second method i tried:
[scriptNAME executeHandlerWithName:#"testWithArguments" arguments:#[#"Hello World"] error:&errorDict];
-- doesnt work
[scriptNAME executeHandlerWithName:#"testWithArguments:" arguments:#[#"Hello World"] error:&errorDict];
-- doesnt work

Bug found.
It was a wrong configured applescript file. Was declared as a script object from a former test. As simple applescript file it works great.

Related

Xcode: Getting the path for AppleScript file in Obj-C/Cocoa project with pathpathForResource

I have a plugin development project in X-code (10.2.1), and am trying to incorporate some AppleScript code (FatApple.applescript) into one of the methods in my implementation file.
On the AppleScript side: I have tried writing the code in Script Editor, saving to Desktop, dragging and dropping the FatApple.scptd in the "Resources", "Other Sources", etc. folders. I have tried the same steps after starting a new Xcode Project for AppleScript and dragging and dropping the FatApple.applescript file (tried with pathWithFormat type as both "scpt" and "applescript".
In Xcode I have added the FatApple.applescript to the Copy Bundle Resources, and removed from Compile Resources.
-(float) calcThing
{
NSAlert *alert=[[[NSAlert alloc] init] autorelease];
NSBundle *bundle = [NSBundle mainBundle];
NSString *path = [bundle pathForResource:#"FatApple" ofType:#"scpt"];
NSString *countstr=[NSString stringWithFormat:#"path=%#",path];
[alert setMessageText: countstr];
[alert runModal];
NSAppleScript *script = [[NSAppleScript alloc] initWithContentsOfURL:[NSURL fileURLWithPath: path] error:nil];
[script executeAndReturnError:nil];
}
I would expect to compile and run my plugin, call it in the program and receive a message with the path to my AppleScript, then ideally I could call the script and start doing stuff. Instead I receive "path=(null)".
I copied your code verbatim into a project and it worked for me, using a dummy AppleScript. The only difference I can see is that I dropped the AppleScript in the main file list rather than in the resources folder, but that shouldn't make any difference. The script shows up in the app resources folder like yours does.
The only questionable thing I see in your code is that you used NSBundle's - pathForResource:ofType: instead of - URLForResource:withExtension:. NSAppleScript wants an NSURL, so asking the bundle for a path and then converting it to a URL seems like an unnecessary step, and unnecessary steps are inherently suspicious. I can't see why that would make a difference (unless the plugin context does something funky to resource file paths), but, you know...

Mail: Application isn't running

I'm trying to execute simple AppleScript in Objective-C. The code is:
NSString *emailString = #"tell application \"Mail\" to activate";
NSAppleScript *emailScript = [[NSAppleScript alloc] initWithSource: emailString];
NSDictionary *errorDict = NULL;
[emailScript executeAndReturnError: &errorDict];
And got this annoying error:
NSAppleScriptErrorMessage: Mail got an error: Application isn’t
running. NSAppleScriptErrorRange: NSRange: {27, 8}
NSAppleScriptErrorBriefMessage: Application isn’t running.
NSAppleScriptErrorNumber: -600 NSAppleScriptErrorAppName: Mail
It's no problem if I execute the script from Script Editor. I need some help — Thanks!
Solved. My app using Sandbox. And if you want run AppleScript from it, you need edit entitlements file. In me case this help.

ScriptingBridge without sdef? (cocoa)

I'd like to get properties of the currently active app. I understand that this should be possible with ScriptingBridge, however, this seems to require you generate an sdef file and import this in your project for the app you are trying to target. Since I want to target all apps, is there another way to do this?
Example of accessing system preferences:
SystemPreferencesApplication *systemPreferences =
[SBApplication
applicationWithBundleIdentifier:#"com.apple.systempreferences"];
If there's another way to access properties of any active app, please do share. (For example; window title)
Thanks.
I assume you want to run an applescript. The scripting bridge is good if you have a lot of applescript code to run. However if you only have a small amount then a simpler way is with NSApplescript.
For example if you wanted to run this applescript...
tell application "System Events"
set theProcesses to processes
repeat with aProcess in theProcesses
tell aProcess to get properties
end repeat
end tell
Then you can write it this way...
NSString* cmd = #"tell application \"System Events\"\nset theProcesses to processes\nrepeat with aProcess in theProcesses\ntell aProcess to get properties\nend repeat\nend tell";
NSAppleScript* theScript = [[NSAppleScript alloc] initWithSource:cmd];
NSDictionary* errorDict = nil;
NSAppleEventDescriptor* result = [theScript executeAndReturnError:&errorDict];
[theScript release];
if (errorDict) {
NSLog(#"Error:%# %#", [errorDict valueForKey:#"NSAppleScriptErrorNumber"], [errorDict valueForKey:#"NSAppleScriptErrorMessage"]);
return;
}
// do something with result
NSLog(#"result: %#", result);
You can get a list of every currently running Application with
NSWorkSpace.sharedWorkspace.runningApplications;
Each object in that array should be an NSRunningApplication, which you can query and manipulate freely.

writeToFile fails when writing to desktop

I have this code snippet below. The purpose is to write the contents of an array to a plist file. When I run this I don´t get any errors and everything seems to be fine. The problem is that the file doesn´t appear on the desktop. I used writeToFile before in other projects without any problems. What is wrong with it? Greetings from Switzerland, Ronald Hofmann.
- (IBAction) doActionPlist: (NSButton *) sender
{
NSString *fileExt = #".plist";
NSArray *myResultArray = [NSArray arrayWithObjects:
#"Product Number Unlimited Desktop:",
#"4DDP120-UUS001-ANLKR-17C6B",
#"4DDP130-UUS001-ANQEI-1BC12",
#"4USE120-UUS001-80BY1-1EAB0",
#"4USE130-UUS001-6NTUE-11D64",
#"qA0iHnw4EIgOALgAAAQCmUtj",
#"qA0iHnw6EIgAALgAAPUBhByg",
#"4DDP11U00USN001",
#"4DDP13U12USN001",
#"4UCL00U00USN001",
#"4UCL00U00USN010",
#"4UCL11U00USN001",
#"4UCL11U00USN010",
#"4UCL12U11USN001",
#"4UCL12U11USN010",
#"4UCL13U12USN001",
#"4UCL13U12USN010",
#"4USE12U11USN002",
#"4USE13U12USN002",
#"4UWE13U12USN999",
nil];
NSString *thePath = [NSString stringWithFormat:#"/Users/ronny/Desktop/Testfile%#",fileExt] ;
[myResultArray writeToFile:thePath atomically:YES] ;
}
Unfortunately, it can be difficult to debug this call because it only returns YES or NO with no further information about why it succeeded or failed. The fact that it's not throwing any exceptions doesn't necessarily mean that nothing is going wrong; it just means that NSArray can't be bothered to tell you about it.
If you're really at wit's end, you might try converting your NSArray to NSData using NSPropertyListSerialization and then using writeToFile:options:error instead. If you do this, post the error message and someone should be able to offer better debugging advice.

Is there a way to programmatically connect to a remote server from Cocoa?

Is there an Coca/obj-C API call to mimic the "Connect to Server" action in Finder? It's possible with Automater, so it seems like Finder has a hook somewhere.
Turns out there's an old Carbon function (can't find a Cocoa equivalent) called FSMountServerVolumeSync which does what I was looking for. You can supply and smb:// URL and login credentials.
File Manager Reference
OSStatus FSMountServerVolumeSync (
CFURLRef url,
CFURLRef mountDir,
CFStringRef user,
CFStringRef password,
FSVolumeRefNum *mountedVolumeRefNum,
OptionBits flags
);
An easy way is to just run some applescript code. I'll show you 2 choices. This first one is the standard way to show that Finder window from applescript.
NSString* cmd = #"choose URL";
The resulting window is bare-bones though, so you can actually open the Finder's window with this command...
NSString* cmd = #"tell application \"Finder\" to activate\ndelay 0.2\ntell application \"System Events\" to keystroke \"k\" using command down";
After choosing either of the "cmd" strings, you can execute that applescript code with this...
NSAppleScript* theScript = [[NSAppleScript alloc] initWithSource:cmd];
[theScript executeAndReturnError:nil];
[theScript release];
This might not be the best way, but can't you just use mount?