// // Copyright © 2018年 dahua. All rights reserved. // #import "DHNetSDKSearchManager.h" #import "DHNetSDKInterface.h" #import "DHDeviceNetInfo.h" #import #import #import #import #import #import @interface DHNetSDKSearchManager() @property (nonatomic, strong) NSMutableDictionary *netInfoDic; @property (nonatomic, assign) long searchHandle; @property (nonatomic, copy) dispatch_queue_t queue; @property (nonatomic, copy) dispatch_queue_t searchQueue; @property (nonatomic, strong) NSTimer *timer; @property (nonatomic, assign) NSInteger tickCount; @property (nonatomic, assign) NSTimeInterval lastFindTime; /**< 记录上次NETSDK回调结果的时间 */ @property (nonatomic, assign) NSInteger searchSequence; /**< 搜索的序号 */ @property (nonatomic, copy) NSString *lastSSID;//上次连接的wifi的ssid,用于网络环境变化重新搜索设备 @end @implementation DHNetSDKSearchManager #pragma mark - circle life - (instancetype)init { if(self = [super init]) { [self initNetSdk]; _netInfoDic = @{}.mutableCopy; _queue = dispatch_queue_create("syncOperation", DISPATCH_QUEUE_CONCURRENT); _searchQueue = dispatch_queue_create("searchQueue", DISPATCH_QUEUE_SERIAL); _tickCount = 0; #if DEBUG _showDebugLog = NO; #else _showDebugLog = YES; #endif } return self; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } #pragma mark - Notification - (void)addObservers { //防止重复添加 [self removeObservers]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive:) name:UIApplicationWillResignActiveNotification object:nil]; //监听是否触发home键挂起程序,(把程序放在后台执行其他操作) [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil]; //监听是否重新进入程序程序.(回到程序) [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkDidChanged:) name:@"LCNotificationWifiNetWorkDidSwitch" object:nil];//从一个wifi网络切换到另外一个wifi网络也要重新获取设备列表 } - (void)removeObservers { [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (void)applicationWillResignActive:(NSNotification *)notification { if(self.timer != nil) { [self.timer fire]; [self.timer invalidate]; self.timer = nil; } DH_LOG_FUN dispatch_async(self.searchQueue, ^{ if(self.searchHandle) { NSLog(@"DHNetSDKSearchManager::Stop search in resign active:%ld, sequence:%ld", self.searchHandle, (long)self.searchSequence); [[DHNetSDKInterface sharedInstance] stopSearchDevices:self.searchHandle]; self.searchHandle = 0; } }); } - (void)applicationDidBecomeActive:(NSNotification *)notification { if(self.isSearching) { [self startSearch]; } } - (void)networkDidChanged:(NSNotificationCenter *)notification { // DTS000583328 偶现崩溃 [DHMobileInfo sharedInstance].WIFISSID if (!self.isSearching) { return; } //针对软ap添加的bug NSString *wifiSSID = [[DHMobileInfo sharedInstance].WIFISSID uppercaseString]; if (![wifiSSID isEqualToString:self.lastSSID] && wifiSSID.length) { self.lastSSID = wifiSSID; [self.netInfoDic removeAllObjects]; if(self.isSearching) { [self startSearch]; } } } #pragma mark - interface - (void)startSearch { if(self.timer != nil) { [self.timer fire]; [self.timer invalidate]; self.timer = nil; } DH_LOG_FUN NSInteger tick = 2; self.timer = [NSTimer scheduledTimerWithTimeInterval:tick target:self selector:@selector(timeTick) userInfo:nil repeats:YES]; self.isSearching = YES; [self timeTick]; //添加通知 [self addObservers]; } - (void)timeTick { //wifi连接连接过程中,可能会出现无法识别的情况,不能加此判断 //只处理ios13以下系统,不是WiFi状态时,不进行检测 if (DH_IOS_VERSION < 13 && [DHNetWorkHelper sharedInstance].emNetworkStatus != AFNetworkReachabilityStatusReachableViaWiFi) { return; } //【*】打印当前的WIFI信息、定位软AP相关问题 if (self.tickCount % 10 == 0) { NSLog(@"DHNetSDKSearchManager::当前WIFI信息 %@, Mask:%@, Router:%@, IP:%@", DHMobileInfo.sharedInstance.WIFISSID, UIDevice.lc_getMaskAddress, [UIDevice lc_getRouterAddress], UIDevice.lc_getIPAddress); } //计时不中断 self.tickCount++; NSInteger intervalCheck = 10; if(self.tickCount % intervalCheck == 0) { [self clearnUnReceiveDevice]; } if (self.tickCount % 5 == 0) { if (_showDebugLog) { dispatch_barrier_async(self.queue, ^{ NSLog(@"当前搜索到的设备:\n%@",self.netInfoDic.allKeys); }); } } // 距离上次回调时间大于3s,才重新开始重新搜索 NSTimeInterval currentTime = NSDate.date.timeIntervalSince1970; if (fabs(currentTime - self.lastFindTime) < 3) { NSLog(@"DHNetSDKSearchManager:: Ignore tick process..."); return; } // 已经停止了,不需要再重新搜索 if (self.isSearching == false) { NSLog(@"DHNetSDKSearchManager:: Search is stopped, return..."); return; } dispatch_async(self.searchQueue, ^{ if(self.searchHandle) { NSLog(@"DHNetSDKSearchManager::Stop search in timetick:%ld, sequence:%ld", self.searchHandle, (long)self.searchSequence); [[DHNetSDKInterface sharedInstance] stopSearchDevices:self.searchHandle]; self.searchHandle = 0; } //【*】记录下当前搜索的序号 //【*】优化:采用传IP+不传IP交替搜索 NSString *localIp = (self.searchSequence % 2) == 0 ? UIDevice.lc_getIPAddress : nil; self.searchSequence++; NSInteger sequence = self.searchSequence; self.searchHandle = [[DHNetSDKInterface sharedInstance] startSearchDevices:^(DHDeviceNetInfo *netInfo) { dispatch_barrier_async(self.queue, ^{ netInfo.searchSequence = sequence; if (self.showDebugLog) { NSLog(@"DHNetSDKSearchManager::-find device: %@ - %@,搜索序号:%ld, Init type:%lu, status: %lu", netInfo.deviceType, netInfo.serialNo, (long)netInfo.searchSequence, (unsigned long)netInfo.deviceInitType, (unsigned long)netInfo.deviceInitStatus); } //避免找到deviceId为空的情况 if (netInfo.serialNo.length > 0) { DHNetSDKSearchManager.sharedInstance.netInfoDic[netInfo.serialNo] = netInfo; } self.lastFindTime = NSDate.date.timeIntervalSince1970; }); } byLocalIp: localIp]; NSLog(@"DHNetSDKSearchManager:: Start search with handle:%ld, search sequence:%ld", self.searchHandle, (long)self.searchSequence); if(self.searchHandle == 0) { unsigned int errorCode = [DHNetSDKInterface getLastError]; NSLog(@"NetSDKInteface:: Load wifilist failed with errorCode:...0x%x", errorCode); NSLog(@"DHNetSDKSearchManager::CLIENT_StartSearchDevices-fail"); DHAddDeviceLogModel *model = [[DHAddDeviceLogModel alloc] init]; model.method = @"startSearchDevices"; model.res = model.resFail; model.errCode = errorCode; [[DHAddDeviceLogManager shareInstance] addDeviceNetSDKLogWithModel:model]; } }); } - (void)stopSearch { //停止通知 [self removeObservers]; dispatch_barrier_async(self.queue, ^{ [self.netInfoDic removeAllObjects]; }); if(self.timer != nil) { [self.timer fire]; [self.timer invalidate]; self.timer = nil; } dispatch_async(self.searchQueue, ^{ if(self.searchHandle) { NSLog(@"DHNetSDKSearchManager::Stop search in stop:%ld, sequence:%ld", self.searchHandle, (long)self.searchSequence); [[DHNetSDKInterface sharedInstance] stopSearchDevices:self.searchHandle]; self.searchHandle = 0; } }); self.searchSequence = 0; self.lastFindTime = 0; self.isSearching = NO; } - (id)getNetInfoByID:(NSString *)deviceID; { __block id device; dispatch_barrier_sync(self.queue, ^{ device = self.netInfoDic[deviceID]; }); return device; } #pragma mark - Custom - (void)clearnUnReceiveDevice { dispatch_barrier_async(self.queue, ^{ //把所有未标记的从dic中一出 已标记的变成未标记 等待下一次的搜索 NSArray *allKeys = [self.netInfoDic allKeys].copy; for (NSString *key in allKeys) { DHDeviceNetInfo *device = self.netInfoDic[key]; if(!device.isVaild) { NSLog(@"%@ 在这次搜索中被移除", key); [self.netInfoDic removeObjectForKey:key]; } else if (device.searchSequence != self.searchSequence) { //【*】21589:只有当前的搜索结束了,才将缓存中未搜索到的设备有效状态重置 NSLog(@"DHNetSDKSearchManager:: 重置设备有效状态,设备 %@, 搜索序号: %ld, 当前序号:%ld", device.deviceSN, (long)device.searchSequence, (long)self.searchSequence); self.netInfoDic[key].isVaild = NO; } } }); } #pragma mark - private method -(void)initNetSdk { [DHNetSDKInterface initSDK]; #if DEBUG NSString *path = [[DHFileManager supportFolder] stringByAppendingPathComponent:@"cache"]; [DHNetSDKInterface logOpen: path]; #endif } #pragma mark - singleton static DHNetSDKSearchManager *_instance = nil; + (instancetype)sharedInstance { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [[self alloc] init]; }); return _instance; } + (id)allocWithZone:(struct _NSZone *)zone { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ _instance = [super allocWithZone:zone]; }); return _instance; } - (id)copyWithZone:(NSZone *)zone{ return _instance; } @end