Как программно обнаружить список устройств iOS и подключиться для зеркалирования с помощью трансляции?

Я хочу создать приложение, в котором пользователь не знал об обнаружении ближайших устройств (например, iphone, ipad, appletv и т. Д.), И выбрать единственный appleTv, если он доступен поблизости, затем подключиться атомарно и запустить зеркало. Для этого я прочитал AirPlay:

Используя AirPlay, пользователи перенаправляют аудио и видео из iTunes или устройства на базе iOS либо на Apple TV (а оттуда в систему домашнего кинотеатра), либо на звуковую систему с поддержкой AirPlay. AirPlay может транслировать медиафайлы, поступающие в прямом эфире из Интернета, медиафайлы, уже хранящиеся в iTunes, или медиафайлы, хранящиеся на устройстве на базе iOS. AirPlay может транслировать интернет-мультимедиа при воспроизведении в приложениях iOS, в браузере Safari на устройствах на базе iOS или в iTunes на любой платформе.

но мне не нужна кнопка трансляции, я хочу программно обнаружить устройство и подключиться только к appleTv, после чего начать зеркалирование.

Я читал много блогов и много гуглил, но не нашел ничего полезного. http://spin.atomicobject.com/2012/04/23/ios-mirroring-and-programmatic-airplay-selection/ дает некоторое объяснение, но оно похоже.

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


person Tom Sawyer    schedule 06.12.2015    source источник
comment
К счастью, это невозможно без действий пользователя. Большинство людей, что активно включать / отключать Airplay. Они не хотят, чтобы приложения запускали Airplay сами. Вот почему Apple не допускает подобных вещей.   -  person dasdom    schedule 06.12.2015
comment
@dasdom: Спасибо за ответ.   -  person Tom Sawyer    schedule 06.12.2015


Ответы (1)


Извините, это слишком поздно, и вы, вероятно, уже реализовали что-то еще, но после ДНЕЙ исследований и проб и ошибок у меня наконец-то есть над чем поработать.

Многие разработчики имеют действительно продвинутый пользовательский интерфейс в своих приложениях и используют множество настраиваемых всплывающих окон и контроллеров, которые обеспечивают уникальный вид их приложений, а затем вынуждены использовать стандартный пользовательский интерфейс контроллера AirPlay, который полностью выводит пользователя из работы с приложениями и может быть полным бельмом на глазу.

Другие хотят лучшего UX; т.е. Вместо того, чтобы разделять меню, в которые люди могут передавать свои текущие медиафайлы (одно для AirPlay и одно для всего остального), они хотят объединить два меню, чтобы у пользователя был действительно отличный опыт.

К сожалению, используя доступный сегодня общедоступный API, вы действительно ничего не можете сделать. Spotify пытается заставить его работать в своем приложении, и, хотя он лучше большинства подходов, все же оставляет желать лучшего. введите здесь описание изображения  введите описание изображения здесь

Однако, если по какой-то причине вы не хотите выпускать свое приложение в магазине приложений, у вас есть хороший обфускатор кода, который может скрыть ваши вызовы функций из Apple (что очень маловероятно), или вы хотите распространить свое приложение в другом магазине (Cydia и т. д.) для вас есть вариант: частные API.

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

Хватит болтать и просто ДАЖИ ДЕ КОДЕЗ

Я не собираюсь знакомить вас с взаимодействием с частными API; вы можете прочитать другие статьи, в которых будет гораздо глубже, чем я когда-либо хотел бы. Без лишних слов, это то, что я придумал.

