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

问题描述

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

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 上没有),这可能是一个非常具体的问题,因为我的 Mac 上的 Java 设置是错误的。但是,由于我在没有更改任何内容的情况下为 Mac 安装了 Big Sur 和 AdoptOpenJDK 11 的新副本,我想知道其他想要运行我的程序的人(老师和学生)是否会出现此问题。

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

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

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

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

解决方法

自从 Catalina(Big Sur 之前的一个版本)以来,Mac 的安全政策一直很愚蠢(因为很多评论者嘲笑这个“功能”是愚蠢的),每个应用程序在运行时都会弹出提示尝试触摸磁盘,请求用户许可。每个主要文件夹(桌面、文档等,最终,整个磁盘)都有自己的弹出窗口。

当您双击一个 jar 文件时,该 jar 文件会“作为自己的应用程序”运行并获得自己的弹出窗口。大概你否认过一次,或者可能是有些东西坏了,那些弹出窗口没有显示。

相比之下,当在终端中运行 java 时,如此产生的 java 进程最终捎带了终端应用程序的权限(如果你不想这样,运行 open foo.jar,它要求 OS X 运行 jar,而不是 java -jar foo.jar)。在您启动终端的那一刻,您已经获得了一个用于完整磁盘访问的弹出窗口,您大概对此说“是”,因此,由终端产生的外壳产生的任何 java 都可以正常工作。

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

之所以更难修复,是因为 Java 桌面应用程序的官方分发模型发生了变化。在过去(直到 java 8),想法是: 最终用户与 Oracle 达成协议:他们从 oracle 下载 java 运行时(“JRE”)。 Oracle 将维护它(将运行更新程序,否则如果该 JRE 存在安全漏洞并且他们没有告诉您,则承担责任),然后此 JRE 将用于运行 Java 应用程序。您(桌面 Java 应用程序的开发者)分发 jar 文件。

这不再是它的工作方式

这就是为什么没有 JRE9(azul 和其他一些团体仍在制作它们;这是为那些尚未准备好升级其分销策略的人维护过时的分销模式的一种尝试。 Oracle 不再提供 JRE,从 java9 开始就不再有意了)。无论如何,新模型与几乎所有严肃的 Java 桌面应用程序已经在做的事情相匹配:(应用程序的制造商)分发了一个可以运行您的应用程序的 JVM,而不是 Oracle。这样,您就不必向您的用户解释从哪里下载 JRE(您的安装程序会这样做),并且您确切地知道您要发送给他们的 JRE 版本,而不是祈祷他们拥有的任何东西都可以运行您的东西。

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

简单的方法?嗯,坚持你目前的分销模式。不妨告诉他们如何启动终端并从那里运行 java - 您已经要求他们从 AdoptOpenJDK 安装,并或多或少地迫使他们注意保持最新状态:您已经将您的最终用户视为知道如何管理自己的系统和安装复杂软件的高级用户。不妨加倍努力,告诉他们有关 Terminal.app 的信息。

,

我遇到了同样的问题 - 几年前我写了一个 java-for-all-desktops jar 应用程序,它在所有 java 版本和所有 Mac OS 和 Windows 上运行良好,直到我将 jar 文件放在 Big Sur (OSX 11.2),此时它无法从/向常规文件系统读取或写入。就其本身而言,它默认只读取和写入 /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 中时,右键单击它并单击在 Finder 中打开。这将打开包含 java 可执行文件的文件夹。然后您可以用鼠标选择它们并将它们直接拖到 Full Disk Access 列表中。我一直在尝试这样做,但是通过双击罐子来使罐子正常工作既不充分也没有必要。享受!

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...