Приложение не запрашивает разрешение на доступ к микрофону в MacOS 10.14 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>

но это не помогло. Другие предположили, что добавление <key>CFBundleDisplayName</key> решит проблему. Но этого не произошло.

Возможно, стоит отметить, что заявка не подписана. Это хобби-проект в свободное время, на который я не хочу тратить 99 долларов в год на процесс подписания кода Apple. Может ли это быть виноватым?

Любые советы или идеи приветствуются.

В качестве временного решения мы сказали пользователям запускать двоичный файл из пакета приложений через консоль, что устраняет проблему. Но я бы хотел исправить это и для самого пакета приложений.


person Roland    schedule 17.04.2019    source источник
comment
Когда-нибудь находили решение?   -  person spartygw    schedule 08.08.2019
comment
Это помогает? reddit.com/r/MacOS/comments/9lwyz0/   -  person Dave Nottage    schedule 21.10.2019
comment
Это действительно похоже на проблему из-за того, что ваш код не подписан.   -  person dparakh    schedule 30.10.2019
comment
Привет, ты нашел решение? Я сильно застрял на той же проблеме. У меня две системы Mac OS Catalina. Java не запрашивает разрешения в обеих системах. Однако в одной системе я могу получить доступ к микрофону и записывать, в то время как в другой он не может обнаруживать звук в микрофоне. Пожалуйста, поделитесь, если у вас есть решение.   -  person Atul    schedule 31.01.2020


Ответы (3)


Для меня сработало решение сбросить PRAM. Там хранятся некоторые системные настройки.

Во время загрузки нажмите и удерживайте Command + Option + P + R. Компьютер перезагрузится, и когда вы второй раз услышите звук запуска, отпустите его.

Снова запустите приложение, и должно появиться диалоговое окно с разрешением.

person samwize    schedule 03.02.2020

начиная с 10.14 MacOS запрашивает разрешение у пользователя, но это диалоговое окно никогда не появляется

Это была моя проблема. Эта серьезная ошибка есть в Mac Mojave и Catalina.

В моем случае мои клиенты столкнулись с этой проблемой на Catalina. Запускаю JAR через JNLP. Из-за изменений, связанных с безопасностью, в последних версиях MacOS приложения должны получать разрешения на доступ к микрофону, записи экрана, полному доступу к диску и т. Д. В случае приложений Java (работающих через JNLP) в идеале разрешение запрашивать у Java. Однако этого не происходит. Мои пользователи не видели диалоговое окно с запросом разрешения микрофона. Они пробовали даже с последней версией Java 8. Все равно не повезло. Я боролся много-много дней. Наконец, вот что сработало для меня:

Я определяю, является ли ОС MacOS Cataline, и если да, я просто снова запускаю тот же 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;             
}
person Atul    schedule 12.03.2020

В итоге я использовал следующие два фрагмента. Первый активно спрашивает, есть ли у приложения авторизованный доступ. Если это не может быть определено (поскольку пользователя никогда не спрашивали), вызывается requestAccess() для активного запроса пользователя и асинхронной обработки ответа. Обе функции обрабатывают случай, когда целевой MacOS <10,14, и в этом случае предполагается, что авторизация истинна.

CMacOSMicrophoneAccess::AuthorizationStatus CMacOSMicrophoneAccess::getAuthorizationStatus()
{
    if (@available(macOS 10.14, *))
    {
        NSString *mediaType = AVMediaTypeAudio;
        AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:mediaType];
        if (authStatus == AVAuthorizationStatusAuthorized)
        {
            return AuthorizationStatus::Authorized;
        }
        else if (authStatus == AVAuthorizationStatusNotDetermined)
        {
            return AuthorizationStatus::NotDetermined;
        }
        return AuthorizationStatus::Denied;
    }
    else
    {
        return AuthorizationStatus::Authorized;
    }
}

void CMacOSMicrophoneAccess::requestAccess()
{
    if (@available(macOS 10.14, *))
    {
        NSString *mediaType = AVMediaTypeAudio;
        [AVCaptureDevice requestAccessForMediaType:mediaType completionHandler: ^ (BOOL granted)
        {
            emit permissionRequestAnswered(granted);
        }];
    }
    else
    {
        emit permissionRequestAnswered(true);
    }

}
person Roland    schedule 18.06.2020
comment
Куда вы положили эти функции? - person Ashwin Nirmale; 28.08.2020