Why no SpecialFolder.TheApplication?

Mac Mojave

I am trying to distribute a simple application to friends/family. Mac only. Free. Desktop app.

No app store, no complicated installer.

What I want to do is just to provide a zip file. The user would unzip the file wherever they wanted on their machine and the application (MyApp) that I have created would be there as well as some support files that I have created all sitting in a folder called (MyAppFolder).

Now I want to have a file with a specific name (MyPicture.png, for example) somewhere that the user would create. It would be a .png file and the user would be told to put it in a given location. Inside the MyAppFolder at the same level as the application itself seems like a natural place and one that is easy to explain. The application itself would look for a file of the agreed-upon name (MyPicture.png in this example) and things would be cool.

Since the user could unzip the file that I provided in any location, I would need to figure out the path to MyAppFolder so I could reference the MyPicture.png. I would know that its path was …/MyAppFolder/MyPicture.png.

If I knew the path to the folder MyAppFolder, that would be easy to figure out. So I look to see if there is a SpecialFolder that refers to the Folder that contains MyApp but I cannot find it. That seems bizarre to me because it seems natural to me that this would be a useful location to know.

It seems that when I build an app (like MyApp) I am actually creating a “Package” and the executable is in the depths of that Package. It looks like … MyAppFolder/MyApp.app/Contents/MacOS/MyApp

Now if this were universally a true pattern then I can find my way to the MyAppFolder is a roundabout way

Var h As FolderItem
h = app.ExecutableFile 

Var folderOfApp As FolderItem
folderOfApp = h.Parent.Parent.Parent.Parent

Var pathFolderOfApp As String
pathFolderOfApp = folderOfApp.NativePath

But this makes me nervous. It seems very kludgy. More to the point, I wonder whether my assumptions are “wrong” in some way or under some circumstances that I am not anticipating. I am finding the FolderItem reference to the executable and then noticing a pattern that allows me to move up a certain number of folders and then retrieve a path of MyAppFolder. It seems like I am “fighting” something. That Xojo does not want or cannot provide an easy way to get to the path of the folder that contains the application.

I am doing something that is frowned upon? Is there a better way to meet the needs of having the user be told a “simple” place to put a file? It seems so natural to me that that place would be in the same folder as the application itself.

Your code looks great to me, BUT OS vendors (Apple and MS) frown upon placing files next to the Application — that is what the Documents folder is for. In an ideal world the Applications folder would be locked.

1 Like

how about to make a path selector and store the folderitem in settings?
if you start the app check if it still exists.

2 Likes

If you do that, these days OSX could slow your app to a crawl by pseudo-sandboxing it. (Translocation)
OSX expects apps to be in Applications (or a myfolder subdirectory of it) , and any files that are next to the app are expected to be read-only.
Ideally, these support files should be unpacked to application support at startup.

Files that the user can amend should be in Documents.
Allow your family to use a file selector to find their picture/whatever

I know you don’t want to go through code signing/notarisation etc, but the user experience will be better if you do.
At the least, consider putting ‘all your stuff’ in a DMG file. all they need to do is double click to mount it.
Your stuff is all local on that ‘drive’
They don’t even need to install if they dont want to (but see ‘translocation’ again)

To answer your specific question

You probably want app.ExecutableFile.Parent.Parent.Parent folder
messy or not.

2 Likes

less messy ?

Public Function ApplicationFolderItem() as FolderItem
  Dim f As FolderItem = SpecialFolder.Resources
  If f<>Nil Then
    #If TargetMacOS
      f = f.Parent.Parent
    #Else
      f = f.Parent
    #EndIf
    Return f
  Else
    Raise New NilObjectException
  End If
  
End Function
1 Like

Perhaps

Raise New PlatformNotSupportedException

would be more specific here

1 Like

good catch !

In an ideal world the Applications folder would be locked.

Not in my ideal world :slightly_smiling_face: In the distant past, when I was still walking to school barefoot in the snow, the Application folder and Documents folder were more like suggestions. This little app of mine is small enough and insignificant enough that I did not want to clutter the user’s Application folder or even top-level Documents folder with the little folder that contains my app. So I thought I would just let them put it in whatever obscure location that they wanted.

I had originally insisted that they place it at the top level of the Documents folder. That made it easy for me to determine the paths for MyPicture.png and my own included support files because of the Xojo’s SpecialFolder.Desktop. That was sort of OK except the recipients had to understand that it had to be at the top level of the Documents folder or else things would not work. Even this level of understanding can be difficult for my target audience. I was hoping to make things more foolproof with the kludge I came up with. But I could go back to that requirement.

Of course, with MyAppFolder being at the top level of the Documents folder, you have an application MyApp, however trivial, in a subfolder of the Documents folder rather than in the Applications folder. I am happy to bend the rules here if it makes no difference. But now Jeff Tulin is saying that this “incorrect” placement could

slow your app to a crawl

That is not something that I want. Is this inevitable? Is this something that might happen in the future?

The terms pseudo-sandboxing and translocation are not things that I really understand or sadly even want to understand because life seems complicated enough already. And, as Jeff speculates, that is why I do not want to go through code signing/notarization.

P.S. (excuse whining) I guess this is related to security issues and “bad guys”. The effect on this old guy/dog, who is reluctant to learn new tricks, is just depression :slightly_frowning_face:. Programming and programming languages are fun to learn and there are many resources for this. But the “baggage” that increasingly comes with programming makes things a lot more complex (translocation, virtual environments, file dependencies, GIT, notarization, etc.) For me, these issues are harder than learning the languages themselves, and simple explanations, directed at the beginner, harder to uncover.

