Create AppleScript as application programatically

Hello,

I would like to create an AppleScript as an application, from my XOJO app, so that when it is launched it runs immediately.

I did this:
Dim TheAppleScriptScript as FolderItem
TheAppleScriptScript = SpecialFolder.Desktop.child(“TheAppleScriptScript.applescript”)

I added the appropriate code and it is launched in the ScriptEditor but I have to click the “Run” icon for it to be executed.

How do I save that script as an application so that when it is launched it runs?

Thanks.

Lennox

You possibly need to convert the script into an executable via the osacompile command line tool which you could invoke via a Xojo Shell.

What is wrong with embedding the script into your app? Don’t forget that you need proper permissions.

1 Like

Hi Kevin g,
Thanks, that seems to be my issue, can you suggest some code to do that?
The script is compiled and launched, so the problem is making it an AppleScript application rather than a scrip… the script has to be run manually, while the application will run on launching.

Thanks again.

Lennox

Thanks Beatrix,
The script is name-dependent, so it will work for John Doe but not Jane Doe.
The script has to be made each time the app is used.
Thanks again.
Lennox

I’m not sure to understand your problem but if I do, this may help.
Add at the beginning of your script:
on run {MyStg1, MyStg2, MyStg3} -- We receive string from Xojo
If you need only one string, just put only one. In Xojo you do:
MyAppleScript(“John”, “Doo”) or MyAppleScript(“John Doo”) depending what you prefer.
I suppose the name will be in a Xojo var string, then you write in Xojo:
MyAppleScript(MyXojoStringWithName)
Just in case you want to use something the applescript return, just write at the end of your applescript:
Return MyStringEnd -- Variable which contains what I need in Xojo.
And in Xojo:
AppleScriptReturnStg = MyAppleScript(MyXojoStringWithName)

Note: I repeat, AppleScript can only receive and return string. It can receive more than one string but can return only one.

See runAs from Xojo + Alfred . This allows you to define and AppleScripts in Xojo code. The below script runs an AppleScript for all available accounts in Mail:

'make script when there isn't one
if AccountTypeAppleScript = nil then
  
  AccountTypeScript.Add "property theAccount: ''"
  AccountTypeScript.Add "tell application id 'com.apple.mail'"
  AccountTypeScript.Add "set theAccountType to (get account type of account theAccount)"
  AccountTypeScript.Add "return theAccountType"
  AccountTypeScript.Add "end tell"
  AccountTypeAppleScript = new RunAS(AccountTypeScript, array(0), false, true)
  
end if

'run with current account
dim theAccountDictionary as Dictionary = RunAS.MakeDictionary("theAccount", theAccount)
AccountTypeAppleScript.ExecuteScriptWithParameters(theAccountDictionary)
return AccountTypeAppleScript.getResult

Thanks Beatrix,

That may be useful for me sometime in the future.

Let me explain what I want to do:

I am a gynaecologist and I see several patients per day.

There is the Data Protection Act which has lots of requirements, including not displaying any patients data.

So after I have seen a patient, several windows are displayed on my two monitors.

I have to close all those windows before the next patient comes in.

When I close my main window which has the patient’s current medical data, I would like all those windows to be closed at the same time.

I have this code at the bottom of my CancelClose event…

Dim TheAppleScriptScript as FolderItem
TheAppleScriptScript = SpecialFolder.Desktop.child("TheAppleScriptScript.scpt")

Dim TOS as TextOutputStream
If TheAppleScriptScript <> Nil and TheAppleScriptScript.Exists then TheAppleScriptScript.delete

If TheAppleScriptScript <> Nil and not TheAppleScriptScript.Exists then
  TOS = TextOutputStream.append(TheAppleScriptScript)
  TOS.WriteLine "tell application ""Finder"""
  TOS.WriteLine "try"
  TOS.WriteLine "close (window " + """" + app.gmyPatientFilesFolder.name + """" + ")"                                                                                   //""Hx Jane Doe 1981-07-28"")"
  TOS.WriteLine "close (window ""The Patient Records Folder"")"
  TOS.WriteLine "end try"
  TOS.WriteLine "end tell"
  TOS = Nil
end if

TheAppleScriptScript.Launch

