События удаленного управления iOS Media Player (MPRemoteCommand) не работают с Unity

Недавно я обнаружил, что обработчики событий удаленного управления MediaPlayer (MPRemoteCommand) не вызываются в iOS-приложении со встроенным проигрывателем Unity. Я использую Xcode 6.3.1 и Unity 5.0.1f1, однако похоже, что его можно воспроизвести с любой комбинацией доступных в настоящее время версий.

Это официальная документация Apple по обработке событий удаленного управления в iOS: https://developer.apple.com/library/ios/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/Remote-ControlEvents/Remote-ControlEvents.html.

Проблему очень легко воспроизвести — это всего лишь 24 строки кода, добавленные в пустой проект.

  1. Создайте новое приложение Single View в Xcode (чтобы сделать рабочий пример без проигрывателя Unity) или создайте пустой проект в Unity и сразу же соберите его для платформы iOS (Файл -> Настройки сборки..., iOS, Сборка) со всеми настройками, оставленными с их значения по умолчанию, чтобы получить проект Xcode, сгенерированный Unity (чтобы сделать сломанный пример со встроенным проигрывателем Unity).

  2. Импортируйте заголовочный файл платформы MediaPlayer в AppDelegate.h (например, без Unity) или UnityAppController.h (например, с Unity):

    #import <MediaPlayer/MediaPlayer.h>
    
  3. Объявите свойство для объекта MPMoviePlayerController в интерфейсе класса, расположенном в AppDelegate.h/UnityAppController.h:

    @property (strong, nonatomic) MPMoviePlayerController *player;
    
  4. Вставьте этот код, который создает проигрыватель с URL-адресом (это прямая радиостанция, вы можете использовать любой другой источник живого звука HTTP, который вы хотите), регистрирует обработчики событий удаленного управления play, pause и togglePlayPause и запускает воспроизведение звука ( таким образом, делая приложение приложением «Сейчас исполняется») в начале метода application:didFinishLaunchingWithOptions:, расположенного в AppDelegate.m/UnityAppController.mm (вы также можете добавить его непосредственно перед оператором возврата этого метода — это не имеет значения):

    self.player = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL URLWithString:@"http://81.9.96.34/eldoradio-64k"]];
    
    [[MPRemoteCommandCenter sharedCommandCenter].playCommand addTarget:self action:@selector(playCommand)];
    [[MPRemoteCommandCenter sharedCommandCenter].pauseCommand addTarget:self action:@selector(pauseCommand)];
    [[MPRemoteCommandCenter sharedCommandCenter].togglePlayPauseCommand addTarget:self action:@selector(togglePlayPauseCommand)];
    
    [self.player play];
    
  5. Добавьте реализацию обработчиков в AppDelegate.m/UnityAppController.mm:

    - (void)playCommand {
        [self.player play];
    }
    
    - (void)pauseCommand {
        [self.player pause];
    }
    
    - (void)togglePlayPauseCommand {
        if (self.player.playbackState == MPMoviePlaybackStatePlaying) {
            [self.player pause];
        } else {
            [self.player play];
        }
    }
    
  6. Соберите и запустите приложение. Вы должны услышать музыку, играющую после ее запуска.

  7. Инициировать некоторые события удаленного управления. Самый простой способ — подключить стандартный Apple EarPods и нажмите кнопку воспроизведения-паузы на них, что должно сгенерировать событие togglePlayPause, но открытие Центра управления iOS (пользовательский интерфейс, который вы получаете, проводя пальцем по экрану снизу) и нажатие кнопки воспроизведения/паузы также допустимо. (они должны генерировать отдельные события воспроизведения и паузы соответственно).

В приложении без Unity звук останавливается и начинает воспроизводиться в соответствии с отправленными событиями удаленного управления. В приложении с Unity обработчики никогда не вызываются (в них можно поставить точки останова и увидеть это под отладчиком) и вообще ничего не происходит. Вы также можете заметить, что внешний вид Центра управления iOS совершенно другой: в приложении со встроенным проигрывателем Unity у него есть кнопки воспроизведения и две кнопки перемотки независимо от состояния звука, а в приложении без Unity отображается только кнопка паузы при воспроизведении звука или просто кнопку воспроизведения, когда он не играет.

Также можно заменить MPMoviePlayerController на AVPlayer из фреймворка AVFoundation — результат будет точно таким же.

Кто-нибудь знает причину такого поведения и/или обходной путь? Это очень плохо влияет на наше приложение.

PS: я уже задавал подобный вопрос раньше, но не получил любые ответы. Пример в этом максимально прост.


person Fedor Chunovkin    schedule 04.05.2015    source источник
comment
Федор, ты когда-нибудь это решал? У меня такая же проблема. Джим   -  person Jim    schedule 18.10.2015


Ответы (1)


У моего приложения почти такие же настройки, как у вас, и та же проблема. Пока я использовал микшируемый аудио сеанс

    try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord, withOptions: [.DuckOthers, .InterruptSpokenAudioAndMixWithOthers])

мое приложение не запускало ни один из обработчиков MPRemoteCommand.

Когда я превратил свою аудиосессию в несовместимую (путем удаления опций)

    try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayAndRecord)

мои обработчики MPRemoteCommand вызывались всякий раз, когда я нажимал кнопку воспроизведения/паузы на гарнитуре.

Итак, решение состоит в том, чтобы использовать не микшируемый аудио сеанс, который PlayAndRecord не имеет явных параметров микширования, вместо микшируемого аудио сеанса.

person Burkhard    schedule 06.11.2015