原文:http://livevision.us/wordpress/2011/02/16/airplay-without-private-api/
如果不是 Erica Sadun 的努力以及 AirPlayer、AirFlick、AirPDF以及 AirSay 这样类似的工具的出现,我可能不会兴起尝试一把的念头。在这篇文章中,我将演示创建一个 iOS app( camThis)将图片发送到Apple TV,既不需要使用任何私有 API,也不需要越狱。我没有提交到苹果商店,但如果有任何新的消息我将随时奉上。
更新:camThis 目前已被苹果接受。
所需工具:
- AirPlayer (Erica Sadun 编写)
译者注:这个链接中 AirPlayer的下载链接已经被删除,读者可以在此处下载: http://download.cnet.com/AirPlayer/3001-13632_4-75330532.html?spi=cc4808989275f217e583547fa2bef669
- Bonjour Browser
- Packet Peeper
- ASIHTTPRequest Framework
- iOS Test app
运行 AirPlayer:
- 在本文中,我们将采取一点类似于欺骗的技巧,以便对 Apple TV 的网络通信进行嗅探...下载并运行 AirPlayer。
译者注:AirPlayer 已经不可用,请用其他类似软件代替。
- AirPlayer 通过广播 _ariplay._tcp 消息并被 bonjour 发现,以此来伪装成 Apple TV,因此你的 Mac 可以被看成一台 Apple TV 。
- 当 AirPlayer 运行时,处于同一网络中的 iOS 设备可以向 AirPlayer 推送图片。
运行 Bonjour Browser: (download)
- Bonjour Browser 是一个杰出的 Mac 应用程序,它能够发现网络中的所有bonjour 设备。
- 我们只是用 Bonjour Browser 找出 Apple TV(AirPlayer) 的IP地址而已,因此我不会告诉你如何编写一个 iOS bonjour 应用程序。
一旦获得 IP 地址,请将地址+端口记下来(在下图中,我用Mac 模拟出的AppleTV的IP地址和端口是 192.168.1.102:7000)。
BonjourBrowser
用Packet Peeper嗅探iOS Airplay 设备发出的网络包:
- Packet Peeper 是一个用于嗅探 Mac 上发出/接收到的网络包的开源工具
- 它支持 tcpdump 过滤器。我们将使用它来过滤网络包,以便我们将注意力集中到 Apple TV的网络包。
- 当你开始一个回话后,你可以设置一个类似于 “tcp port 7000”之类的过滤器
选择一张AirPlayer的图片:
- 如果一切顺利,你会在照片应用程序的右上角看到一个 airplay的标记。
按下 airplay 按钮。可以观察到Packet Peeper中的监控到大量网络包。
- 一旦监控到网络包,你可以选中会话中的所有网络包,然后选择 “View 菜单->View TCP Stream” ,结果类似下图所示。
PacketPeeper results
- 看到左边的会话吗?那是最开始从设备发向AppleTV的请求,请求交换客户端/服务器关系。这就是大家所知的ReverseHTTP——没错,实际上它已经列入了 RFC 草案 。
- 为了让我的 iPhone app能够初始化并处理ReverseHTTP,我头疼了数个小时——但你没有必要关心它,你只需关心诸如 /server-info,/photo之类的即可。
示例代码:
- ok, 现在你已经具备了所有条件,可以发送一张图片到AppleTV了。
- 假设使用ASIHTTPRequest框架。如果你不熟悉它,请参考 这里。
- 这是代码 (简单,不是吗?)
- (void) sendUIImage {
UIImage *img = [UIImageimageNamed:@"test.png"];
NSData *data = UIImageJPEGRepresentation(img,1.0);
NSMutableData *mdata = [[[NSMutableData alloc]initWithData:data] autorelease];
NSLog(@"PUT photo...");
NSURL *url = [NSURLURLWithString:@"http://192.168.2.32:7000/photo"];
request = [ASIHTTPRequest requestWithURL:url];
[request setRequestMethod:@"PUT"];
[requestaddRequestHeader:@"User-Agent" value:@"MediaControl/1.0"];
[request setPostBody:mdata];
[requestsetShouldAttemptPersistentConnection:YES];
[request startSynchronous];
NSError *error = [request error];
if (!error) {
NSLog(@"success");
} else {
NSLog(@"%@",[errorlocalizedDescription]);
}
}