我想创建一个应用程序,用户不知道附近设备的发现(如iphone,ipad和appletv等),并选择唯一的appleTv,如果在附近可用,则自动连接并启动镜像。为此我读了 AirPlay :
使用AirPlay,用户可以从iTunes或iTunes重定向音频和视频 基于iOS的设备可以是Apple TV(从那里到家庭) 剧院系统)或支持AirPlay的音响系统。 AirPlay可以 流媒体从互联网上传来,媒体已存储在其中 iTunes,或存储在基于iOS的设备上的媒体。 AirPlay可以流式传输 在iOS应用程序中,在Safari中播放基于Internet的媒体 基于iOS的设备上的浏览器,或任何平台上的iTunes
但我不需要airplay按钮,我想以编程方式发现设备并仅在启动镜像后与appleTv连接。
我阅读了许多博客并搜索了很多内容,但没有找到任何有用的内容。 http://spin.atomicobject.com/2012/04/23/ios-mirroring-and-programmatic-airplay-selection/给出了一些解释,但它出现了。
请给我一些建议,如何以一种伟大的方式实现这种东西。
答案 0 :(得分:6)
对不起,这是一个非常优秀的duperdy迟到你可能已经实现了别的东西,但在 DAYS 的研究和反复试验之后,我终于得到了一些工作。
许多开发人员在他们的应用程序中拥有非常高级的UI,并使用大量自定义弹出窗口和控制器,为他们的应用程序提供非常独特的外观,然后必须使用库存AirPlay控制器UI,使用户完全脱离应用体验,可以是一个完整的眼睛。
其他人想要更好的用户体验;即。他们希望将两者结合起来,以便将人们的当前媒体流分开(一个用于AirPlay,一个用于其他所有媒体),而不是必须将菜单分开,以便用户拥有非常棒的体验。
不幸的是,使用今天提供的公共API,你真的无能为力。 Spotify试图让它在他们的应用程序中工作,虽然比大多数方法更好,但仍然有很多不足之处。
但是,如果由于某种原因,您不想在应用程序商店中发布您的应用程序,那么您有一个很好的代码混淆器可以隐藏来自Apple的函数调用(极不可能),或者您希望将应用程序分发到另一个商店(Cydia等)有一个选项:私人API。
很多人在听到这两个词时都会回避,但是一旦你习惯了这种格式,它就会像普通的Cocoa编程一样减去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中执行选择器 SUCKS 。
因此,我们将基本上创建一个我们稍后需要使用的类的本地表示。
@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
现在我们已经完全初始化了对象,我们可以做很酷的事情。所以我们首先需要做的是启动守护进程来搜索airplay设备。
audioDeviceController.setRouteDiscoveryEnabled!(true)
此步骤是可选的,但建议使用。我们可以为自己分配MPAVRoutingController的委托,并在设备变为活动状态时获得委托调用,而不是更新您的UI以查找可能存在或不存在的更改。
routingController.setDelegate!(self)
然后我们实现该功能。
func routingControllerAvailableRoutesDidChange(controller: MPAVRoutingControllerProtocol) {
}
然后在这个函数中我们可以填充UI的数据源。
routingController.fetchAvailableRoutesWithCompletionHandler! { (routes) in
}
首先,我们调用routingController
的方法将返回一个MPAVRoute对象数组,我们可以提取有关的信息。您需要的所有信息都在MPAVRouteProtcol中,但如果您需要更多信息,可以致电audioDeviceController.routeDescriptionAtIndex!(an Index)
。这将返回详细信息,例如airplay设备的类型,mac地址,是否支持视频等等。
然后,当您需要选择路线时,您可以拨打routingController.pickRoute!(selectedRoute)
。您无需担心密码,iOS会自动为您处理(错误,缓存警报控制器等)。