iOS mdns之Bonjour 客户端基本使用及完美解决各种坑~

对Bonjour完全小白的同学,推荐一篇文章
iOS开发 Bonjour的使用,在此也感谢此篇的作者,毕竟站在巨人的肩膀上做事情,事半功倍!

假如你看完了上面的文章, 对Bonjour已经有了一个基本的认识,那我们这里就直接进入主题,如果在实战中使用. 想法也是封装出一个工具类,方便使用,当然要达到如下效果

1.最好是单例
2.最好使用简单,方便使用
3.能发现所有的设备及返回所有设备的相关信息(看了很多文章都没有处理这一步,大多只是发现一台设备,没有对多台设备进行处理,也没有返回给外面使用)

回到正题

直接新建一个类,类名叫FindDeviceServiceTool 继承自NSObject,FindDeviceServiceTool.h文件如下:

#import 
typedef  void(^ResultBlock)(NSArray * _Nullable resultArray);
NS_ASSUME_NONNULL_BEGIN

@interface FindDeviceServiceTool : NSObject

+(FindDeviceServiceTool *) sharedInstance;
@property (nonatomic,copy) ResultBlock resultBlock;
-(void)createServiceBrowser;
@end

NS_ASSUME_NONNULL_END

FindDeviceServiceTool.m文件如下:

//
//  FindDeviceServiceTool.m
//  Bonjour_OC_demo
//
//  Created by zz on 2021/9/10.
//

#import "FindDeviceServiceTool.h"
#include 


@interface FindDeviceServiceTool ()

//定义NSNetService,NSNetServiceBrowser两个变量以及添加代理
@property(strong,nonatomic)NSNetServiceBrowser *brower;

//是为了保存服务,不让其立马销毁,这样后面的代理方法才能起到作用
@property(strong,nonatomic)NSMutableArray *serviceArray;

//结果数组,供外界使用
@property(strong,nonatomic)NSMutableArray *resultArray;


@end

@implementation FindDeviceServiceTool

- (NSMutableArray *)serviceArray{
    
    if (_serviceArray == nil) {
        _serviceArray = [[NSMutableArray alloc]init];
    }
    return _serviceArray;
}

- (NSMutableArray *)resultArray{
    
    if (_resultArray == nil) {
        _resultArray = [[NSMutableArray alloc]init];
    }
    return _resultArray;
}

/**
 单利模式
 */
+(FindDeviceServiceTool *) sharedInstance
{
    static FindDeviceServiceTool *sharedInstace = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstace = [[self alloc] init];
    });
    return sharedInstace;
}

