On windows, using jpackage, I can silently install my app into APPDATA local. I rely on this behavior to set registry settings for my starter scripts for the app and updater, using,
System.getenv("APPDATA")
I do this so as not to have security issues with my app.
These are the locations where the apps are installed on mac and linux.
On Linux/Mac I believe they are talking about,
System.getProperty("user.home");
On windows I was having problems with the install due to security issues that do not apply to APPDATA. Was getting permission denied errors if I remember correctly.
Can I expect to run into similar issues on mac/linux using user.home?
The document you linked only shows the internal structure of the apps as generated by jpackage. This will end up being placed somewhere appropriate in the userâs system.
What error were you getting? Iâve been one of the primary maintainers of a java application that relies on user.home property cross platform, and weâve never had a report of a security error.
For more background:
Each platform has itâs own set of conventions for keeping application data:
Linux typically uses ${user.home}/.<app-name> (Note the leading dot to place a hidden directory)
Windows may use ${user.home}/AppData/. The full path for this should be what you get when you pull the APPDATA property.
Also on Windows, some programs use the same pattern as on linux. Including: gimp, virtualbox, ssh, oracleâs system-installed JRE, (Usage stats) & the JME SDK.
OSX prefers ~/Library/Application Support/<appname> (more specifically, the AppID defined in your Info.plist)
This path should be available under the system property NSApplicationSupportDirectory, similar to how you are pulling APPDATA on windows. See this Apple Document.
Of course, the linux-style hidden folder also work on mac.
The SDK seems to use the dot-folder approach, because it mostly just works on every platform.
Be aware that any of these locations are vulnerable to being deleted by the user, or another app. You should not be relying on them to be populated by your installer. Instead, make sure the app has a âbootstrapâ mode that can backfill the defaults if your configuration files are not present.
On macOS, the default is /Applications/application-name
On Windows, the default is c:\Program Files\application-name; if the --win-per-user-install option is used, the default is C:\Users\user-name\AppData\Local\application-name
These locations are not configurable when using jpackage , just subfolders of what I assume is user.home.
I know nothing about linux and mac os variables. On windows its
âProgramFilesâ by default, so I assume that user.home = /opt on linux and user.home = /Applications on mac?
If my memory is correct, using url prefix of file:/// on windows was getting permission denied from the
âProgramFilesâ directory.
APPDATA, no problems.
I donât see how thatâs a problem. Kinda confused by this since the user cant install it to a different location as jpackage is in control of the install. If what should be there isnât, things should not work.
I donât use defaults but instead throw exceptions. If I donât find what I am expecting, then it should not work period is how I look at it. At most, an error message telling them to contact support should be displayed is what I thought made sense. As long as the user leaves the program alone, no problem. If they meddle with it, thatâs on them.
I dont understand why you would want defaults if somethings not as you expect it to be but I have not ran this with users yet so you may be right.
No, with the exception of the --win-per-user-install, these are not subfolders of user.home
These installation locations are Absolute paths for system-wide applications.
user.home is the individualâs home directory:
/home/<username> on Linux
C:\Users\<username> on Windows
/Users/<username> on Mac
If youâre trying to open a file in java, the pathname is just a string without a prefix. Exactly as if you type it on the command line, eg. C:\My\Crazy\Directory
Your mentioning the user.home stuff made me believe that you were trying to manage per-user configurations/preferences/etc.
If this is actually per-application, youâd need to approach it a little differently. Some questions so that we arenât talking past each other:
Is this data read from inside the application?
Is this data read from outside the application, such as by a launcher?
Is this data written from inside the application?
Is this data written from outside the application, such as by a launcher?
I am using the updater to grab the file as part of the update process.
URLConnection downloadFileConnection = new URI(downloadUrl).toURL().openConnection();
Keeps everything in a small method.
The updater takes arguments.
Update server url
Version file to check for on update server
The dir where the version file lives on update server
Current version file name locally
The fully qualified path to the start script of calling app, based on os
The fully qualified path to the parent dir of the updater, based on os
The calling app sets them from enums in a UpdateCheck class.
The class that runs the check is in the client.
The updater:
The updater is not on the class path of the calling app.
The updater lives in a subfolder of the calling app.
Its only function is to look where you tell it and download what you tell it to get.
The updater has all its info in enums:
Where to save a download app file to.
Where to save a new updater file to.
The name of its version file.
The name of its startup script, based on os
The download server holds the exact same directory structure as is used for the calling app and updater app. Version files are created as part of the distZip build or jpackage build. I just unzip the updater distribution on the update server or upload the app image folder to the update server after jpackage is ran.
When client starts, it looks to see if any new updater files have been downloaded first, if so, moves them into the appropriate folders as is dictated by the version files. Then runs the updater. If nothing new, just runs the updater.
When updater starts, it first checks for a new updater, if found downloads it, exits and starts calling app. No new updater, it checks for new calling app. If found downloads, installs it and starts calling app. If nothing new for either, starts calling app with argument notifying the calling app nothing new has downloaded.
When calling app recieves notifcation there are no new updates, it skips updating.
If there are any problems, the app stops or the updater stops, breaking the cycle.
On windows, I use
environment variable to get the APPDATA dir.
This works fine for windows as I am familar with it but I am unsure of the proper way to get the linux /opt dir or the mac /Applications directory and once I do get them whether I will hit the same problem of grabbing a file.
If the updater is in the program files dir, it can access the user.home and download things to there but can things in user.home move files around inside program files?
You can check the operating system and location because itâs static. Windows + Program Files = elevated privileges. Youâll have to branch that logic in the installer/updater.
Edit: You can also check it in the installer and warn the user that elevated privileges are required if they install it in Program FIles.
Well, the flag for windows makes it pretty obvious: If you want to make system wide changes (i.e. installing/updating), you need system administrator privilegs.
For Linux, I guess you can only error out and request to be run with sudo privilegs (there also is a suid bit or something, though), for windows it is something about the app manifest, so nothing a jar can really do.
Steam installs there, so Iâd say no. There is a possibility that the user home is mounted with noexec flag, but i would say that it is generally safe to install thereâŚ
Especially on Linux, you do not want to force installation in one of the system folders. There are many flavors of Linux, and they each have different policies on how third-party software is installed. Itâs one thing if you are supplying distro specific packaging, such as a .deb or .rpm or .pkg, but, for generic installs, they should either be Unzip-in-place, or at most, apply file associations, etc.
Mac actually usually puts things in /Users/<name>/Applications
Iâm starting to think that this tool has issues⌠eek.
So, to recap:
Main application needs to write a configuration file that the updater uses to do a proper update
Iâm also noting that if there is a new updater program/class, youâre making two full round trips, launching App>updater>App>updater>App before its up and running? But leave that aside.
Good news: Since your configuration file is a core part of the app system, and you know where the App and updater are in relation to each other, you donât have to worry about managing all the system-specific stuff for this one file.
What you need is to teach the application how to find itâs own exact location at runtime.
The following was originally posted by someone named David Smiley on a mailing list in 2002:
URL url = <yourApp>.class.getResource("/path/to/<yourApp>.class");
if (url.toString().startsWith("jar:"))
{
String furl = url.getFile();
furl = furl.substring(0, furl.indexOf('!'));
dir = new File(new URL(furl).getFile()).getParent();
if (!new File(dir).exists())
return <error>;
}
You probably want to put it in a try block, but what Itâll do is give you the Absolute Path to the folder that your app.jar is in. You can then write your update config to whatever location relative to that that you need. (Probably in the subfolder where the updater lives)
And if the attempt to write the update config fails due to access conrol, just pop an error: âThe update process requires Administrator level access. Please re-run the application with admin privileges.â
I just confirmed with another mac user that this constant does not seem to be readable from inside java. Will probably need to hand-code the path relative to user.home