应用程序不要求在 MacOS 10.14 Mojave 中访问麦克风的权限

Rol*_*and 6 privacy microphone portaudio macos-mojave

我是开发飞行模拟应用程序的团队的一员。其中一个应用程序也在 MacOS 上运行,需要访问麦克风才能与在线虚拟空中交通管制进行通信。从 MacOS 10.14 开始,麦克风访问不再有效。它曾经在任何以前版本的 MacOS 中都能完美运行。我读过从 10.14 开始,MacOS 会要求用户授予权限,但此对话框从未出现。使用portaudio作为音频库,成功打开音频输入流。没有警告,没有错误,没有任何指向问题的东西。它只是不返回任何音频输入。

我了解到许多其他项目——甚至是商业项目——也有类似的问题。但我不知道他们最终是如何解决这个问题的。我知道应用程序包需要在 Info.plist 中添加一个特定的键

<key>NSMicrophoneUsageDescription</key>
<string>This application needs access to your Microphone virtual ATC.</string>
Run Code Online (Sandbox Code Playgroud)

但这没有帮助。其他人建议添加<key>CFBundleDisplayName</key>解决问题。但它没有。

也许值得注意的是,该应用程序未签名。这是一个业余爱好项目,我不愿意每年为 Apple 的代码签名过程花费 99 美元。这可能是罪魁祸首吗?

欢迎任何建议或想法。

作为临时解决方法,我们告诉用户通过控制台从应用程序包启动二进制文件,从而解决了问题。但我也想为应用程序包本身正确修复它。

Atu*_*tul 0

从 10.14 开始,MacOS 会请求用户许可,但此对话框永远不会出现

这正是我的问题。Mac Mojave 和 Catalina 中存在这个严重的错误。

就我而言,我的客户在 Catalina 上遇到了这个问题。我通过 JNLP 启动 JAR。由于最新版本的 MacOS 中与安全相关的更改,应用程序应该获得访问麦克风、屏幕录制、全磁盘访问等的权限。对于 Java 应用程序(通过 JNLP 运行),理想情况下应该是 Java 来寻求权限。然而,这并没有发生。我的用户没有看到请求麦克风许可的对话框。他们甚至尝试使用最新的 Java 版本 8。仍然没有成功。我挣扎了很多很多天。最后这对我有用:

我检测操作系统是否为 MacOS Cataline,如果是,我只需使用 javaws 再次启动相同的 JNLP。为了避免递归,我仅在检测到小程序第一次运行时才执行此操作。这是代码:

这是完整的代码:

private boolean IsAlreadyRunning()
{
    System.out.println("Checking if applet already running by opening applet locked file");
    try
    {
        file_locked_by_applet=new File("my_java_application.lock");
        // createNewFile atomically creates a new, empty file ... if and only if a file with this name does not yet exist. 

        System.out.println("Locked file path: " + file_locked_by_applet.getAbsolutePath());

        if (file_locked_by_applet.createNewFile())
        {
            System.out.println("Opened applet locked file successfully");
            file_locked_by_applet.deleteOnExit();
            return false;
        }

        System.out.println("Cannot open applet locked file. Applet might be already running.");
        return true;
    }
    catch (IOException e)
    {
        System.out.println("Exception while opening applet locked file. Applet might be already running.");
        e.printStackTrace();
        return true;
    }
}

private boolean IsOSMacCatalina()
{
    System.out.println("Checking if current operating system is MacOS Catalina");
    String OS = System.getProperty("os.name").toLowerCase();
    String OSVersion = System.getProperty("os.version").toLowerCase();      
    String OSArch = System.getProperty("os.arch").toLowerCase();

    System.out.println("OS detected: " + OS);
    System.out.println("OS version detected: " + OSVersion);
    System.out.println("OS arch detected: " + OSArch);

    if (OS.contains ("mac os") && OSVersion.contains("10.15"))
    {   
            System.out.println("Operating system: Mac Catalina detected");
            return true;
    }

    System.out.println("Operating system is not Mac Catalina");
    return false;

}

// Method that first gets invoked by applet at the beginning
public void start() 
{
    super.start();
    System.out.println("Starting applet here");
    System.out.println("JNLP file name: " + System.getProperty("jnlpx.origFilenameArg"));
    System.out.println("JVM command line: " + ManagementFactory.getRuntimeMXBean().getInputArguments());

if ((!IsOSMacCatalina()) || IsAlreadyRunning())
{
    System.out.println("Either OS is not Catalina or applet is already launched with bash and javaws. Continuing with applet...");
}
else
{
    try
    {
        System.out.println("Applet running first time on Mac Catalina. Starting again with bash and javaws");

        // "javaws -wait" causes javaws to start java process and wait for it to exit
        String javawsCommandLine = "javaws -wait \"" + System.getProperty("jnlpx.origFilenameArg").replace("\\","/") + "\"";
        System.out.println("bash javaws command line to run: " + javawsCommandLine);
        // String[] args = new String[] {"bash", "-c", javawsCommandLine}; // Works on Windows where Bash is installed
        String[] args = new String[] {"/bin/bash", "-c", javawsCommandLine};
        System.out.println("---\nStarting bash javaws process withh args:");
        for (String arg: args)
            System.out.println(arg);
        System.out.println("\n---");

        // Runtime.getRuntime() discouraged. Hence we using ProcessBuilder
        // Process proc = Runtime.getRuntime().exec("bash -c \"" + javawsCommandLine + "\"");

        Process proc = new ProcessBuilder(args).start();

        System.out.println("Waiting for bash process to finish");
        proc.waitFor();
        System.out.println("Bash process finished. Deleting instance locked file");
        file_locked_by_applet.delete();
        System.out.println("Stopping applet here");
    }
    catch (java.io.IOException e) 
    {
        e.printStackTrace();
    }
    catch (java.lang.InterruptedException e)
    {
        e.printStackTrace();
    }
    return;             
}
Run Code Online (Sandbox Code Playgroud)