2 Likes

I may explore this suggestion further. Right now, if the user does not provide a MyPicture.png, the app uses a default. It would not be too onerous to require the user to select their replacement in a file dialogue as a mechanism for substituting their MyPicture.png for the default. I suspect I could figure out how to put their selection in a “Settings” folder.

Are you implying that this mechanism would be OK if I just told the user to take the MyAppFolder and put that in their Application folder? And then proceeded. Are the users going to be hassled somehow when they put MyAppFolder in their Application folder?

Thanks for chiming in.

finally not because the exception is raised if f is nil, not if the target is unsupported ?

if me think as user i not like to unzip folders or create it somewehere.
i also not like creating or overwriting a image with a exact size.
what i like is selecting a foto and the app import it (drag and drop?) and use it and tell me where it was saved.
at windows maybe the app data folder which is part inside the user folder is a good location.
docs.xojo.com/SpecialFolder
because one app can handle multiple users the source image need a separated place.

I guess it was prior to Mac OS X, then.
Mac OS 9 didn’t have permissions like OS X have.
All your files/folders in OS X have permissions (owner, group, others having a set of permissions). You can check for yourself for existing permissions: the main user/administrator may (or may not) have write permissions, but other users usually have read-only permissions for an application (and if not, the OS might prevent the apps from launching because of security reasons). Proper permissions are “read-only” for the group, usually.
So even if you (the logged-in user) has write permissions in the bundle, you can be almost sure other users won’t be able to write to the files created by that user (and possibly, even no read permissions).
Even if there’s a single user only, you should not expect to be able to write in an app’s bundle.

Writing to an application after it has been built isn’t a good method, since Mac OS X at least, and it’s not designed for. For signed applications, it would also break the signature.

Consider using either a user’s folder (Documents, etc.) if you plan for only one user using your app or a shared location (the “/Library/Application Support” or “/Users/Shared” are two places for that). These are the proper ways.

How you are wanting to do it, is how I originally set up my app: user’s data in a folder next to the app. The advantage is it made it easier to move the app+data if the user wanted to. They could even just put it on a stick and carry it around and plug into another machine. They could even have Win/Lin/Mac versions of the app together with the user’s data folder on a USB stick, and carry that around and plug into any machine that was handy. (stick would have to be formatted as FAT, of course)

That would still be possible except for one thing: distribution. If you download a macOS app from a website these days, your app has to be code-signed and notarised, otherwise it’s hard to run it. And what a palaver this process is, and would be impossible for any normal human were it not for Our Sam, who has waved his magic wand over it.

So I modified my app: it runs, and if it discovers it is NOT somewhere in /Applications, it behaves as previously. If it discovers that it is, then it expects the user’s data folder in Documents. That’s easy enough to arrange.

If you don’t want to notarise, hopw will you distribute your app to people? You could do it on a stick, but I wouldn’t put it past Apple to ban even that, somehow.

1 Like

What does this mean? I do not know the reference. :man_shrugging:t2:

1 Like

This is a Mac only application. My plan was to just have a zip file that could be downloaded from my website. Then I would instruct users where to put the folder that the zip file produced. It would seem from the above that that location should be the Application folder.

How can I be forced to “notarize” it in this scenario? How is the user thwarted if I do not?

Now you say

your app has to be code-signed and notarised, otherwise it’s hard to run it.

What does that mean exactly. Hard to run it? It won’t run? It runs poorly? You have to give it permission?

Now I can and am willing to structure it so that if the user does want to provide their custom MyPicture.png that I can cajole them into placing that file in the Documents folder or some specifically named subfolder of the Documents folder.

He created AppWrapper, which allows an ordinary mortal to get an app code-signed and notarised. But you still have to navigate Apple’s Developer minefield: pay to become a registered developer, find and understand the two different web-sites to obtain the necessary certificates to feed into AppWrapper. I managed that, but it was more hit-and-miss than by having any sort of clear understanding of the process.

1 Like

“Our Sam” is Sam Rowlands, author of AppWrapper. This is invaluable for code signing/notarizing.

To your point of using the application’s enclosing folder as the user folder–as you say, for your select family audience who are not formally installing this, an easy solution might be to put your built application in a folder, and then zip that. Unzipped, your app is again in the folder. That would provide an easy way to get your folderitem, as this parent folder, absent another specified path, would be the default.

2 Likes

If a user downloads it, zipped or not, it will need to have been notarised. This process involes uploading the app to Apple, who look through it to satisfy themselves that it does not contain malware. They then record the app-specific password you supply to AppWrapper for that app, so that when the user first tries to run it, they can look up this password, see that the app is recorded as clean, and then allow it to run. Otherwise it will be prevented from running.

AppWrapper automates this process. The alternative is to disable SIP on the target machine, which involves using the Terminal; doesn’t sound like something your users would want to do.

AppWrapper is written by @Sam_Rowlands.

1 Like

Per Tim’s point about an unsigned app being “hard to run”, that means that Gatekeeper will not allow the app (on the first try) to launch by double-clicking. Instead, your users will have to right-click (or option-click) on the icon, and select “Open” from the contextual menu that appears. Then, after telling Gatekeeper that yes, you really want to run it, it will launch and the user won’t be nagged about it again.

1 Like

Ah, does that still work? I thought all those work-arounds were gradually being removed.