Apple TV как внешний UIScreen на устройстве iOS

У меня есть приложение, которое отображает видео в подвиде, и было бы неплохо дать возможность отображать это видео на втором экране, таком как Apple TV, и иметь возможность использовать это освобожденное пространство для отображения дополнительных элементов управления.

Я нашел всевозможную помощь о том, как это сделать, но я упираюсь в стену еще до того, как выхожу из стартовых ворот.

Чтобы определить, что приложение запущено в среде с несколькими дисплеями, во всех примерах кода есть строка вроде...

if (UIScreen.Screens.Length > 1) {
    // ...
}

(Я делаю это на С#/Xamarin, хотя сомневаюсь, что проблема связана с этим; во всяком случае, фрагменты кода на С#)

Моя проблема в том, что массив экранов всегда равен 1, что бы я ни делал. iPad работает под управлением iOS 11.2.5, и если я включу зеркальное отображение, iPad будет зеркально отражен, но, опять же, в массиве экранов есть только один элемент.

Также есть пара наблюдателей для обнаружения добавления/удаления экранов во время работы приложения. Я не видел конкретного кода Xamarin, но я предполагаю, что он выглядит так:

NSNotificationCenter.DefaultCenter.AddObserver(this, UIScreen.DidConnectNotification, NSKeyValueObservingOptions.New, IntPtr.Zero);
NSNotificationCenter.DefaultCenter.AddObserver(this, UIScreen.DidDisconnectNotification, NSKeyValueObservingOptions.New, IntPtr.Zero);

Во всяком случае, они никогда не срабатывают, даже если я добавляю/удаляю Apple TV или вхожу/выхожу из режима зеркального отображения на iPad.

Ой; также, если я сделаю

avPlayer.AllowsExternalPlayback = true;
avPlayer.UsesExternalPlaybackWhileExternalScreenIsActive = true;

тогда это тоже работает, как и ожидалось. Теперь видео отображается в полноэкранном режиме на Apple TV, а UIView на iPad, содержащий avPlayer, становится серым, а не показывает видео.

Однако это не то, что я ищу. Я хотел бы контролировать расположение обоих экранов, но это не так. (Хотя я хочу, чтобы видео было полноэкранным на Apple TV, я не хочу, чтобы это был AVPlayerViewController, и я хочу перепрофилировать экранную недвижимость, занимаемую просмотром видео на iPad)

В конце концов, все, что, как я думаю, мне нужно, это суметь получить

UIScreen.Screens.Length должен быть равен 2, когда я запускаю приложение.

В чем секрет того, как заставить UIScreen обнаруживать/сообщать о втором дисплее?


person Gilles Dignard    schedule 06.02.2018    source источник
comment
AirPlay устарел developer.apple.com/documentation/avfoundation/avplayer в пользу внешних дисплеев. Более того, на моем iPad (под управлением iOS 11) зеркалирование — единственная опция, доступная в центре управления.   -  person Gilles Dignard    schedule 07.02.2018


Ответы (1)


Когда приложение запускается с уже включенным зеркалированием экрана, массив UIScreen.screens изначально содержит только экран устройства. Вскоре после запуска iOS публикует уведомление UIScreenDidConnect, чтобы сообщить вашему приложению о подключении второго экрана.

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

Хотя это кажется немного нелогичным, на самом деле ваш код становится немного проще; вам нужно следить за уведомлениями UIScreenDidConnect и UIScreenDidDisconnect в любом случае, и теперь вам не нужно писать какой-либо специальный код для обработки случая, когда приложение запускается с уже прикрепленным вторым экраном.

Вы можете использовать что-то подобное в своем didFinishLaunching:

let nc = NotificationCenter.default

nc.addObserver(forName: NSNotification.Name.UIScreenDidConnect, object: nil, queue: nil) { (notification) in
    print("Screen connected")
    self.enableExternalDisplay()
}

nc.addObserver(forName: NSNotification.Name.UIScreenDidDisconnect, object: nil, queue: nil) { (notification) in
    print("Screen disconnected")
    self.disableExternalDisplay()
}

ОБНОВЛЕНИЕ

На самом деле, похоже, что в вашем коде есть формат наблюдения за ключом/значением AddObserver, когда вы действительно хотите наблюдать за уведомлениями. Что-то типа:

NSNotificationCenter.DefaultCenter.AddObserver(UIScreen.DidConnectNotification,OnScreenConnected)

Затем вам нужно реализовать метод OnScreenConnected.

person Paulw11    schedule 06.02.2018
comment
Никаких извинений за код Swift не требуется. Понимание того, что UIScreens имеет только один ожидаемый элемент при запуске, полезно; это позволяет мне сосредоточиться на том, почему я не вижу уведомление. Поскольку NSNotification.Name.UIScreenDidConnect предположительно является константой, не могли бы вы опубликовать основную строку? В остальном код C# и Swift кажется идентичным, поэтому строка, которую я передаю, кажется кандидатом на то, что может быть основной проблемой. - person Gilles Dignard; 07.02.2018
comment
Это UIScreenDidConnectNotification, хотя в Swift вы используете значения перечисления NSNotification.Name. Эта строка является необработанным значением перечисления. - person Paulw11; 07.02.2018
comment
Похоже, вы используете неправильный формат для AddObserver - формат, который вы используете, предназначен для наблюдения за ключом/значением. Вам нужен этот формат - person Paulw11; 07.02.2018