- (void)createServiceBrowser{
    [self.serviceArray removeAllObjects];
    [self.resultArray removeAllObjects];
    self.brower = [[NSNetServiceBrowser alloc]init];
    self.brower.delegate = self;
    [self.brower scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
    [self.brower searchForServicesOfType:@"_x5_gw._tcp" inDomain:@"local."];
}

#pragma mark - NSNetServiceBrowserDelegate

/*
 * 即将查找服务
 */
- (void)netServiceBrowserWillSearch:(NSNetServiceBrowser *)browser {
    NSLog(@"-----------------netServiceBrowserWillSearch");
}

/*
 * 停止查找服务
 */
- (void)netServiceBrowserDidStopSearch:(NSNetServiceBrowser *)browser {
    NSLog(@"-----------------netServiceBrowserDidStopSearch");
}

/*
 * 查找服务失败
 */
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser didNotSearch:(NSDictionary *)errorDict {
    NSLog(@"----------------netServiceBrowser didNotSearch");
    
}

/*
 * 发现域名服务
 */
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser didFindDomain:(NSString *)domainString moreComing:(BOOL)moreComing {
    NSLog(@"---------------netServiceBrowser didFindDomain");
}

/*
 * 发现客户端服务
 */
- (void)netServiceBrowser:(NSNetServiceBrowser *)browser didFindService:(NSNetService *)service moreComing:(BOOL)moreComing {
    
    NSLog(@"didFindService---------\nname=%@\ndomain=%@\ntype=%@",service.name,service.domain,service.type);
    if(self.serviceArray.count == 0 ) {
        [self.serviceArray addObject:service];
    }else{
        BOOL didHadServiceInArray = NO;
        for (NSInteger i=0; isa_family == AF_INET) {
            sPort = ntohs(((struct sockaddr_in *)socketAddr)->sin_port);
            struct sockaddr_in* pV4Addr = (struct sockaddr_in*)socketAddr;
            int ipAddr = pV4Addr->sin_addr.s_addr;
            char str[INET_ADDRSTRLEN];
            ipv4 = [NSString stringWithUTF8String:inet_ntop( AF_INET, &ipAddr, str, INET_ADDRSTRLEN )];
        }
        
        else if(socketAddr->sa_family == AF_INET6) {
            sPort = ntohs(((struct sockaddr_in6 *)socketAddr)->sin6_port);
            struct sockaddr_in6* pV6Addr = (struct sockaddr_in6*)socketAddr;
            char str[INET6_ADDRSTRLEN];
            ipv6 = [NSString stringWithUTF8String:inet_ntop( AF_INET6, &pV6Addr->sin6_addr, str, INET6_ADDRSTRLEN )];
        }
        else {
            NSLog(@"Socket Family neither IPv4 or IPv6, can't handle...");
        }
    }
    
    if ([ipv6 isEqual:[NSNull null]] || ipv6 == nil) {
        ipv6 = @"";
    }
    
    if ([ipv4 isEqual:[NSNull null]] || ipv4.length == 0) {
        ipv4 = @"";
    }
    
    NSDictionary *data = @{@"mac": macString,
                           @"type": [sender type],
                           @"domain":[sender domain],
                           @"name": [sender name],
                           @"hostName": [sender hostName],
                           @"ipv4": ipv4,
                           @"ipv6": ipv6,
                           @"port": [NSNumber numberWithInt:sPort]};
    return data;
}
 
// 解析服务成功
-(void)netServiceDidResolveAddress:(NSNetService *)sender{
    NSDictionary *resultDict = [self parsingIP:sender];
    
    if(self.resultArray.count == 0 ) {
        [self.resultArray addObject:resultDict];
    }else{
        BOOL didHadServiceInArray = NO;
        for (NSInteger i=0; i

封装工具类完成后,使用的地方,就比较简单了,代码如下:

    [FindDeviceServiceTool.sharedInstance createServiceBrowser];
    FindDeviceServiceTool.sharedInstance.resultBlock = ^(NSArray * _Nullable resultArray) {
        NSLog(@"你想的信息都在这里-------->%@",resultArray);
    };
最终的效果如下图
image.png
3.gif

注意点,使用Bonjour需要申请要权限

image.png

红框里面的4个权限最好都申请一下

    NSLocalNetworkUsageDescription
    Used to scan and find nearby gateway devices, please authorize, otherwise the configuration gateway device function cannot be used normally
    NSLocationWhenInUseUsageDescription
    We need access to your location for creating an account and for sending push notifications
    NSLocationAlwaysAndWhenInUseUsageDescription
    We need access to your location for creating an account and for sending push notifications
    NSBonjourServices
    
        _x5_gw._tcp
    

结尾

看到这里的小伙们,或者觉得文章对你有点帮助的话,请点赞加关注喽,您的反馈就是我们前进的动力。后续会分享更多关于移动端的干货。谢谢~~

补充一下

感谢小伙伴们的关注, 针对有的小伙伴说,没有正常收到消息的问题,在这里补充一下:
Bonjour正确的流程应该是这样的:
第一步: 去局域网中注册Bonjour服务,至于怎么注册及注册过程,此篇文章没有涉及到,请自行研究; 或者让你们公司的硬件工程师去注册Bonjour服务; 注册Bonjour服务这一端,相当于是服务端,只有先有了服务端,有了这个服务,我们iOS工程,作为客户端,才能找到这个服务.

第二步:在iOS工程里面要申请4个权限

第三步:在使用的过程 ,请把我测试的type字符串:"_x5_gw._tcp",改成你们自己的type字符串, 申请权限那边的type字符串,也记得一起改

第四步:才是使用上面封装的工具, 在第一步注册的局域网中去发现服务.

注册Bonjour服务 与 发现服务 一定是在同一局域网中进行; 注册Bonjour服务 与 发现服务 一定是在同一局域网中进行; 注册Bonjour服务 与 发现服务 一定是在同一局域网中进行. 通常情况下,就是在同一个路由器wifi下进行Bonjour注册, 与 Bonjour的服务发现!!!! 最后祝君好运~

你可能感兴趣的:(iOS mdns之Bonjour 客户端基本使用及完美解决各种坑~)