// // BTDataProcessVC.m // Unity-iPhone // // Created by leon on 2021/2/3. #import "BTDataProcess.h" #import "IOSPlatformSDK.h" #include "Game.h" #import "MYFactoryManager.h" #import "LEONBLManager.h" #import "ShoesInfo.h" #import "GameInfo.h" #import "CacheTool.h" //#define NSLog(format, ...) printf("TIME:%s FILE:%s(%d行) FUNCTION:%s %s\n",__TIME__, [[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, __PRETTY_FUNCTION__, [[NSString stringWithFormat:(format), ##__VA_ARGS__] UTF8String]) @interface BTDataProcess () { @private Game *game; Game *viceDeviceGame; } //蓝牙弹窗 @property (strong, nonatomic)SearchDeviceViewController * searchDeviceVC; //蓝牙外设数据源 @property (strong, nonatomic)NSMutableArray * deviceArray; //好友列表弹窗 @property (strong, nonatomic)FriendsListViewController * friendsListVC; //定时查询设备状态 @property(nonatomic,weak)NSTimer * timer; //鞋子信息 @property(nonatomic,strong)ShoesInfo * shoes_info; //当局游戏信息 @property(nonatomic,strong)GameInfo * game_info; // @property(nonatomic,assign)BOOL isPopUp; @end @implementation BTDataProcess #pragma mark ===============================================>> 单例 static BTDataProcess* instance = nil; +(instancetype)sharedInstance{ return [[self alloc] init]; } + (instancetype)allocWithZone:(struct _NSZone *)zone{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [super allocWithZone:zone]; }); return instance; } - (instancetype)init{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [super init]; //游戏数据初始化 [self initData]; }); return instance; } #pragma mark ===============================================>> private -(void)initData{ self.shoes_info = [ShoesInfo new]; self.shoes_info.gameModel = NO; //默认游戏模式关 self.shoes_info.timestamp = [AlgorithmTool returnTimestamp];//跳转游戏时候刷新一个新的时间戳 self.game_info = [GameInfo new]; self.game_info.isBackGround = NO; //后台模式 NSLog(@"self.game_info = %d %d %d %d %d %d %d",self.game_info.step,self.game_info.jump,self.game_info.crouch,self.game_info.tick,self.game_info.paper,self.game_info.scissors,self.game_info.rock); //监听 趣动 app group 消息 ==>> 好友邀请信息 CFStringRef invite = (__bridge CFStringRef)@"INVITE_NOTIFICATION"; CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, inviteFriends, invite, NULL, CFNotificationSuspensionBehaviorDeliverImmediately); //监听 趣动 app group 消息 ==>> 断开蓝牙 CFStringRef strRef = (__bridge CFStringRef)@"DISCONNECT_BLE"; CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, disConnectBle, strRef, NULL, CFNotificationSuspensionBehaviorDeliverImmediately); //监听程序 退到 后台 [CUS_NOTIFICATIONCENTER addObserver:self selector:@selector(enterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil]; //监听程序 返回 前台 [CUS_NOTIFICATIONCENTER addObserver:self selector:@selector(willEnterForeground) name:UIApplicationWillEnterForegroundNotification object:nil]; } -(void)enterBackground{ NSLog(@"leon UIApplicationDidEnterBackgroundNotification"); self.game_info.isBackGround = YES; } -(void)willEnterForeground{ NSLog(@"leon UIApplicationWillEnterForegroundNotification"); // 发送app group通知 NSString * notificaitonName = @"GAME_ENTERFOREGROUND"; CFStringRef strRef = (__bridge CFStringRef)notificaitonName; CFNotificationCenterRef notification = CFNotificationCenterGetDarwinNotifyCenter (); CFNotificationCenterPostNotification(notification, strRef, NULL,NULL, YES); self.game_info.isBackGround = NO; NSLog(@"程序从后台返回 重连蓝牙 peripheral.state = %ld %ld",LEManager.peripheral.state,LEManager.vicePeripheral.state); //主副设备:deviceType 游戏种类:game_type mac地址:macAddress self.game_info.deviceType = DEVICETYPE_MAIN; self.game_info.game_type = (GAME_TYPE)[[CacheTool getGameType] intValue]; self.game_info.vibrate = [CacheTool getGameVibrate]; self.game_info.debug = [CacheTool getGameDebug]; self.shoes_info.macAddress = [CacheTool getGameMac]; self.shoes_info.viceMacAddress = @""; //开启自动重连 [self newCentralManagerOrScan]; } //返回趣动同时断开主副设备链接 void disConnectBle (CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo){ NSLog(@"趣动 通知断开蓝牙"); [instance disConnedctBle:0]; [instance disConnedctBle:1]; } //趣动or点击游戏内断开按钮 ==>> 断开蓝牙 -(void)disConnedctBle:(int)type{ //是点击button主动断开 if (type == 0){ self.shoes_info.macAddress = @""; }else if (type == 1){ self.shoes_info.viceMacAddress = @""; } [LEManager cancelPeripheralConnection:type]; } //趣动 ==>> 通知邀请好友 void inviteFriends (CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo){ NSLog(@"IOS_SKD 回调好友邀请信息 GetInviteInfo ===>> %@",userInfo); //group.com.Oujia.AppAndGame 沙河数据 NSUserDefaults* userDefault = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.Oujia.AppAndGame"]; //趣动传过来的 invite json字符串转字典 NSString * string = [userDefault objectForKey:@"invite"]; if (string == nil) { [PopupView showCusHUDA:@"邀请参数为空"]; return; } NSData * data = [string dataUsingEncoding:NSUTF8StringEncoding]; NSDictionary * inviteDict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; if (inviteDict!=nil){ //字典取值 NSDictionary * invite = [inviteDict objectForKey:@"invite"]; NSDictionary * user = [invite objectForKey:@"user"]; //user字典 -> 字符串 -> Char NSData * userData = [NSJSONSerialization dataWithJSONObject:user options:NSJSONWritingPrettyPrinted error:nil]; NSString * userString = [[NSString alloc] initWithData:userData encoding:NSUTF8StringEncoding]; const char * userChar =[userString UTF8String]; //info字符串 -> Char NSString * infoString = invite[@"info"]; const char * infoChar =[infoString UTF8String]; NSLog(@"IOS_SKD 回调好友邀请信息 GetInviteInfo ===>> %s , %s",userChar,infoChar); [[IOSPlatformSDK sharedInstance] bridgingInvite:0 userChar:userChar infoChar:infoChar]; } } #pragma mark ===============================================>> public method -(void)startWithUrl:(NSURL*)url{// if (url==nil){ return; } NSString * urlString = [url absoluteString]; NSArray * stringArr = [urlString componentsSeparatedByString:@"//"]; if (stringArr == nil || stringArr.count<2){ return; } NSString * arr2 = stringArr[1]; NSString* finsalString = [arr2 stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; NSDictionary * urlDict = [AlgorithmTool dictionaryWithJsonString:finsalString]; NSLog(@"Schemes_Url转码的dict ========= %@",urlDict); //缓存用户信息数据 [IOS_NSUSERDEFAULT setObject:urlDict forKey:IOSSDK_USERINFO]; [IOS_NSUSERDEFAULT synchronize]; //界面还没加载完毕 弹窗会导致奔溃 // //检查有没有好友邀请信息 // const char * userChar = [[CacheTool getInviteUser] UTF8String]; // const char * infoChar =[[CacheTool getInviteInfo] UTF8String]; // if (infoChar!=nil&&strlen(infoChar)>1) { // [[IOSPlatformSDK sharedInstance] bridgingInvite:0 userChar:userChar infoChar:infoChar]; // } //主副设备:deviceType 游戏种类:game_type mac地址:macAddress self.game_info.deviceType = DEVICETYPE_MAIN; self.game_info.game_type = (GAME_TYPE)[[CacheTool getGameType] intValue]; self.game_info.vibrate = [CacheTool getGameVibrate]; self.game_info.debug = [CacheTool getGameDebug]; //重置mac self.shoes_info.macAddress = [CacheTool getGameMac]; self.shoes_info.viceMacAddress = @""; //链接蓝牙 [self newCentralManagerOrScan]; } //unity call instance弹出蓝牙搜索框 -(void)searchBLEAction:(int)type{ //初始化蓝牙CBCentralManager [self newCentralManagerOrScan]; //搜索蓝牙外设弹窗 if (self.searchDeviceVC!=nil){ self.searchDeviceVC=nil; } self.searchDeviceVC = [SearchDeviceViewController new]; self.isPopUp = YES; [[UIApplication sharedApplication].keyWindow addSubview:self.searchDeviceVC.view]; //点击searchVC的tableViewCell链接选中的蓝牙 __weak __typeof(self)weakself = self; self.searchDeviceVC.connectDeviceBlock = ^(CBPeripheral * peripheral){ //主副设备:deviceType 游戏种类:game_type mac地址:macAddress weakself.game_info.game_type = (GAME_TYPE)[[CacheTool getGameType] intValue]; weakself.game_info.deviceType = (DEVICE_TYPE)type; if (type == 0) { weakself.shoes_info.macAddress = peripheral.identifier.UUIDString; }else if (type ==1){ weakself.shoes_info.viceMacAddress = peripheral.identifier.UUIDString; } [weakself connectBLEManagerData:peripheral]; }; self.searchDeviceVC.closeBlock = ^{ weakself.isPopUp = NO; }; } //unity call instance弹出 好友列表 搜索框 (int code, char * info) -(void)showInviteFriend:(int)code inviteInof:(NSString*)inviteInof{ //搜索蓝牙外设弹窗 if (self.friendsListVC!=nil){ self.friendsListVC=nil; } self.friendsListVC = [FriendsListViewController new]; self.isPopUp = YES; [[UIApplication sharedApplication].keyWindow addSubview:self.friendsListVC.view]; [MBProgressHUD showHUDAddedTo:self.friendsListVC.view animated:YES]; [HTTPDataProcession getFriendsList:^(int code, const char *jsonString, NSMutableArray *dataArr){ NSLog(@"IOS_SKD 回调好友列表 GetUserFriends 数组 ===> %@",dataArr); self.friendsListVC.friendsArray = dataArr; //主线程 dispatch_async(dispatch_get_main_queue(), ^{ [MBProgressHUD hideHUDForView:self.friendsListVC.view animated:YES]; [self.friendsListVC reloadData]; }); }]; //点击searchVC的tableViewCell链接选中的蓝牙 __weak __typeof(self)weakself = self; self.friendsListVC.inviteFriendBlock = ^(UserFriendsModel *model){ [HTTPDataProcession inviteFriends:model.trans_id inviteInfo:inviteInof inviteDataBlock:^(NSString *jsonString){ // NSLog(@"IOS_SKD 回调点击邀请好友事件 InviteFriend ===>>"); dispatch_async(dispatch_get_main_queue(), ^{ [PopupView showCusHUDA:jsonString]; }); }]; }; self.friendsListVC.closeBlock = ^{ // NSLog(@"设置 weakself.isPopUp = NO"); weakself.isPopUp = NO; }; // } //每重新开始一局游戏 -(void)gameStartInitData{ //当局游戏持续时间 self.game_info.firstTime = [NSDate date]; //游戏模式 ==>> 回调剑波sdk数据 self.shoes_info.gameModel = YES; //读写到特征后 添加测试弹窗 dispatch_async(dispatch_get_main_queue(), ^{ [DebugViewInstance notificationStartGame]; }); } //每结束一局游戏 -(void)gameEndInitData{ self.shoes_info.gameModel = NO; if ([self.game_info.debug intValue] == 1) { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(),^{ [DebugViewInstance uploadpPlistFile]; }); } } //监听unity通知震动 -(void)vibrationAction:(int)type duration:(int)duration leftOrRight:(int)leftOrRight{ if ([self.game_info.vibrate intValue] == 1) { [BTDataSendInstance vibration:(DEVICE_TYPE)type duration:duration leftOrRight:leftOrRight]; } } #pragma mark ===============================================>> leon Ble manager //自己封装的蓝牙类 -(void)newCentralManagerOrScan{ if (LEManager.centralManager == nil && LEManager.peripheral == nil && LEManager.vicePeripheral == nil){ NSLog(@" ====================>> 未初始化 centralManager 直接开始初始化"); [LEManager initCBCentralManager]; }else{ [self ifHasLinks]; } //每次 initCBCentralManager 走以下回调 LEManager.stateUpdateBlock = ^(CBCentralManager * central){ switch(central.state){ case 0: NSLog(@"当前的蓝牙状态 ===>> CBCentralManagerStateUnknown"); break; case 1: NSLog(@"当前的蓝牙状态 ===>> CBCentralManagerStateResetting"); break; case 2: NSLog(@"当前的蓝牙状态 ===>> CBCentralManagerStateUnsupported"); break; case 3: NSLog(@"当前的蓝牙状态 ===>> CBCentralManagerStateUnauthorized"); break; case 4:{ NSLog(@"当前的蓝牙状态 ===>> 蓝牙已关闭"); if (LEManager.peripheral!=nil){ [[IOSPlatformSDK sharedInstance] bridgingDeviceAction:DEVICETYPE_MAIN name:LEManager.peripheral.name address:LEManager.peripheral.identifier.UUIDString status:CONNECT_LOST electricity:0]; } if (LEManager.vicePeripheral!=nil){ [[IOSPlatformSDK sharedInstance] bridgingDeviceAction:DEVICETYPE_VICE name:LEManager.vicePeripheral.name address:LEManager.vicePeripheral.identifier.UUIDString status:CONNECT_LOST electricity:0]; } } break; case 5:{ NSLog(@"当前的蓝牙状态 ===>> 蓝牙已开启");//蓝牙已开启 [self ifHasLinks]; } break; default: break; } }; [self.deviceArray removeAllObjects]; //发现蓝牙 LEManager.discoverPeripheralBlock = ^(CBCentralManager * _Nonnull central, CBPeripheral * _Nonnull peripheral, NSDictionary * _Nonnull advertisementData, NSNumber * _Nonnull RSSI){ // NSLog(@"扫描发现蓝牙设备advertisementData = %@",advertisementData); NSString *advertiseName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey]; NSData * manufacturerData = [advertisementData objectForKey:CBAdvertisementDataManufacturerDataKey]; Byte *testByte = (Byte *)[manufacturerData bytes]; if (testByte!=nil) { NSInteger byteLength = sizeof(testByte); NSString * byteString; for (int i = 0; i < byteLength; i++){ int index = testByte[i]; byteString = [NSString stringWithFormat:@"%@,%d",byteString,index]; } NSLog(@" byteString ====================>> %@",byteString); } // NSLog(@"扫描发现蓝牙设备advertisementDataManufacturerData = %@",manufacturerData); peripheral.advertiseName = advertiseName; if ([advertiseName hasPrefix:@"SH_"]||[advertiseName hasPrefix:@"fun_"]||[advertiseName hasPrefix:@"Fun_"]||[advertiseName hasPrefix:@"FUN_"]){//SH_DANCE BLE_LOOP Shoes_4530 Shoes_2A74 // NSLog(@"主设备扫描发现有效的蓝牙设备 =============== %@ identifier == %@",peripheral.name,peripheral.identifier.UUIDString); if (self.deviceArray.count == 0){//数据源为0 [self.deviceArray addObject:peripheral]; //判断扫描到外设之后是否要链接蓝牙 [self judgeConnect:peripheral]; }else{ BOOL isExist = NO; for (int i = 0; i < self.deviceArray.count; i++){ CBPeripheral *per = [self.deviceArray objectAtIndex:i]; if ([per.identifier.UUIDString isEqualToString:peripheral.identifier.UUIDString]){ isExist = YES; [self.deviceArray replaceObjectAtIndex:i withObject:peripheral]; } } if (!isExist){ [self.self.deviceArray addObject:peripheral]; //判断扫描到外设之后是否要链接蓝牙 [self judgeConnect:peripheral]; } } //数据回调给 搜索蓝牙弹窗 self.searchDeviceVC.deviceArray = self.deviceArray; [self.searchDeviceVC reloadData]; } }; } #pragma mark ===============================================>> 主设备蓝牙数据 //扫描还是直链 -(void)ifHasLinks{ [LEManager stopScan]; // //已经被系统或者其他APP连接上的设备数组 // NSArray *arr = [LEManager.centralManager retrieveConnectedPeripheralsWithServices:@[[CBUUID UUIDWithString:@"6E400001-B5A3-F393-E0A9-E50E24DCCA9E"]]]; // // if (arr.count>0) {//已经链了一双鞋子了 // // NSLog(@" ====================>> 已初始化 centralManager 有已经链接的鞋子"); // //UUID是外设的服务UUID,满足UUID 的外设就会放在数组中 // [arr enumerateObjectsUsingBlock:^(CBPeripheral *peripheral, NSUInteger idx, BOOL *stop){ // // if ([peripheral.name hasPrefix:@"SH_"]){//SH_DANCE BLE_LOOP Shoes_4530 Shoes_2A74 // // NSLog(@"主设备 已经链接到的 蓝牙设备 =============== %@ identifier == %@",peripheral.name,peripheral.identifier.UUIDString); // // LEManager.peripheral = peripheral; // // [self connectPeripheral:LEManager.peripheral]; // // } // // }]; // // }else{ NSLog(@" ====================>> 已初始化 centralManager 直接开扫描"); [LEManager scanForPeripheralsWithServices:nil options:nil]; // } } //app跳转 断线重连 从后台返回 -(void)judgeConnect:(CBPeripheral*)peripheral{ // NSLog(@"self.shoes_info.macAddress = %@ peripheral.identifier.UUIDString = %@",self.shoes_info.macAddress,peripheral.identifier.UUIDString); if (self.shoes_info.macAddress.length>12 && [peripheral.identifier.UUIDString isEqualToString:self.shoes_info.macAddress]){ self.game_info.deviceType = DEVICETYPE_MAIN; [self connectBLEManagerData:peripheral]; } if (self.shoes_info.viceMacAddress.length>12 && [peripheral.identifier.UUIDString isEqualToString:self.shoes_info.viceMacAddress]){ self.game_info.deviceType = DEVICETYPE_VICE; [self connectBLEManagerData:peripheral]; }// } #pragma mark ===============================================>> public 链接蓝牙 //搜索弹窗 点击 //链接蓝牙 -(void)connectBLEManagerData:(CBPeripheral*)peripheral{ NSLog(@"peripheral.name ==>> %@",peripheral.name); if(instance == NULL || peripheral == NULL){return;} NSLog(@"BTDataProcess connectPeripheral self.game_info.deviceType ==>> %ld self.game_info.game_type ==>> %d mac ==>> %@",(long)self.game_info.deviceType,self.game_info.game_type,self.shoes_info.macAddress); //初始化运轨sdk if (self.game_info.deviceType==DEVICETYPE_MAIN){ LEManager.peripheral = peripheral; game = new Game(self.game_info.game_type); //开始链接动画 [[MainLoadingView shanreAnimationView] addAnimation]; }else if (self.game_info.deviceType == DEVICETYPE_VICE){ LEManager.vicePeripheral = peripheral; viceDeviceGame = new Game(self.game_info.game_type); //开始链接动画 [[ViceLoadingView shanreAnimationView] addAnimation]; } //链接蓝牙 此时 LEManager.peripheral || LEManager.vicePeripheral 还未init [LEManager connectPeripheral:peripheral options:nil]; //蓝牙连接成功 LEManager.successfulBlock = ^(CBPeripheral * _Nonnull peripheral){ if (self.shoes_info.macAddress.length>12 && self.shoes_info.viceMacAddress.length == 0){//有主没副 if (LEManager.peripheral.state == CBPeripheralStateConnected){//主设备已经连接上后 停止扫描 NSLog(@"主设备蓝牙链接成功"); [LEManager stopScan]; } }else if(self.shoes_info.macAddress.length == 0 && self.shoes_info.viceMacAddress.length >12){//没主有副 if (LEManager.vicePeripheral.state == CBPeripheralStateConnected){//副设备已经连接上后 停止扫描 NSLog(@"副设备蓝牙链接成功"); [LEManager stopScan]; } }else if(self.shoes_info.macAddress.length>12 && self.shoes_info.viceMacAddress.length > 12){//有主有副 if (LEManager.peripheral.state == CBPeripheralStateConnected && LEManager.vicePeripheral.state == CBPeripheralStateConnected){//主和副设备都已经连接上后 停止扫描 NSLog(@"主设备 和 副设备 蓝牙链接成功"); [LEManager stopScan]; } } }; //蓝牙连接失败 LEManager.connectFailureBlock = ^(NSError * _Nonnull error){ NSLog(@"蓝牙链接失败"); }; //蓝牙连接丢失 LEManager.disConnectBlock = ^(CBPeripheral * _Nonnull peripheral, NSError * _Nonnull error){ if (LEManager.peripheral!=nil && peripheral==LEManager.peripheral){ [[IOSPlatformSDK sharedInstance] bridgingDeviceAction:DEVICETYPE_MAIN name:LEManager.peripheral.name address:LEManager.peripheral.identifier.UUIDString status:CONNECT_LOST electricity:0]; if (self.shoes_info.macAddress.length>12){ NSLog(@"主设备 蓝牙链接断开 被动断开 需要重连"); [self newCentralManagerOrScan]; }else{ NSLog(@"主设备 蓝牙链接断开 主动断开 不需重连"); } } if (LEManager.vicePeripheral!=nil && peripheral==LEManager.vicePeripheral){ [[IOSPlatformSDK sharedInstance] bridgingDeviceAction:DEVICETYPE_VICE name:LEManager.vicePeripheral.name address:LEManager.vicePeripheral.identifier.UUIDString status:CONNECT_LOST electricity:0]; //副设备 断线 手动断开的话不用重连,自动断开的要重连 if (self.shoes_info.viceMacAddress.length>12){ NSLog(@"副设备 蓝牙链接断开 被动断开 需要重连"); [self newCentralManagerOrScan]; }else{ NSLog(@"副设备 蓝牙链接断开 主动断开 不需重连"); } } }; //发现服务和特征 LEManager.discoverCharacteristicsBlock = ^(CBPeripheral * _Nonnull peripheral, CBService * _Nonnull service, NSArray * _Nonnull characteristics, NSError * _Nonnull error){ if (peripheral==LEManager.peripheral){//主设备 for (CBCharacteristic * cha in service.characteristics){ if (cha.properties == 12){//写 LEManager.write = cha; //获取到写的特征后才能向 主设备 蓝牙对象写入数据 [self startGameModeAndQueryDevideInfo]; //链接成功震动一次 [BTDataSendInstance vibration:DEVICETYPE_MAIN duration:400 leftOrRight:0]; [self initTimer]; }else if (cha.properties == 16){//读 LEManager.read = cha; [LEManager.peripheral readValueForCharacteristic:cha]; [LEManager.peripheral setNotifyValue:YES forCharacteristic:cha]; } } }else if (peripheral==LEManager.vicePeripheral){//副设备 for (CBCharacteristic * cha in service.characteristics){ if (cha.properties == 12){//写 LEManager.viceWrite = cha; //获取到写的特征后才能向 副设备 蓝牙对象写入数据 [self startGameModeAndQueryDevideInfo]; //链接成功震动一次 [BTDataSendInstance vibration:DEVICETYPE_VICE duration:400 leftOrRight:0]; }else if (cha.properties == 16){//读 LEManager.viceRead = cha; [LEManager.vicePeripheral readValueForCharacteristic:cha]; [LEManager.vicePeripheral setNotifyValue:YES forCharacteristic:cha]; } } } }; //读取特征的报文数据 LEManager.readValueForCharacteristicBlock = ^(CBPeripheral * _Nonnull peripheral, CBCharacteristic * _Nonnull characteristic, NSData * _Nonnull value, NSError * _Nonnull error){ // NSLog(@"characteristic.value = %@ characteristic.UUID.UUIDString = %@",characteristic.value,characteristic.UUID.UUIDString); if ([characteristic.UUID.UUIDString isEqualToString:@"6E400003-B5A3-F393-E0A9-E50E24DCCA9E"]){//判断是不是我们设备 //每收到数据包读取一次蓝牙RSSI 无论1秒内请求多少次rssi值,原生api每秒都最多返回一次RSSI [peripheral readRSSI]; //带cmd位的有效数据 计算校验位 if ([AlgorithmTool verificationRusult:characteristic.value]==YES){ int dataType = [AlgorithmTool dataToChar:[characteristic.value subdataWithRange:NSMakeRange(3, 1)]];//cmd类型 if (dataType == 4){//鞋子游戏数据 if (characteristic.value.length < 64){ return; } //数据丢给算法计算轨迹 if (peripheral==LEManager.peripheral&&LEManager.main_read == 0){ // NSLog(@"LEManager.main_read = %d",LEManager.main_read); // NSLog(@"主设备 读取特征的报文 游戏数据 %ld dataType = %d %@",(long)type,dataType,characteristic.value); [[MainLoadingView shanreAnimationView] stopAnimation]; LEManager.main_read = 1; [self shoseSDK:characteristic.value]; }else if (peripheral==LEManager.vicePeripheral&&LEManager.vice_read == 0){ [[ViceLoadingView shanreAnimationView] stopAnimation]; LEManager.vice_read = 1; [self viceShoseSDK:characteristic.value]; } }else if(dataType == -95){//鞋子状态信息 if (characteristic.value.length<30){ return; } //嵌入式原始数据解析 --->> 回调蓝牙状态/电量给unity BTDataAnalysis * anly = [BTDataAnalysis new]; [anly analysisCharacteristic:characteristic.value peripheral:peripheral]; } } } }; //蓝牙更新RSSI LEManager.rssiBlock = ^(NSNumber * _Nonnull RSSI){ LEManager.RSSI = RSSI; }; } #pragma mark ===============================================>> 读取特征后 鞋子打开游戏模式 & 激光开关 &查询鞋子蓝牙状态 & 主设备初始化缓存游戏步数 //init定时器 -(void)initTimer{ //定时开启游戏模式 & 查询设备信息 & 开启激光检测下蹲 if (self.timer!=nil){ [self.timer invalidate]; self.timer = nil; } self.timer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(startGameModeAndQueryDevideInfo) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode]; } //定时发送数据 -(void)startGameModeAndQueryDevideInfo{ //开启游戏模式&查询设备信息 初始化步数数据 (防止读取到的读写为空 延迟0.5s) dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(),^{ if (self.game_info.isBackGround){//程序在后台 }else{//程序在前台 [BTDataSendInstance startGameModel]; [BTDataSendInstance queryDevideInfo]; [BTDataSendInstance keepConnect]; } }); } #pragma mark ===============================================>> 主设备 报文数据解析后 -- 调用蓝牙鞋子SDK装换数据 -- ios call unity 更新游戏动作 -(void)shoseSDK:(NSData*)characteristic{ // NSLog(@"characteristic = %@",characteristic); /********************初始化 运动轨迹算法 SDK *****************/ NSData * validData= [characteristic subdataWithRange:NSMakeRange(4, characteristic.length-4)]; Byte * buff = (Byte*)[validData bytes]; game->GameProcessBuf(buff, (int)validData.length); if (self.shoes_info.gameModel==YES){//当前是游戏模式 /********************剑波 & 威严 要的图表数据 *****************/ NSString * message = [NSString stringWithUTF8String:game->getGameDataStr().c_str()]; [DebugViewInstance debugMessage:message shoesInfo:self.shoes_info]; } /******************左右脚动作数据处理 + 回调*****************/ int length = 10; int result[length]; game->getGameResult(result); int motionLeft = result[0];//左脚的动作 int motionRight = result[1];//右脚的动作 int motionJump = result[2];//jump int motionDown = result[3];//down // //无效动作 过滤无效动作会导致步频加速无效 // if (motionLeft==-1 && motionRight == -1&& motionJump == -1&& motionDown == -1){ // return; // } //跳跃和蹲下的动作 双脚是同步的 if (motionJump == MOTION_JUMP||motionJump == MOTION_JUMP_OC||motionJump == MOTION_JUMP_VERTICAL){ motionLeft = motionJump; motionRight = motionJump; } if (motionDown == MOTION_DOWN){ motionLeft = motionDown; motionRight = motionDown; } /******************当局游戏 鞋子子动作状态数据 缓存*****************/ self.shoes_info.leftStepStatus = game->getStepStatus(LEFT_FOOT); self.shoes_info.leftStepFreq = game->getStepFreq(LEFT_FOOT); self.shoes_info.leftStepCount = game->getStepCount(LEFT_FOOT); self.shoes_info.rightStepStatus = game->getStepStatus(RIGHT_FOOT); self.shoes_info.rightStepFreq = game->getStepFreq(RIGHT_FOOT); self.shoes_info.rightStepCount = game->getStepCount(RIGHT_FOOT); [self cacheAllMotionCount]; /******************鞋子动作状态数据 实时回调*****************/ //左右脚动作:所有游戏都需要回调 [[IOSPlatformSDK sharedInstance] bridgingMotionAction:DEVICETYPE_MAIN left:motionLeft right:motionRight]; //步频状态:只有跑酷回调 if (self.game_info.game_type == GAME_TYPE_RUN||self.game_info.game_type == GAME_TYPE_CYCLE){ [[IOSPlatformSDK sharedInstance] bridgingStepAction:DEVICETYPE_MAIN leftStatus:self.shoes_info.leftStepStatus rightStatus:self.shoes_info.rightStepStatus leftFrag:self.shoes_info.leftStepFreq rightFrag:self.shoes_info.rightStepFreq]; } //人物朝向 只有 三轮车 需要 if (self.game_info.game_type == GAME_TYPE_CYCLE){ int attLength = 3; int left[attLength]; int right[attLength]; game->getFootAtt(left, right); self.main_nativeAttX = left[0]; // NSLog(@"self.nativeAttX = %d",self.nativeAttX); } /******************脚步交互数据 实时回调*****************/ int interaction = game->getInteractionCMD(); if (interaction==-1){ return; } //自定义弹窗界面交互 if (self.isPopUp == YES){ NSLog(@"BTDataProcess 有效交互动作 ===>> %d",interaction); [self.searchDeviceVC getInteraction:interaction]; [self.friendsListVC getInteraction:interaction]; }else{ //游戏界面交互 [[IOSPlatformSDK sharedInstance] bridgingInteraction:DEVICETYPE_MAIN code:interaction]; } } #pragma mark ===============================================>>副设备 报文数据解析后 -- 调用蓝牙鞋子SDK装换数据 -- ios call unity 更新游戏动作 -(void)viceShoseSDK:(NSData*)characteristic{ /********************初始化 运动轨迹算法 SDK *****************/ //游戏数据 NSData * validData= [characteristic subdataWithRange:NSMakeRange(4, characteristic.length-4)]; Byte * buff = (Byte*)[validData bytes]; viceDeviceGame->GameProcessBuf(buff, (int)validData.length); //当前是游戏模式 // if (self.shoes_info.gameModel==YES){ /******************左右脚动作数据处理 + 回调*****************/ int length = 10; int result[length]; viceDeviceGame->getGameResult(result); int motionLeft = result[0];//左脚的动作 int motionRight = result[1];//右脚的动作 int ivce_motionJump = result[2];//jump int ivce_motionDown = result[3];//down //跳跃和蹲下的动作 双脚是同步的 if (ivce_motionJump == MOTION_JUMP||ivce_motionJump == MOTION_JUMP_OC||ivce_motionJump == MOTION_JUMP_VERTICAL){ motionLeft = ivce_motionJump; motionRight = ivce_motionJump; } if (ivce_motionDown == MOTION_DOWN){ motionLeft = ivce_motionDown; motionRight = ivce_motionDown; } /******************当局游戏 鞋子子动作状态数据 缓存*****************/ int leftStepStatus = viceDeviceGame->getStepStatus(LEFT_FOOT); int leftStepFreq = viceDeviceGame->getStepFreq(LEFT_FOOT); // int leftStepCount = viceDeviceGame->getStepCount(LEFT_FOOT); int rightStepStatus = viceDeviceGame->getStepStatus(RIGHT_FOOT); int rightStepFreq = viceDeviceGame->getStepFreq(RIGHT_FOOT); // int rightStepCount = viceDeviceGame->getStepCount(RIGHT_FOOT); /******************鞋子动作状态数据 实时回调*****************/ //左右脚动作:所有游戏都需要回调 [[IOSPlatformSDK sharedInstance] bridgingMotionAction:DEVICETYPE_VICE left:motionLeft right:motionRight]; //步频:跑酷和三轮车 if (self.game_info.game_type == GAME_TYPE_RUN||self.game_info.game_type == GAME_TYPE_CYCLE){ [[IOSPlatformSDK sharedInstance] bridgingStepAction:DEVICETYPE_VICE leftStatus:leftStepStatus rightStatus:rightStepStatus leftFrag:leftStepFreq rightFrag:rightStepFreq]; } //人物朝向:三轮车 if (self.game_info.game_type == GAME_TYPE_CYCLE){ int attLength = 3; int left[attLength]; int right[attLength]; viceDeviceGame->getFootAtt(left, right); self.vice_nativeAttX = left[0]; } // } /******************脚步交互数据 实时回调*****************/ int interaction = viceDeviceGame->getInteractionCMD(); if (interaction==-1){ return; } if (self.isPopUp == YES){//自定义弹窗界面交互 }else{ //游戏界面交互 [[IOSPlatformSDK sharedInstance] bridgingInteraction:DEVICETYPE_VICE code:interaction]; } } #pragma mark ===============================================>> 懒加载 -- 蓝牙设备数据源 -(NSMutableArray*)deviceArray{ if (!_deviceArray){ _deviceArray = [NSMutableArray new]; } return _deviceArray;; } #pragma mark ===============================================>> 玩游戏过程中缓存 动作数据 和时间戳 数据存入plist -(void)cacheAllMotionCount{ //总数 int total_step_count = game->getMotionCount(STEP_COUNT) - self.game_info.step; int total_jump_count = game->getMotionCount(JUMP_COUNT) - self.game_info.jump; int total_crouch_count = game->getMotionCount(DOWN_COUNT) - self.game_info.crouch; int total_tick_count = game->getMotionCount(KICK_COUNT) - self.game_info.tick; int total_paper_count = game->getMotionCount(PAPER_COUNT) - self.game_info.paper; int total_scissors_count = game->getMotionCount(SCISSORS_COUNT) - self.game_info.scissors; int total_rock_count = game->getMotionCount(ROCK_COUNT) - self.game_info.rock; // int total_trample_count = game->getMotionCount(ROCK_COUNT) - self.game_info.trample; // NSLog(@"total_ = %d %d %d %d %d %d %d",total_step_count,total_jump_count,total_cro÷uch_count,total_tick_count,total_paper_count,total_scissors_count,total_rock_count); //缓存pilst文件 NSMutableDictionary * motionCountObj = [NSMutableDictionary new]; [motionCountObj setObject:[NSNumber numberWithInt:total_step_count] forKey:@"step"]; [motionCountObj setObject:[NSNumber numberWithInt:total_jump_count] forKey:@"jump"]; [motionCountObj setObject:[NSNumber numberWithInt:total_crouch_count] forKey:@"crouch"]; [motionCountObj setObject:[NSNumber numberWithInt:total_tick_count] forKey:@"tick"]; [motionCountObj setObject:[NSNumber numberWithInt:total_paper_count] forKey:@"paper"]; [motionCountObj setObject:[NSNumber numberWithInt:total_scissors_count] forKey:@"scissors"]; [motionCountObj setObject:[NSNumber numberWithInt:total_rock_count] forKey:@"rock"]; [motionCountObj setObject:[NSNumber numberWithInt:0] forKey:@"trample"]; NSMutableDictionary * movements = [NSMutableDictionary new]; [movements setObject:motionCountObj forKey:@"movements"]; //游戏总共经历的时长(秒数) NSTimeInterval durationTime = [[NSDate date] timeIntervalSinceDate:self.game_info.firstTime]; [movements setObject:[NSNumber numberWithInt:durationTime] forKey:@"duration"]; //时间戳 [movements setObject: self.shoes_info.timestamp forKey:@"play_group"]; NSDictionary * dict = [NSDictionary dictionaryWithDictionary:movements]; //归档缓存 [IOS_NSUSERDEFAULT setObject:dict forKey:IOSSDK_MOTIONCOUNT]; [IOS_NSUSERDEFAULT synchronize]; } @end