Шаг 1. Прочтите файлы заголовков с обратной инженерией, которые другие более умные люди разместили на github (https://github.com/nst/iOS-Runtime-Headers/blob/master/Frameworks/). Действительно стоит прочитать все файлы заголовков, потому что некоторые вещи, которые вы можете делать, действительно интересны.

Шаг 2: Приступите к делу. Теперь я буду делать это в Swift, но я предоставлю ссылки на Objective-C ниже. Я бы порекомендовал сделать это в Objective-C, потому что большинство этих классов написано на Objective-C, а многие методы начинаются с "_" быстрых ошибок для iVars, и это становится действительно беспорядочным. Но если нужно, вот как бы вы это сделали.

Таким образом, вместо обычного способа [class performSelector:methodName] для методов и [instance valueForKey:_iVar] для доступа к переменным экземпляра гораздо проще использовать протоколы в Swift; в основном потому, что выполняем селектор ОТСАСЫВАЕТ в Swift.

Итак, мы собираемся создать локальное представление классов, которые нам позже понадобятся.

@objc protocol MPAVRoutingControllerProtocol {
    optional func fetchAvailableRoutesWithCompletionHandler(completion: (routes: [MPAVRouteProtocol]) -> Void)
    optional func pickRoute(route: MPAVRouteProtocol) -> Bool
    optional func setDelegate(delegate: NSObject)
}

@objc protocol MPAVRouteProtocol {
    optional func routeName() -> String
    optional func routeUID() -> String
    optional func isPicked() -> Bool
    optional func wirelessDisplayRoute() -> MPAVRouteProtocol
}

@objc protocol MPAudioDeviceControllerProtocol {
    optional func setRouteDiscoveryEnabled(enabled: Bool)
    optional func routeDescriptionAtIndex(index: Int) -> [String: AnyObject]
}

extension NSObject : MPAVRoutingControllerProtocol, MPAVRouteProtocol, MPAudioDeviceControllerProtocol {

}

Вот где действительно происходит волшебство. Где-то в вашем контроллере представления мы создаем классы, используя NSClassFromString()

let MPAudioDeviceControllerClass: NSObject.Type =  NSClassFromString("MPAudioDeviceController") as! NSObject.Type
let MPAVRoutingControllerClass: NSObject.Type = NSClassFromString("MPAVRoutingController") as! NSObject.Type

Затем мы создаем объекты из этих классов и взаимодействуем с ними, вызывая функции нашего протокола.

let routingController = MPAVRoutingControllerClass.init() as MPAVRoutingControllerProtocol
let audioDeviceController = MPAudioDeviceControllerClass.init() as MPAudioDeviceControllerProtocol

Теперь, когда у нас есть полностью инициализированные объекты, мы можем делать самые интересные вещи. Итак, первое, что нам нужно сделать, это запустить демон для поиска устройств трансляции.

audioDeviceController.setRouteDiscoveryEnabled!(true)

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

routingController.setDelegate!(self)

Затем мы реализуем функцию.

func routingControllerAvailableRoutesDidChange(controller: MPAVRoutingControllerProtocol) {
}

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

routingController.fetchAvailableRoutesWithCompletionHandler! { (routes) in

}

Итак, начнем с того, что этот метод, который мы вызываем, routingController вернет нам массив объектов MPAVRoute, о которых мы можем извлечь информацию. Вся необходимая информация находится в MPAVRouteProtcol, но если вам понадобится больше, вы можете позвонить audioDeviceController.routeDescriptionAtIndex!(an Index). Это вернет подробную информацию, такую ​​как тип устройства трансляции, MAC-адрес, поддерживает ли оно видео и многое другое.

Затем, когда вам нужно выбрать маршрут, вы должны позвонить routingController.pickRoute!(selectedRoute). Вам не нужно беспокоиться о паролях, iOS позаботится об этом автоматически (ошибки, кеширование контроллеров предупреждений и т. Д.).

person Mark Bourke    schedule 04.07.2016
comment
То, как это делает Spotify, нет, в остальном - определенно. Даже не уверен, насколько хорошо работает этот код. - person Mark Bourke; 14.06.2017
comment
@MarkBourke Привет! Извините, если я беспокоюсь об этом. Не могли бы вы также помочь нам с кодом цели c? Я много пытался определить, зеркалирует ли устройство, и не могу найти на это ответа ... Не могли бы вы мне помочь? Заранее большое спасибо! - person Razvan N; 20.06.2017
comment
Понятия не имею, как это работает в iOS 9/10/11. Поведение могло измениться, и я не очень заинтересован в том, чтобы обновлять его, потому что очень сложно использовать недокументированный класс. Вы можете следовать этой статье, если продолжите: justinyangjing.github.io/2016/07/ 16 / AirPlay, но я бы порекомендовал сделать что-то похожее на то, что делает Spotify. - person Mark Bourke; 21.06.2017