AppleScript and Finder in a sandboxed app

There is no way to script the Finder from a sandboxed app is there?


Finder has no access-groups vai sdef, so the only way i could get this to work is by using


<key>com.apple.security.temporary-exception.apple-events</key>

<string>com.apple.finder</string>


in the entitlements. Of course, this caused a rejection from Apple. Apparently, if i can convince the user to install AppleScript file(s) into FileManager.SearchPathDirectory.applicationScriptsDirectory it may work. Seems to be an high hurdle. Any other possible ways?


I understand, it's a valid security concern. I'm only using AppleScript to get the Desktop icon names and positions, the Desktop View Options text size and icon size and the bounds of the Desktop window. I use the return data to 'memorize' and 'restore' various icon arrangements on the Desktop. Is there any other way to achieve this in an macOS app that would not be rejected? I expect not, since it appears only the Finder knows such information.


Thanks,

Replies

Generally, any apps that interact with other apps or the system are frowned upon. The process is designed to reject such apps. If you manage to get it working, you may regret it later. Any potential solution would require some kind of system hack or reverse engineering. Apple is pretty good about letting little things slide. But technically speaking, if it isn't an API listed in Xcode's documentation, then it is not allowed and cause for rejection.


You yould probably have to reverse-engineer DS_Store files and try to extract the information from there. I'm not 100% certain the information is there. But even reading that file would require user consent, which you can't directly ask for in the Mac App Store. You can offer and document it, but you can't facilitate. You can allow the horse to drink, but you can't lead her there. And your app would have to be meaningfully functional without this access entirely.

Thanks John.


Since .DS_Store has never been documented, i'm not going to go down that rabbit hole. Again. If i recall correctly, icon positions are stored in .DS_Store only if the user manually moves the icons and further the Finder isn't required to follow the information in .DS_Store anyway.


I did try to appeal the rejection pointing out the information from/to the Finder is all user generated and i never touch it other than to store it and retieve it at user request. They said, probably correctly, "no".


They did say this, though:

Finder access may be possible by having user select the location via OpenPanel.


Please also be aware the app requires to install AppleScripts under Application Scripts directory in order to perform core functionality violates our “2.4.5 App installs Code” guideline.


Perhaps i can play around w/ NSOpenPanel and get the user to select it.


Not vey elegant or mac-like. Alas.

Generally, the advice I give to people in these situations is this: Imagine how you would implement an iOS version of your app. Do that on the Mac. If that would be a paradox or impossibility, then pick a new project. The Mac, as we know it, is simply not long for this world.

That seems to be reasonable advice.


I was able to figure out how to install the AppleScript via NSOpenPanel (trying to make it 'obvious' to the user why they need to hit the 'open' button...). Now i just have to refactor the rest of the code. I have a sneaking suspicion that even though i'm following the guidlines, App Store Review won't like it since the app has no functionality unless the user does hit 'open'.


Hope you're incorrect about the future of Mac. i do expect Automation on the Mac will continue to be more limited which, i think, is a true shame. If one is looking for hope, we now have Shortcuts on iOS which may imply the future of Mac Automation. Particularly if you do sdef on Finder.app, the only access-group is to Siri...

You can change the text on that button. You can also set the title on the dialog. However, if your app has no functionality without this, then it would be a waste of time. In my experience, Apple will reject any app that asks for an escape from the sandbox. You can offer one, but you can't lead the user to it. Just having a button immediately visible in the app is enough for a rejection.


Typically Apple rolls last year's iOS features into this year's macOS. Shortcuts for macOS is a strong possibility. Automator and AppleScript will probably be deprecated and removed next year or the year after.

so, i was able to communicate w/ an AppleScript that got stored in Application Scripts directory and it can communicate w/ the Finder w/o any special entitlements.


two questions:


1) in the completion handler to NSUserAppleScriptTask.execute, i get back a NSAppleEventDescriptor. the AppleScript returns a list with five elements. the first element is a list of strings, second element is a list of integer pairs, third element is a list of four integers and the last two elements are simply integers. so,


let i = resultAED!.atIndex(1)?.atIndex(1)?.stringValue


does, in fact, give me what i expect. therefore i conclude i must upwrap everything in the NSAppleEventDescritor? Is there no helpers available? when i was using AppleScriptObjC, the return from this script was simply an NSArray with five elements, first element was a string array, etc.


2) it was my understanding, that NSUserAppleScriptTask was not persistent. if there are properties defined in the AppleScript, those properties *are* persistent across runs. am i misunderstanding the use of 'persistent' here? for example


property number : {}
on getNumber
     display dialog "in getNumber " & number
     tell application "Finder" to set number to (count desktop's item)
end getNumber


on the first call to getNumber, it simply displays "in getNumber" in the dialog box. on the second call, it includes the number of Desktop's items. if i stop the code and rerun it, it still displays the number of Desktop's items. is that not 'persistent'? i will note this behavior is how AppleScript originally behaved (storing properties) and then changed with AppleScript Studio Applications (back in 10.4).


thanks,

Generally, any apps that interact with other apps or the system are frowned upon. The process is designed to reject such apps.

I'm not sure this is entirely accurate. I believe that scripting with other apps, in general, is perfectly acceptable as long as the entitlement can be justified. It's true that submitting an app to review which wishes to control Finder would most likely get rejected, but mainly because this could provide a means to escape the sandbox. This isn't the case in other contexts (i.e. scripting iTunes to play/pause a song).


To me, this is probably one of the main take aways for having these entitlements (along with scripting access groups) to begin with.

You are welcome to spend whatever time it takes building an app for the Mac App Store and submitting it in hopes that you are right.


Developers tend to consider sandboxing and the Mac App Store as one in the same. Why else would you ever sandbox? But Apple sees it entirely differently. Apple wants all apps to be sandboxed. Then, if you want to use AppleScript, you should use the preferred method scripting-targets. You can use a temporary exception, but there is no guarantee that the app in question will continue to support that particular event. Currently, scripting targets exist for Photos, Reminders, Safari extensions, Calendar, iTunes, Messages, Mail, and maybe System Preferences.


But all of that is entirely separate from App Review. Obviously any temporary exception is dead in the water. Whether or not you can use a scripting target is entirely App Review's call. I think you can freely script 3rd party apps, but again, only at App Review's discretion.

Should have the app ready for submission in a day or two (took me only a week, so not a huge time waste). We'll see. As far as i can tell, i'm doing what Apple claims they want. The user needs to take action before the app helps the user to install the AppleScript in Application Scripts and it makes clear why and they are allowed to back out. I fear i'll still run into their "2.4.5 App installs code" guidlines. Ugh.


Since AppleScript can save data with 'property' variables, it made the interface between the swift app and AppleScript very easy. It's amusing, in a sense, since an AppleScript i wrote back in System 7 days worked the same way.

So, rejected. Apparently for:


Your app installs scripts in shared locations.


Specifically, your app requires to install additional script in order to run.


Well, if there was a way to get the names and positions of icons on the Desktop w/o using AppleScript, i won't need AppleScript. And since an AppleScript inside the Bundle isn't allowed to talk to the Finder, there doesn't appear to be a way of doing this at all. Since this is all that the app does (stores and restores Desktop arrangements), i give up.


At least i learnt how to do NSUserAppleScriptTask w/ Swift. For what that's worth (not much, apparently).