iOS-使用bonjour完成与智能硬件交互的功能
2016-04-30 本文已影响1764人
茄子星人
虽然很久之前就有转到简书的想法,但在拖延症的影响下一直是处于要命的状态,借着这次离职了终于可以好好写一下自己的工作上的一些事了,毕竟只是一介普通的iOS程序员,基础知识已经有太多人写过了,高深的我也不敢误人子弟,所以,只能将自己工作中遇到的一些冷门经验写出来,做一点微薄的工作,希望大家带着交流的心态来看,不要全信,我有错误的地方请务必指出。
关于bonjour的基础知识百度谷歌要多少有多少,在此便不多做说明,简而言之,你可以通过它发布服务以及检索服务,并在客户端获取服务端的信息。
上一份工作时为了达到与智能硬件交互,完成在给硬件发送手机当前所处的wifi的账号密码的同时将硬件的mac地址及其他数据保存下来这样的功能时使用了bonjour,不得不说,比起之前用的广播手法,bonjour的效率高上不少,至少,修改后就没多少催命电话了。
首先,你得明白,除非你自家智能硬件的wifi模块是由你们自家制造的,否则的话wifi模块的制造厂商需要提供一份框架以让发布服务的功能在他们的框架下完成,所以我的任务大部分就是自写一个检索服务的模块来自动获得我需要的信息。
//如果wifi模块制造商没有提供框架,那我也没办法了| ω・´)
//这块代码是将wifi账号密码保存并发送给智能硬件,大体上建议做封装,不过DEMO就随意啦
if (!self.easylink) {
self.easylink = [[EASYLINK alloc]initWithDelegate:self];
}
NSMutableDictionary *wlanConfig = [NSMutableDictionary dictionaryWithCapacity:20];
NSData *ssidData = [self.tfdSSID.text dataUsingEncoding:NSUTF8StringEncoding];
[wlanConfig setObject:ssidData forKey:KEY_SSID];
[wlanConfig setObject:self.tfdPWD.text forKey:KEY_PASSWORD];
[wlanConfig setObject:[NSNumber numberWithBool:YES] forKey:KEY_DHCP];
[self.easylink prepareEasyLink_withFTC:wlanConfig info:nil mode:EASYLINK_V2_PLUS];
[self.easylink transmitSettings];
好了,我们已经注册了服务,接下来就是进行检索了,需要注意的是,检索服务涉及到一些苹果认为颇为隐私的数据,所以虽然没有像UDID一样被禁止,但也是限制了获取信息的手法,似乎只能通过代理回调的样子。
//定义NSNetService,NSNetServiceBrowser两个变量以及添加代理
@property(strong,nonatomic)NSNetServiceBrowser *brower;
@property(strong,nonatomic)NSNetService *service;
NSNetServiceDelegate,NSNetServiceBrowserDelegate
那么来检索吧
/*
需要注意的是,并不是进行检索就能立即检索出来,发布服务可能会有稍许延迟,所以,如果在检索未能
成功获取到想要的数据时当然是再一次检索,但在此之前,你必须停止上一次的检索,它可不是善解人意的
小宝贝。
*/
[self.brower stop];
/*
如果你的模块商没有告诉你发布的服务名的话那么最好的解决方法是进入手机上的App Store以
bonjour为关键词搜索软件‘Discovery - Bonjour Brower’,然后用它就好了。
*/
[self.brower searchForServicesOfType:@"_easylink._tcp" inDomain:@"local."];
如你所见,苹果只提供了代理让我们来获取信息,不过,总比没有好吧。
//字面意思,当检索到指定名的服务时就会调用的代理方法,如果你如我一样想获得更细致的数据就必须通过它来做下一步动作
-(void)netServiceBrowser:(NSNetServiceBrowser *)browser didFindService:(NSNetService *)service moreComing:(BOOL)moreComing{}
//需要解释么
-(void)netService:(NSNetService *)sender didNotResolve:(NSDictionary<NSString *,NSNumber *> *)errorDict{}
//如果你想要获得更细致的数据,那么,它是你的选择,不过,你得先通过它丈母娘(第一个代理方法)的审视。
-(void)netServiceDidResolveAddress:(NSNetService *)sender{}
-(void)netServiceBrowser:(NSNetServiceBrowser *)browser didFindService:(NSNetService *)service moreComing:(BOOL)moreComing{
//为service设置代理,无法直接在此代理中得到地址,似乎必须通过代理回调
NSString *str = [service.name lowercaseString];
NSRange range = [str rangeOfString:@"#"];
NSString *maccode = [str substringWithRange:NSMakeRange(range.location+3, 4)];
echo(@"%@",maccode);
if ([maccode isEqualToString:[self.tfdCode.text lowercaseString]] ) {
//可能有人问我,为何要这么做,因为杀千刀的苹果同一时间里只给你提供一个宝贝的详细数据,如果你想要对每个service宝贝都添加代理,那你恐怕就得失望了。
self.service = service;
self.service.delegate = self;
//使用它,在下一个代理回调内得到数据
[self.service resolveWithTimeout:1.0]; }
}
来吧,胜利的果实就在眼前.
-(void)netServiceDidResolveAddress:(NSNetService *)sender{
NSData* data = [sender TXTRecordData];
NSDictionary* dict = [NSNetService dictionaryFromTXTRecordData:data];
NSData *str = [dict objectForKey:@"MAC"];
NSString *oldmacadress = [[NSString alloc]initWithData:str encoding:NSUTF8StringEncoding];
//如果你如我一样需要硬件的mac地址,那么切记字典中的数据并不是立马就能用的,必须再做处理。
NSString *macadress = [oldmacadress stringByReplacingOccurrencesOfString:@":" withString:@""];
if (macadress.length < 8) {
return;
}
if (self.timer) {
[self.timer invalidate];
}
_Mac = macadress;
//既然找到了心仪的对象,记得收收心,把该停的都停掉。
[self stopToLink];
}
好了,我得到了mac地址,我的任务完成了,把它保存在本地数据库,等到该用的时候拿出来用就好了。