为什么 jar 文件在通过双击启动时没有从磁盘读取的权限 - 但如果从终端启动则没有?

Why does a jar file have no permissions to read from disk when started via double-click - but not if started from the Terminal?

在带有全新安装的 Big Sur 和 AdoptOpenJDK 11 的 MacBook Pro (2015) 上,我开发了一个 Java 用于教育目的的程序,该程序使用 JFileChooser。我没有使用任何 IDE 特定的代码。由于程序的其余部分无关紧要,这里是一个对我产生相同问题的最小示例(注意:这里仅作为示例,单击 按钮将打开文件选择器,选择一个文件并单击确定将更改按钮的文本 'OK'):

import javax.swing.*;
import java.awt.event.*;

public class Test extends JFrame implements ActionListener {

  private JFileChooser jf;
  private JButton jb;

  public Test() {
    setSize(480,320);    
    jf = new JFileChooser();
    jf.setDialogType(JFileChooser.OPEN_DIALOG);
    jb = new JButton("CLICK ME");
    jb.addActionListener(this);
    add(jb);
    setVisible(true);
  }

  public void actionPerformed(ActionEvent e) {
    if (e.getSource().equals(jb)) {
        jf.setVisible(true);
        final int result = jf.showOpenDialog(null);
        if (result == JFileChooser.APPROVE_OPTION) {
          jb.setText("OK");
        }
    }
  }

  public static void main(String[] args) {
      new Test();
  }
}

如果我通过终端启动程序java Test或使用java -jar Test.jar编译为jar)一切正常。我可以打开文件选择器,它会显示我磁盘上的文件和文件夹。

如果我通过双击启动已编译的 jar,程序也会启动,但是如果我打开文件选择器 我看不到任何文件我的磁盘,因此我无法将数据加载和保存到磁盘。

因为我只在 Mac 上遇到这些问题(在 Windows 10 或 Lubuntu Linux 上没有)这可能是一个非常具体的问题,因为 false Java我的 Mac 上的设置。但是,由于我为 Mac 安装了全新的 Big Sur 和 AdoptOpenJDK 11 且没有进行任何更改,我想知道其他想要 运行 我的程序的人(教师和学生)是否会出现此问题。

那么可能是什么问题以及如何解决这个问题(对我和其他人而言)?

我已经用 activity 监视器发现双击的 jar 是用 JavaLauncher 加载的(但我在磁盘上找不到它,我无法更改任何系统设置)。

我也在这里搜索过类似的问题。但这些主要与将文件保存在错误的路径有关。

很高兴找到解决方案。感谢您的回答!

自 Catalina(Big Sur 之前的一个版本)以来,mac 的安全策略有一个边缘性的愚蠢(因为大量评论者嘲笑此 'feature' 是愚蠢的)安全策略,其中每个应用程序当它试图触摸磁盘时得到一个弹出提示,请求用户的许可。每个主要文件夹(桌面、文档等,最终是整个磁盘)都有自己的弹出窗口。

当您双击 jar 文件时,jar 文件 运行s 'as its own app' 并获得自己的弹出窗口。大概你拒绝了一次,或者可能有些东西坏了,那些弹出窗口没有显示。

相比之下,当在终端中 运行ning java 时,如此产生的 java 进程最终会搭载终端应用程序的权限(如果您不想要那个,运行 open foo.jar,它要求 OS X 到 运行 罐子,而不是 java -jar foo.jar)。在您启动终端的那一刻,您已经获得了一个完整磁盘访问的弹出窗口,您可能对此说了 'yes',因此,由 shell 产生的任何 javas终端工作正常。

有一个简单的修复和一个硬修复。硬性修复是完全 'mac-osx-ize' 您的应用程序。为此,您需要使用 OpenJDK 发行版中的 jlinkjpackage。它们就在 javacjava 可执行文件旁边。您需要模块化才能正确使用这些工具。

它更难修复的原因是 java 桌面应用程序的官方分发模型已经改变。过去(最多 java 8),想法是:最终用户与 Oracle 达成协议:他们从神谕。 Oracle 将维护它(运行 更新程序,如果该 JRE 存在安全漏洞但他们没有告诉您,则将承担责任),然后该 JRE 将用于 运行 java 应用程序。您(桌面 java 应用程序的开发者)分发 jar 文件。

这不再是它的工作方式

这就是为什么 没有 JRE9(azul 和其他一些团体仍在制造它们;这是为那些还没有准备好维护过时的分发模型的尝试升级他们的分发策略。Oracle 不再发布 JRE,自 java9 以来就不再发布了,有意)。新模型符合几乎所有严肃的 java 桌面应用程序已经在做的事情:(应用程序的制造商)分发一个 JVM,可以 运行 你的应用程序,不是甲骨文。这样,您不必向您的用户解释在哪里下载 JRE(您的安装程序会这样做),并且您确切地知道您要运送给他们的 JRE 版本,而不是祈祷他们拥有的任何东西都可以 运行 你的东西。

这就是 jlinkjpackage 的意义所在。这样你最终得到一个 .app 文件,然后它适合普通的 mac 应用程序:如果用户拒绝磁盘访问,并且他们后来改变了主意,他们可以将 .app 拖到适当的位置像任何其他 mac 应用程序一样,在其系统偏好设置 window 的安全小部件中列出。 (而且,是的,大多数用户不知道该怎么做。Apple 把这部分搞砸了,java 无法解决 OS X 用户友好性方面的疏忽)。

简单的方法?嗯,致力于您当前的分发模型。不妨告诉他们如何从那里启动 Terminal 和 运行 java - 您已经要求他们从 AdoptOpenJDK 安装并且或多或少地迫使他们注意保持最新:您已经将最终用户视为知道如何管理自己的系统和安装复杂软件的高级用户。还不如多走一步,告诉他们 Terminal.app。

我有同样的问题 - 我几年前写了一个 java-for-all-desktops jar 应用程序,它在所有 java 版本和所有 Mac OS 和 Windows,直到我将 jar 文件放在 Big Sur (OSX 11.2) 上,此时它无法读取或写入 from/to 常规文件系统。就其本身而言,它默认只读取和写入 /private/var 中的 tmp 区域...而不是包含 jar 文件的目录,并可选择使用 jFileChooser 在真实文件系统中移动。我明确地将它设置为桌面上的开始,然后它可以移动到不同的目录但看不到或访问文件。

经过几个小时的折腾,我想出了如何根据上面的一些内容来修复它(谢谢!)......而且原来的海报太接近了!

我在 /System/Library/CoreServices/Jar Launcher.app

中找到了当您双击它们时启动 JAR 文件的程序

通过进入系统偏好设置 -> 安全 -> 隐私 -> 全磁盘访问,我能够导航到上面的 Jar Launcher.app 并将其添加到列表中,然后我的 jar 文件可以是双-单击并像往常一样工作,可以完全访问文件系统:)

不需要它来解决我的问题,因为,正如你们上面所说的那样,java 似乎从终端或 Jar Launcher 继承了它的访问权限,但如果有人需要,你可以还将 java 本身及其任何模块添加到完整磁盘访问列表(如上所述)。最简单的方法是使用 java -jar YourProgram.jar 从终端启动 jar,然后,当 jar 出现在 dock 中时,右键单击它并单击 Open in Finder。这将打开包含 java 可执行文件的文件夹。然后你可以用鼠标 select 它们并将它们拖到 Full Disk Access 列表中。我一直尝试这样做,但通过双击使罐子正常工作既不充分也没有必要。享受吧!