It works, but the AppleScript is displayed and I have to manually click the “Run” icon to close those windows, then I now have to manually quit Script editor.

I would like to circumvent those manual clicks.

Any suggestions?

Thanks again.

Lennox

It would be far easier to send an AppleEvent to the Finder to close the given window:

var ae As new AppleEvent("core","clos","com.apple.finder")
var o As AppleEventObjectSpecifier=GetNamedObjectDescriptor("cwin",nil,"Window's title")
ae.ObjectSpecifierParam("----")=o

call ae.Send

(replacing “Window’s title” with the actual title, of course)

Thanks Arnaud,

Compiles but do not execute close the windows.

var ae As new AppleEvent("core","clos","com.apple.finder")
var o As AppleEventObjectSpecifier=GetNamedObjectDescriptor("cwin",nil,app.gmyPatientFilesFolder.name)
ae.ObjectSpecifierParam("----")=o

call ae.Send


'var ae As new AppleEvent("core","clos","com.apple.finder")
o = GetNamedObjectDescriptor("cwin",nil,"The Patient Records Folder")
ae.ObjectSpecifierParam("----")=o

call ae.Send

Thanks again.

Lennox

That’s weird; I wrote and checked the code before submitting. If you’re sure the window’s title matches exactly, you may possibly just try this code in a blank project (this avoids others possible issues).
Is your app notarised?

Tried it in a blank project… windows do not close.
My project is not notarised.

Lennox

Anything that needs permissions may need a permanent version of the app or macOS will forget the permission when the debug app is killed. And even in debug the app needs to be signed for full disk access. I don’t remember if this is also true for AppleScript.

If you own (or want to try) the MBS plugin, this could work (permissions must be granted):

Var source As String = "tell application ""Finder""" + EndOfLine.Macintosh + _ 
"try" + EndOfLine.Macintosh + _
"close (window " + """" + app.gmyPatientFilesFolder.name + """" + ")"  + EndOfLine.Macintosh + _
"close (window ""The Patient Records Folder"")" + EndOfLine.Macintosh + _
"set result to errMsg" + EndOfLine.Macintosh + _
"end try" + EndOfLine.Macintosh + _
"end tell"

Var n As New NSAppleScriptMBS(source)
Var d As Dictionary
Var result As NSAppleEventDescriptorMBS = n.execute(d)

If d <> Nil Then
  // display errormessage
  MessageBox (d.Value(NSAppleScriptMBS.NSAppleScriptErrorMessage))
End if

Thanks Thomas and Beatrix,

I do not have the MBS plugins,

I just have to do the manual clicks.

Thanks again.

Lennox

Did you have a look at my code? You can use both the MBS plugin and the shell.

Hi Beatrix,

I read your code but I do not know how to use it for my needs.

All I want is to close two windows when I close my app, the code will go in the close event of my app.

The two windows are:
“The Patient Records Folder”
and
“Hx Jane Doe 1981-07-28”

My apple script works, regardless of the location of the folders, once the windows are opened, on closing my app the AppleScript is launched but I have to click “Run the script” icon for the windows to close.

That works but I have to manually click “Run the script” and then quit Script Editor.

I do not want to perform those two clicks manually.

Any other suggestions/code will be appreciated.

My app is an app for my personal use, t is not being old.

Thanks again.

Lennox

Does it help to know that Cmd-Opt-W is “Close all windows” in Finder?

go into the privacy and security pane and make sure that your application has permissions to control the finder via automation. You may have to reset this after each build of the app, but you may not it does not seem consistent to me. You may not be able to get this working for a debug build as the app will go away when you’re done running it and so you can’t add it to the list. If you can put a delay before you run the script then it may work OK.

Then just pass your file to osascript in the terminal. So after you’ve written the file out do something like:

dim sh as new shell
sh.execute( “/usr/bin/osascript “ + TheAppleScriptScript.shellPath)

1 Like

OK, I have a workaround…

Just as I had it before, the AppleScript is created and launched.
I now save it as an app, put it in the patients folder and launch ehe AppleScript.app when I am closing the patient’s main file… works great, I do not have to make those clicks again.

The drawback is that I have to create the AppleScript.app for each patient, but I only have to do it once for each new patient.

Thanks everyone for their inputs, concern and willingness to help.

Thanks again.

Lennox