BTDataProcess.mm 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958
  1. //
  2. // BTDataProcessVC.m
  3. // Unity-iPhone
  4. //
  5. // Created by leon on 2021/2/3.
  6. #import "BTDataProcess.h"
  7. #import "IOSPlatformSDK.h"
  8. #include "Game.h"
  9. #import "MYFactoryManager.h"
  10. #import "LEONBLManager.h"
  11. #import "ShoesInfo.h"
  12. #import "GameInfo.h"
  13. #import "CacheTool.h"
  14. //#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])
  15. @interface BTDataProcess ()
  16. {
  17. @private
  18. Game *game;
  19. Game *viceDeviceGame;
  20. }
  21. //蓝牙弹窗
  22. @property (strong, nonatomic)SearchDeviceViewController * searchDeviceVC;
  23. //蓝牙外设数据源
  24. @property (strong, nonatomic)NSMutableArray * deviceArray;
  25. //好友列表弹窗
  26. @property (strong, nonatomic)FriendsListViewController * friendsListVC;
  27. //定时查询设备状态
  28. @property(nonatomic,weak)NSTimer * timer;
  29. //鞋子信息
  30. @property(nonatomic,strong)ShoesInfo * shoes_info;
  31. //当局游戏信息
  32. @property(nonatomic,strong)GameInfo * game_info;
  33. //
  34. @property(nonatomic,assign)BOOL isPopUp;
  35. @end
  36. @implementation BTDataProcess
  37. #pragma mark ===============================================>> 单例
  38. static BTDataProcess* instance = nil;
  39. +(instancetype)sharedInstance{
  40. return [[self alloc] init];
  41. }
  42. + (instancetype)allocWithZone:(struct _NSZone *)zone{
  43. static dispatch_once_t onceToken;
  44. dispatch_once(&onceToken, ^{
  45. instance = [super allocWithZone:zone];
  46. });
  47. return instance;
  48. }
  49. - (instancetype)init{
  50. static dispatch_once_t onceToken;
  51. dispatch_once(&onceToken, ^{
  52. instance = [super init];
  53. //游戏数据初始化
  54. [self initData];
  55. });
  56. return instance;
  57. }
  58. #pragma mark ===============================================>> private
  59. -(void)initData{
  60. self.shoes_info = [ShoesInfo new];
  61. self.shoes_info.gameModel = NO; //默认游戏模式关
  62. self.shoes_info.timestamp = [AlgorithmTool returnTimestamp];//跳转游戏时候刷新一个新的时间戳
  63. self.game_info = [GameInfo new];
  64. self.game_info.isBackGround = NO; //后台模式
  65. 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);
  66. //监听 趣动 app group 消息 ==>> 好友邀请信息
  67. CFStringRef invite = (__bridge CFStringRef)@"INVITE_NOTIFICATION";
  68. CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
  69. NULL,
  70. inviteFriends,
  71. invite,
  72. NULL,
  73. CFNotificationSuspensionBehaviorDeliverImmediately);
  74. //监听 趣动 app group 消息 ==>> 断开蓝牙
  75. CFStringRef strRef = (__bridge CFStringRef)@"DISCONNECT_BLE";
  76. CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
  77. NULL,
  78. disConnectBle,
  79. strRef,
  80. NULL,
  81. CFNotificationSuspensionBehaviorDeliverImmediately);
  82. //监听程序 退到 后台
  83. [CUS_NOTIFICATIONCENTER addObserver:self selector:@selector(enterBackground) name:UIApplicationDidEnterBackgroundNotification object:nil];
  84. //监听程序 返回 前台
  85. [CUS_NOTIFICATIONCENTER addObserver:self selector:@selector(willEnterForeground) name:UIApplicationWillEnterForegroundNotification object:nil];
  86. }
  87. -(void)enterBackground{
  88. NSLog(@"leon UIApplicationDidEnterBackgroundNotification");
  89. self.game_info.isBackGround = YES;
  90. }
  91. -(void)willEnterForeground{
  92. NSLog(@"leon UIApplicationWillEnterForegroundNotification");
  93. // 发送app group通知
  94. NSString * notificaitonName = @"GAME_ENTERFOREGROUND";
  95. CFStringRef strRef = (__bridge CFStringRef)notificaitonName;
  96. CFNotificationCenterRef notification = CFNotificationCenterGetDarwinNotifyCenter ();
  97. CFNotificationCenterPostNotification(notification, strRef, NULL,NULL, YES);
  98. self.game_info.isBackGround = NO;
  99. NSLog(@"程序从后台返回 重连蓝牙 peripheral.state = %ld %ld",LEManager.peripheral.state,LEManager.vicePeripheral.state);
  100. //主副设备:deviceType 游戏种类:game_type mac地址:macAddress
  101. self.game_info.deviceType = DEVICETYPE_MAIN;
  102. self.game_info.game_type = (GAME_TYPE)[[CacheTool getGameType] intValue];
  103. self.game_info.vibrate = [CacheTool getGameVibrate];
  104. self.game_info.debug = [CacheTool getGameDebug];
  105. self.shoes_info.macAddress = [CacheTool getGameMac];
  106. self.shoes_info.viceMacAddress = @"";
  107. //开启自动重连
  108. [self newCentralManagerOrScan];
  109. }
  110. //返回趣动同时断开主副设备链接
  111. void disConnectBle (CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo){
  112. NSLog(@"趣动 通知断开蓝牙");
  113. [instance disConnedctBle:0];
  114. [instance disConnedctBle:1];
  115. }
  116. //趣动or点击游戏内断开按钮 ==>> 断开蓝牙
  117. -(void)disConnedctBle:(int)type{
  118. //是点击button主动断开
  119. if (type == 0){
  120. self.shoes_info.macAddress = @"";
  121. }else if (type == 1){
  122. self.shoes_info.viceMacAddress = @"";
  123. }
  124. [LEManager cancelPeripheralConnection:type];
  125. }
  126. //趣动 ==>> 通知邀请好友
  127. void inviteFriends (CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo){
  128. NSLog(@"IOS_SKD 回调好友邀请信息 GetInviteInfo ===>> %@",userInfo);
  129. //group.com.Oujia.AppAndGame 沙河数据
  130. NSUserDefaults* userDefault = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.Oujia.AppAndGame"];
  131. //趣动传过来的 invite json字符串转字典
  132. NSString * string = [userDefault objectForKey:@"invite"];
  133. if (string == nil) {
  134. [PopupView showCusHUDA:@"邀请参数为空"];
  135. return;
  136. }
  137. NSData * data = [string dataUsingEncoding:NSUTF8StringEncoding];
  138. NSDictionary * inviteDict = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
  139. if (inviteDict!=nil){
  140. //字典取值
  141. NSDictionary * invite = [inviteDict objectForKey:@"invite"];
  142. NSDictionary * user = [invite objectForKey:@"user"];
  143. //user字典 -> 字符串 -> Char
  144. NSData * userData = [NSJSONSerialization dataWithJSONObject:user options:NSJSONWritingPrettyPrinted error:nil];
  145. NSString * userString = [[NSString alloc] initWithData:userData encoding:NSUTF8StringEncoding];
  146. const char * userChar =[userString UTF8String];
  147. //info字符串 -> Char
  148. NSString * infoString = invite[@"info"];
  149. const char * infoChar =[infoString UTF8String];
  150. NSLog(@"IOS_SKD 回调好友邀请信息 GetInviteInfo ===>> %s , %s",userChar,infoChar);
  151. [[IOSPlatformSDK sharedInstance] bridgingInvite:0 userChar:userChar infoChar:infoChar];
  152. }
  153. }
  154. #pragma mark ===============================================>> public method
  155. -(void)startWithUrl:(NSURL*)url{//
  156. if (url==nil){
  157. return;
  158. }
  159. NSString * urlString = [url absoluteString];
  160. NSArray * stringArr = [urlString componentsSeparatedByString:@"//"];
  161. if (stringArr == nil || stringArr.count<2){
  162. return;
  163. }
  164. NSString * arr2 = stringArr[1];
  165. NSString* finsalString = [arr2 stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
  166. NSDictionary * urlDict = [AlgorithmTool dictionaryWithJsonString:finsalString];
  167. NSLog(@"Schemes_Url转码的dict ========= %@",urlDict);
  168. //缓存用户信息数据
  169. [IOS_NSUSERDEFAULT setObject:urlDict forKey:IOSSDK_USERINFO];
  170. [IOS_NSUSERDEFAULT synchronize];
  171. //界面还没加载完毕 弹窗会导致奔溃
  172. // //检查有没有好友邀请信息
  173. // const char * userChar = [[CacheTool getInviteUser] UTF8String];
  174. // const char * infoChar =[[CacheTool getInviteInfo] UTF8String];
  175. // if (infoChar!=nil&&strlen(infoChar)>1) {
  176. // [[IOSPlatformSDK sharedInstance] bridgingInvite:0 userChar:userChar infoChar:infoChar];
  177. // }
  178. //主副设备:deviceType 游戏种类:game_type mac地址:macAddress
  179. self.game_info.deviceType = DEVICETYPE_MAIN;
  180. self.game_info.game_type = (GAME_TYPE)[[CacheTool getGameType] intValue];
  181. self.game_info.vibrate = [CacheTool getGameVibrate];
  182. self.game_info.debug = [CacheTool getGameDebug];
  183. //重置mac
  184. self.shoes_info.macAddress = [CacheTool getGameMac];
  185. self.shoes_info.viceMacAddress = @"";
  186. //链接蓝牙
  187. [self newCentralManagerOrScan];
  188. }
  189. //unity call instance弹出蓝牙搜索框
  190. -(void)searchBLEAction:(int)type{
  191. //初始化蓝牙CBCentralManager
  192. [self newCentralManagerOrScan];
  193. //搜索蓝牙外设弹窗
  194. if (self.searchDeviceVC!=nil){
  195. self.searchDeviceVC=nil;
  196. }
  197. self.searchDeviceVC = [SearchDeviceViewController new];
  198. self.isPopUp = YES;
  199. [[UIApplication sharedApplication].keyWindow addSubview:self.searchDeviceVC.view];
  200. //点击searchVC的tableViewCell链接选中的蓝牙
  201. __weak __typeof(self)weakself = self;
  202. self.searchDeviceVC.connectDeviceBlock = ^(CBPeripheral * peripheral){
  203. //主副设备:deviceType 游戏种类:game_type mac地址:macAddress
  204. weakself.game_info.game_type = (GAME_TYPE)[[CacheTool getGameType] intValue];
  205. weakself.game_info.deviceType = (DEVICE_TYPE)type;
  206. if (type == 0) {
  207. weakself.shoes_info.macAddress = peripheral.identifier.UUIDString;
  208. }else if (type ==1){
  209. weakself.shoes_info.viceMacAddress = peripheral.identifier.UUIDString;
  210. }
  211. [weakself connectBLEManagerData:peripheral];
  212. };
  213. self.searchDeviceVC.closeBlock = ^{
  214. weakself.isPopUp = NO;
  215. };
  216. }
  217. //unity call instance弹出 好友列表 搜索框 (int code, char * info)
  218. -(void)showInviteFriend:(int)code inviteInof:(NSString*)inviteInof{
  219. //搜索蓝牙外设弹窗
  220. if (self.friendsListVC!=nil){
  221. self.friendsListVC=nil;
  222. }
  223. self.friendsListVC = [FriendsListViewController new];
  224. self.isPopUp = YES;
  225. [[UIApplication sharedApplication].keyWindow addSubview:self.friendsListVC.view];
  226. [MBProgressHUD showHUDAddedTo:self.friendsListVC.view animated:YES];
  227. [HTTPDataProcession getFriendsList:^(int code, const char *jsonString, NSMutableArray *dataArr){
  228. NSLog(@"IOS_SKD 回调好友列表 GetUserFriends 数组 ===> %@",dataArr);
  229. self.friendsListVC.friendsArray = dataArr;
  230. //主线程
  231. dispatch_async(dispatch_get_main_queue(), ^{
  232. [MBProgressHUD hideHUDForView:self.friendsListVC.view animated:YES];
  233. [self.friendsListVC reloadData];
  234. });
  235. }];
  236. //点击searchVC的tableViewCell链接选中的蓝牙
  237. __weak __typeof(self)weakself = self;
  238. self.friendsListVC.inviteFriendBlock = ^(UserFriendsModel *model){
  239. [HTTPDataProcession inviteFriends:model.trans_id inviteInfo:inviteInof inviteDataBlock:^(NSString *jsonString){
  240. // NSLog(@"IOS_SKD 回调点击邀请好友事件 InviteFriend ===>>");
  241. dispatch_async(dispatch_get_main_queue(), ^{
  242. [PopupView showCusHUDA:jsonString];
  243. });
  244. }];
  245. };
  246. self.friendsListVC.closeBlock = ^{
  247. // NSLog(@"设置 weakself.isPopUp = NO");
  248. weakself.isPopUp = NO;
  249. };
  250. //
  251. }
  252. //每重新开始一局游戏
  253. -(void)gameStartInitData{
  254. //当局游戏持续时间
  255. self.game_info.firstTime = [NSDate date];
  256. //游戏模式 ==>> 回调剑波sdk数据
  257. self.shoes_info.gameModel = YES;
  258. //读写到特征后 添加测试弹窗
  259. dispatch_async(dispatch_get_main_queue(), ^{
  260. [DebugViewInstance notificationStartGame];
  261. });
  262. }
  263. //每结束一局游戏
  264. -(void)gameEndInitData{
  265. self.shoes_info.gameModel = NO;
  266. if ([self.game_info.debug intValue] == 1) {
  267. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(),^{
  268. [DebugViewInstance uploadpPlistFile];
  269. });
  270. }
  271. }
  272. //监听unity通知震动
  273. -(void)vibrationAction:(int)type duration:(int)duration leftOrRight:(int)leftOrRight{
  274. if ([self.game_info.vibrate intValue] == 1) {
  275. [BTDataSendInstance vibration:(DEVICE_TYPE)type duration:duration leftOrRight:leftOrRight];
  276. }
  277. }
  278. #pragma mark ===============================================>> leon Ble manager
  279. //自己封装的蓝牙类
  280. -(void)newCentralManagerOrScan{
  281. if (LEManager.centralManager == nil && LEManager.peripheral == nil && LEManager.vicePeripheral == nil){
  282. NSLog(@" ====================>> 未初始化 centralManager 直接开始初始化");
  283. [LEManager initCBCentralManager];
  284. }else{
  285. [self ifHasLinks];
  286. }
  287. //每次 initCBCentralManager 走以下回调
  288. LEManager.stateUpdateBlock = ^(CBCentralManager * central){
  289. switch(central.state){
  290. case 0:
  291. NSLog(@"当前的蓝牙状态 ===>> CBCentralManagerStateUnknown");
  292. break;
  293. case 1:
  294. NSLog(@"当前的蓝牙状态 ===>> CBCentralManagerStateResetting");
  295. break;
  296. case 2:
  297. NSLog(@"当前的蓝牙状态 ===>> CBCentralManagerStateUnsupported");
  298. break;
  299. case 3:
  300. NSLog(@"当前的蓝牙状态 ===>> CBCentralManagerStateUnauthorized");
  301. break;
  302. case 4:{
  303. NSLog(@"当前的蓝牙状态 ===>> 蓝牙已关闭");
  304. if (LEManager.peripheral!=nil){
  305. [[IOSPlatformSDK sharedInstance] bridgingDeviceAction:DEVICETYPE_MAIN
  306. name:LEManager.peripheral.name
  307. address:LEManager.peripheral.identifier.UUIDString
  308. status:CONNECT_LOST
  309. electricity:0];
  310. }
  311. if (LEManager.vicePeripheral!=nil){
  312. [[IOSPlatformSDK sharedInstance] bridgingDeviceAction:DEVICETYPE_VICE
  313. name:LEManager.vicePeripheral.name
  314. address:LEManager.vicePeripheral.identifier.UUIDString
  315. status:CONNECT_LOST
  316. electricity:0];
  317. }
  318. }
  319. break;
  320. case 5:{
  321. NSLog(@"当前的蓝牙状态 ===>> 蓝牙已开启");//蓝牙已开启
  322. [self ifHasLinks];
  323. }
  324. break;
  325. default:
  326. break;
  327. }
  328. };
  329. [self.deviceArray removeAllObjects];
  330. //发现蓝牙
  331. LEManager.discoverPeripheralBlock = ^(CBCentralManager * _Nonnull central, CBPeripheral * _Nonnull peripheral, NSDictionary * _Nonnull advertisementData, NSNumber * _Nonnull RSSI){
  332. // NSLog(@"扫描发现蓝牙设备advertisementData = %@",advertisementData);
  333. NSString *advertiseName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey];
  334. NSData * manufacturerData = [advertisementData objectForKey:CBAdvertisementDataManufacturerDataKey];
  335. Byte *testByte = (Byte *)[manufacturerData bytes];
  336. if (testByte!=nil) {
  337. NSInteger byteLength = sizeof(testByte);
  338. NSString * byteString;
  339. for (int i = 0; i < byteLength; i++){
  340. int index = testByte[i];
  341. byteString = [NSString stringWithFormat:@"%@,%d",byteString,index];
  342. }
  343. NSLog(@" byteString ====================>> %@",byteString);
  344. }
  345. // NSLog(@"扫描发现蓝牙设备advertisementDataManufacturerData = %@",manufacturerData);
  346. peripheral.advertiseName = advertiseName;
  347. if ([advertiseName hasPrefix:@"SH_"]||[advertiseName hasPrefix:@"fun_"]||[advertiseName hasPrefix:@"Fun_"]||[advertiseName hasPrefix:@"FUN_"]){//SH_DANCE BLE_LOOP Shoes_4530 Shoes_2A74
  348. // NSLog(@"主设备扫描发现有效的蓝牙设备 =============== %@ identifier == %@",peripheral.name,peripheral.identifier.UUIDString);
  349. if (self.deviceArray.count == 0){//数据源为0
  350. [self.deviceArray addObject:peripheral];
  351. //判断扫描到外设之后是否要链接蓝牙
  352. [self judgeConnect:peripheral];
  353. }else{
  354. BOOL isExist = NO;
  355. for (int i = 0; i < self.deviceArray.count; i++){
  356. CBPeripheral *per = [self.deviceArray objectAtIndex:i];
  357. if ([per.identifier.UUIDString isEqualToString:peripheral.identifier.UUIDString]){
  358. isExist = YES;
  359. [self.deviceArray replaceObjectAtIndex:i withObject:peripheral];
  360. }
  361. }
  362. if (!isExist){
  363. [self.self.deviceArray addObject:peripheral];
  364. //判断扫描到外设之后是否要链接蓝牙
  365. [self judgeConnect:peripheral];
  366. }
  367. }
  368. //数据回调给 搜索蓝牙弹窗
  369. self.searchDeviceVC.deviceArray = self.deviceArray;
  370. [self.searchDeviceVC reloadData];
  371. }
  372. };
  373. }
  374. #pragma mark ===============================================>> 主设备蓝牙数据
  375. //扫描还是直链
  376. -(void)ifHasLinks{
  377. [LEManager stopScan];
  378. // //已经被系统或者其他APP连接上的设备数组
  379. // NSArray *arr = [LEManager.centralManager retrieveConnectedPeripheralsWithServices:@[[CBUUID UUIDWithString:@"6E400001-B5A3-F393-E0A9-E50E24DCCA9E"]]];
  380. //
  381. // if (arr.count>0) {//已经链了一双鞋子了
  382. //
  383. // NSLog(@" ====================>> 已初始化 centralManager 有已经链接的鞋子");
  384. // //UUID是外设的服务UUID,满足UUID 的外设就会放在数组中
  385. // [arr enumerateObjectsUsingBlock:^(CBPeripheral *peripheral, NSUInteger idx, BOOL *stop){
  386. //
  387. // if ([peripheral.name hasPrefix:@"SH_"]){//SH_DANCE BLE_LOOP Shoes_4530 Shoes_2A74
  388. //
  389. // NSLog(@"主设备 已经链接到的 蓝牙设备 =============== %@ identifier == %@",peripheral.name,peripheral.identifier.UUIDString);
  390. //
  391. // LEManager.peripheral = peripheral;
  392. //
  393. // [self connectPeripheral:LEManager.peripheral];
  394. //
  395. // }
  396. //
  397. // }];
  398. //
  399. // }else{
  400. NSLog(@" ====================>> 已初始化 centralManager 直接开扫描");
  401. [LEManager scanForPeripheralsWithServices:nil options:nil];
  402. // }
  403. }
  404. //app跳转 断线重连 从后台返回
  405. -(void)judgeConnect:(CBPeripheral*)peripheral{
  406. // NSLog(@"self.shoes_info.macAddress = %@ peripheral.identifier.UUIDString = %@",self.shoes_info.macAddress,peripheral.identifier.UUIDString);
  407. if (self.shoes_info.macAddress.length>12 && [peripheral.identifier.UUIDString isEqualToString:self.shoes_info.macAddress]){
  408. self.game_info.deviceType = DEVICETYPE_MAIN;
  409. [self connectBLEManagerData:peripheral];
  410. }
  411. if (self.shoes_info.viceMacAddress.length>12 && [peripheral.identifier.UUIDString isEqualToString:self.shoes_info.viceMacAddress]){
  412. self.game_info.deviceType = DEVICETYPE_VICE;
  413. [self connectBLEManagerData:peripheral];
  414. }//
  415. }
  416. #pragma mark ===============================================>> public 链接蓝牙
  417. //搜索弹窗 点击
  418. //链接蓝牙
  419. -(void)connectBLEManagerData:(CBPeripheral*)peripheral{
  420. NSLog(@"peripheral.name ==>> %@",peripheral.name);
  421. if(instance == NULL || peripheral == NULL){return;}
  422. 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);
  423. //初始化运轨sdk
  424. if (self.game_info.deviceType==DEVICETYPE_MAIN){
  425. LEManager.peripheral = peripheral;
  426. game = new Game(self.game_info.game_type);
  427. //开始链接动画
  428. [[MainLoadingView shanreAnimationView] addAnimation];
  429. }else if (self.game_info.deviceType == DEVICETYPE_VICE){
  430. LEManager.vicePeripheral = peripheral;
  431. viceDeviceGame = new Game(self.game_info.game_type);
  432. //开始链接动画
  433. [[ViceLoadingView shanreAnimationView] addAnimation];
  434. }
  435. //链接蓝牙 此时 LEManager.peripheral || LEManager.vicePeripheral 还未init
  436. [LEManager connectPeripheral:peripheral options:nil];
  437. //蓝牙连接成功
  438. LEManager.successfulBlock = ^(CBPeripheral * _Nonnull peripheral){
  439. if (self.shoes_info.macAddress.length>12 && self.shoes_info.viceMacAddress.length == 0){//有主没副
  440. if (LEManager.peripheral.state == CBPeripheralStateConnected){//主设备已经连接上后 停止扫描
  441. NSLog(@"主设备蓝牙链接成功");
  442. [LEManager stopScan];
  443. }
  444. }else if(self.shoes_info.macAddress.length == 0 && self.shoes_info.viceMacAddress.length >12){//没主有副
  445. if (LEManager.vicePeripheral.state == CBPeripheralStateConnected){//副设备已经连接上后 停止扫描
  446. NSLog(@"副设备蓝牙链接成功");
  447. [LEManager stopScan];
  448. }
  449. }else if(self.shoes_info.macAddress.length>12 && self.shoes_info.viceMacAddress.length > 12){//有主有副
  450. if (LEManager.peripheral.state == CBPeripheralStateConnected && LEManager.vicePeripheral.state == CBPeripheralStateConnected){//主和副设备都已经连接上后 停止扫描
  451. NSLog(@"主设备 和 副设备 蓝牙链接成功");
  452. [LEManager stopScan];
  453. }
  454. }
  455. };
  456. //蓝牙连接失败
  457. LEManager.connectFailureBlock = ^(NSError * _Nonnull error){
  458. NSLog(@"蓝牙链接失败");
  459. };
  460. //蓝牙连接丢失
  461. LEManager.disConnectBlock = ^(CBPeripheral * _Nonnull peripheral, NSError * _Nonnull error){
  462. if (LEManager.peripheral!=nil && peripheral==LEManager.peripheral){
  463. [[IOSPlatformSDK sharedInstance] bridgingDeviceAction:DEVICETYPE_MAIN
  464. name:LEManager.peripheral.name
  465. address:LEManager.peripheral.identifier.UUIDString
  466. status:CONNECT_LOST
  467. electricity:0];
  468. if (self.shoes_info.macAddress.length>12){
  469. NSLog(@"主设备 蓝牙链接断开 被动断开 需要重连");
  470. [self newCentralManagerOrScan];
  471. }else{
  472. NSLog(@"主设备 蓝牙链接断开 主动断开 不需重连");
  473. }
  474. }
  475. if (LEManager.vicePeripheral!=nil && peripheral==LEManager.vicePeripheral){
  476. [[IOSPlatformSDK sharedInstance] bridgingDeviceAction:DEVICETYPE_VICE
  477. name:LEManager.vicePeripheral.name
  478. address:LEManager.vicePeripheral.identifier.UUIDString
  479. status:CONNECT_LOST
  480. electricity:0];
  481. //副设备 断线 手动断开的话不用重连,自动断开的要重连
  482. if (self.shoes_info.viceMacAddress.length>12){
  483. NSLog(@"副设备 蓝牙链接断开 被动断开 需要重连");
  484. [self newCentralManagerOrScan];
  485. }else{
  486. NSLog(@"副设备 蓝牙链接断开 主动断开 不需重连");
  487. }
  488. }
  489. };
  490. //发现服务和特征
  491. LEManager.discoverCharacteristicsBlock = ^(CBPeripheral * _Nonnull peripheral, CBService * _Nonnull service, NSArray * _Nonnull characteristics, NSError * _Nonnull error){
  492. if (peripheral==LEManager.peripheral){//主设备
  493. for (CBCharacteristic * cha in service.characteristics){
  494. if (cha.properties == 12){//写
  495. LEManager.write = cha;
  496. //获取到写的特征后才能向 主设备 蓝牙对象写入数据
  497. [self startGameModeAndQueryDevideInfo];
  498. //链接成功震动一次
  499. [BTDataSendInstance vibration:DEVICETYPE_MAIN duration:400 leftOrRight:0];
  500. [self initTimer];
  501. }else if (cha.properties == 16){//读
  502. LEManager.read = cha;
  503. [LEManager.peripheral readValueForCharacteristic:cha];
  504. [LEManager.peripheral setNotifyValue:YES forCharacteristic:cha];
  505. }
  506. }
  507. }else if (peripheral==LEManager.vicePeripheral){//副设备
  508. for (CBCharacteristic * cha in service.characteristics){
  509. if (cha.properties == 12){//写
  510. LEManager.viceWrite = cha;
  511. //获取到写的特征后才能向 副设备 蓝牙对象写入数据
  512. [self startGameModeAndQueryDevideInfo];
  513. //链接成功震动一次
  514. [BTDataSendInstance vibration:DEVICETYPE_VICE duration:400 leftOrRight:0];
  515. }else if (cha.properties == 16){//读
  516. LEManager.viceRead = cha;
  517. [LEManager.vicePeripheral readValueForCharacteristic:cha];
  518. [LEManager.vicePeripheral setNotifyValue:YES forCharacteristic:cha];
  519. }
  520. }
  521. }
  522. };
  523. //读取特征的报文数据
  524. LEManager.readValueForCharacteristicBlock = ^(CBPeripheral * _Nonnull peripheral, CBCharacteristic * _Nonnull characteristic, NSData * _Nonnull value, NSError * _Nonnull error){
  525. // NSLog(@"characteristic.value = %@ characteristic.UUID.UUIDString = %@",characteristic.value,characteristic.UUID.UUIDString);
  526. if ([characteristic.UUID.UUIDString isEqualToString:@"6E400003-B5A3-F393-E0A9-E50E24DCCA9E"]){//判断是不是我们设备
  527. //每收到数据包读取一次蓝牙RSSI 无论1秒内请求多少次rssi值,原生api每秒都最多返回一次RSSI
  528. [peripheral readRSSI];
  529. //带cmd位的有效数据 计算校验位
  530. if ([AlgorithmTool verificationRusult:characteristic.value]==YES){
  531. int dataType = [AlgorithmTool dataToChar:[characteristic.value subdataWithRange:NSMakeRange(3, 1)]];//cmd类型
  532. if (dataType == 4){//鞋子游戏数据
  533. if (characteristic.value.length < 64){ return; }
  534. //数据丢给算法计算轨迹
  535. if (peripheral==LEManager.peripheral&&LEManager.main_read == 0){
  536. // NSLog(@"LEManager.main_read = %d",LEManager.main_read);
  537. // NSLog(@"主设备 读取特征的报文 游戏数据 %ld dataType = %d %@",(long)type,dataType,characteristic.value);
  538. [[MainLoadingView shanreAnimationView] stopAnimation];
  539. LEManager.main_read = 1;
  540. [self shoseSDK:characteristic.value];
  541. }else if (peripheral==LEManager.vicePeripheral&&LEManager.vice_read == 0){
  542. [[ViceLoadingView shanreAnimationView] stopAnimation];
  543. LEManager.vice_read = 1;
  544. [self viceShoseSDK:characteristic.value];
  545. }
  546. }else if(dataType == -95){//鞋子状态信息
  547. if (characteristic.value.length<30){ return; }
  548. //嵌入式原始数据解析 --->> 回调蓝牙状态/电量给unity
  549. BTDataAnalysis * anly = [BTDataAnalysis new];
  550. [anly analysisCharacteristic:characteristic.value peripheral:peripheral];
  551. }
  552. }
  553. }
  554. };
  555. //蓝牙更新RSSI
  556. LEManager.rssiBlock = ^(NSNumber * _Nonnull RSSI){
  557. LEManager.RSSI = RSSI;
  558. };
  559. }
  560. #pragma mark ===============================================>> 读取特征后 鞋子打开游戏模式 & 激光开关 &查询鞋子蓝牙状态 & 主设备初始化缓存游戏步数
  561. //init定时器
  562. -(void)initTimer{
  563. //定时开启游戏模式 & 查询设备信息 & 开启激光检测下蹲
  564. if (self.timer!=nil){
  565. [self.timer invalidate];
  566. self.timer = nil;
  567. }
  568. self.timer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(startGameModeAndQueryDevideInfo) userInfo:nil repeats:YES];
  569. [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
  570. }
  571. //定时发送数据
  572. -(void)startGameModeAndQueryDevideInfo{
  573. //开启游戏模式&查询设备信息 初始化步数数据 (防止读取到的读写为空 延迟0.5s)
  574. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(),^{
  575. if (self.game_info.isBackGround){//程序在后台
  576. }else{//程序在前台
  577. [BTDataSendInstance startGameModel];
  578. [BTDataSendInstance queryDevideInfo];
  579. [BTDataSendInstance keepConnect];
  580. }
  581. });
  582. }
  583. #pragma mark ===============================================>> 主设备 报文数据解析后 -- 调用蓝牙鞋子SDK装换数据 -- ios call unity 更新游戏动作
  584. -(void)shoseSDK:(NSData*)characteristic{
  585. // NSLog(@"characteristic = %@",characteristic);
  586. /********************初始化 运动轨迹算法 SDK *****************/
  587. NSData * validData= [characteristic subdataWithRange:NSMakeRange(4, characteristic.length-4)];
  588. Byte * buff = (Byte*)[validData bytes];
  589. game->GameProcessBuf(buff, (int)validData.length);
  590. if (self.shoes_info.gameModel==YES){//当前是游戏模式
  591. /********************剑波 & 威严 要的图表数据 *****************/
  592. NSString * message = [NSString stringWithUTF8String:game->getGameDataStr().c_str()];
  593. [DebugViewInstance debugMessage:message shoesInfo:self.shoes_info];
  594. }
  595. /******************左右脚动作数据处理 + 回调*****************/
  596. int length = 10;
  597. int result[length];
  598. game->getGameResult(result);
  599. int motionLeft = result[0];//左脚的动作
  600. int motionRight = result[1];//右脚的动作
  601. int motionJump = result[2];//jump
  602. int motionDown = result[3];//down
  603. // //无效动作 过滤无效动作会导致步频加速无效
  604. // if (motionLeft==-1 && motionRight == -1&& motionJump == -1&& motionDown == -1){
  605. // return;
  606. // }
  607. //跳跃和蹲下的动作 双脚是同步的
  608. if (motionJump == MOTION_JUMP||motionJump == MOTION_JUMP_OC||motionJump == MOTION_JUMP_VERTICAL){
  609. motionLeft = motionJump;
  610. motionRight = motionJump;
  611. }
  612. if (motionDown == MOTION_DOWN){
  613. motionLeft = motionDown;
  614. motionRight = motionDown;
  615. }
  616. /******************当局游戏 鞋子子动作状态数据 缓存*****************/
  617. self.shoes_info.leftStepStatus = game->getStepStatus(LEFT_FOOT);
  618. self.shoes_info.leftStepFreq = game->getStepFreq(LEFT_FOOT);
  619. self.shoes_info.leftStepCount = game->getStepCount(LEFT_FOOT);
  620. self.shoes_info.rightStepStatus = game->getStepStatus(RIGHT_FOOT);
  621. self.shoes_info.rightStepFreq = game->getStepFreq(RIGHT_FOOT);
  622. self.shoes_info.rightStepCount = game->getStepCount(RIGHT_FOOT);
  623. [self cacheAllMotionCount];
  624. /******************鞋子动作状态数据 实时回调*****************/
  625. //左右脚动作:所有游戏都需要回调
  626. [[IOSPlatformSDK sharedInstance] bridgingMotionAction:DEVICETYPE_MAIN left:motionLeft right:motionRight];
  627. //步频状态:只有跑酷回调
  628. if (self.game_info.game_type == GAME_TYPE_RUN||self.game_info.game_type == GAME_TYPE_CYCLE){
  629. [[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];
  630. }
  631. //人物朝向 只有 三轮车 需要
  632. if (self.game_info.game_type == GAME_TYPE_CYCLE){
  633. int attLength = 3;
  634. int left[attLength];
  635. int right[attLength];
  636. game->getFootAtt(left, right);
  637. self.main_nativeAttX = left[0];
  638. // NSLog(@"self.nativeAttX = %d",self.nativeAttX);
  639. }
  640. /******************脚步交互数据 实时回调*****************/
  641. int interaction = game->getInteractionCMD();
  642. if (interaction==-1){
  643. return;
  644. }
  645. //自定义弹窗界面交互
  646. if (self.isPopUp == YES){
  647. NSLog(@"BTDataProcess 有效交互动作 ===>> %d",interaction);
  648. [self.searchDeviceVC getInteraction:interaction];
  649. [self.friendsListVC getInteraction:interaction];
  650. }else{
  651. //游戏界面交互
  652. [[IOSPlatformSDK sharedInstance] bridgingInteraction:DEVICETYPE_MAIN code:interaction];
  653. }
  654. }
  655. #pragma mark ===============================================>>副设备 报文数据解析后 -- 调用蓝牙鞋子SDK装换数据 -- ios call unity 更新游戏动作
  656. -(void)viceShoseSDK:(NSData*)characteristic{
  657. /********************初始化 运动轨迹算法 SDK *****************/
  658. //游戏数据
  659. NSData * validData= [characteristic subdataWithRange:NSMakeRange(4, characteristic.length-4)];
  660. Byte * buff = (Byte*)[validData bytes];
  661. viceDeviceGame->GameProcessBuf(buff, (int)validData.length);
  662. //当前是游戏模式
  663. // if (self.shoes_info.gameModel==YES){
  664. /******************左右脚动作数据处理 + 回调*****************/
  665. int length = 10;
  666. int result[length];
  667. viceDeviceGame->getGameResult(result);
  668. int motionLeft = result[0];//左脚的动作
  669. int motionRight = result[1];//右脚的动作
  670. int ivce_motionJump = result[2];//jump
  671. int ivce_motionDown = result[3];//down
  672. //跳跃和蹲下的动作 双脚是同步的
  673. if (ivce_motionJump == MOTION_JUMP||ivce_motionJump == MOTION_JUMP_OC||ivce_motionJump == MOTION_JUMP_VERTICAL){
  674. motionLeft = ivce_motionJump;
  675. motionRight = ivce_motionJump;
  676. }
  677. if (ivce_motionDown == MOTION_DOWN){
  678. motionLeft = ivce_motionDown;
  679. motionRight = ivce_motionDown;
  680. }
  681. /******************当局游戏 鞋子子动作状态数据 缓存*****************/
  682. int leftStepStatus = viceDeviceGame->getStepStatus(LEFT_FOOT);
  683. int leftStepFreq = viceDeviceGame->getStepFreq(LEFT_FOOT);
  684. // int leftStepCount = viceDeviceGame->getStepCount(LEFT_FOOT);
  685. int rightStepStatus = viceDeviceGame->getStepStatus(RIGHT_FOOT);
  686. int rightStepFreq = viceDeviceGame->getStepFreq(RIGHT_FOOT);
  687. // int rightStepCount = viceDeviceGame->getStepCount(RIGHT_FOOT);
  688. /******************鞋子动作状态数据 实时回调*****************/
  689. //左右脚动作:所有游戏都需要回调
  690. [[IOSPlatformSDK sharedInstance] bridgingMotionAction:DEVICETYPE_VICE left:motionLeft right:motionRight];
  691. //步频:跑酷和三轮车
  692. if (self.game_info.game_type == GAME_TYPE_RUN||self.game_info.game_type == GAME_TYPE_CYCLE){
  693. [[IOSPlatformSDK sharedInstance] bridgingStepAction:DEVICETYPE_VICE leftStatus:leftStepStatus rightStatus:rightStepStatus leftFrag:leftStepFreq rightFrag:rightStepFreq];
  694. }
  695. //人物朝向:三轮车
  696. if (self.game_info.game_type == GAME_TYPE_CYCLE){
  697. int attLength = 3;
  698. int left[attLength];
  699. int right[attLength];
  700. viceDeviceGame->getFootAtt(left, right);
  701. self.vice_nativeAttX = left[0];
  702. }
  703. // }
  704. /******************脚步交互数据 实时回调*****************/
  705. int interaction = viceDeviceGame->getInteractionCMD();
  706. if (interaction==-1){
  707. return;
  708. }
  709. if (self.isPopUp == YES){//自定义弹窗界面交互
  710. }else{
  711. //游戏界面交互
  712. [[IOSPlatformSDK sharedInstance] bridgingInteraction:DEVICETYPE_VICE code:interaction];
  713. }
  714. }
  715. #pragma mark ===============================================>> 懒加载 -- 蓝牙设备数据源
  716. -(NSMutableArray*)deviceArray{
  717. if (!_deviceArray){
  718. _deviceArray = [NSMutableArray new];
  719. }
  720. return _deviceArray;;
  721. }
  722. #pragma mark ===============================================>> 玩游戏过程中缓存 动作数据 和时间戳 数据存入plist
  723. -(void)cacheAllMotionCount{
  724. //总数
  725. int total_step_count = game->getMotionCount(STEP_COUNT) - self.game_info.step;
  726. int total_jump_count = game->getMotionCount(JUMP_COUNT) - self.game_info.jump;
  727. int total_crouch_count = game->getMotionCount(DOWN_COUNT) - self.game_info.crouch;
  728. int total_tick_count = game->getMotionCount(KICK_COUNT) - self.game_info.tick;
  729. int total_paper_count = game->getMotionCount(PAPER_COUNT) - self.game_info.paper;
  730. int total_scissors_count = game->getMotionCount(SCISSORS_COUNT) - self.game_info.scissors;
  731. int total_rock_count = game->getMotionCount(ROCK_COUNT) - self.game_info.rock;
  732. // int total_trample_count = game->getMotionCount(ROCK_COUNT) - self.game_info.trample;
  733. // 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);
  734. //缓存pilst文件
  735. NSMutableDictionary * motionCountObj = [NSMutableDictionary new];
  736. [motionCountObj setObject:[NSNumber numberWithInt:total_step_count] forKey:@"step"];
  737. [motionCountObj setObject:[NSNumber numberWithInt:total_jump_count] forKey:@"jump"];
  738. [motionCountObj setObject:[NSNumber numberWithInt:total_crouch_count] forKey:@"crouch"];
  739. [motionCountObj setObject:[NSNumber numberWithInt:total_tick_count] forKey:@"tick"];
  740. [motionCountObj setObject:[NSNumber numberWithInt:total_paper_count] forKey:@"paper"];
  741. [motionCountObj setObject:[NSNumber numberWithInt:total_scissors_count] forKey:@"scissors"];
  742. [motionCountObj setObject:[NSNumber numberWithInt:total_rock_count] forKey:@"rock"];
  743. [motionCountObj setObject:[NSNumber numberWithInt:0] forKey:@"trample"];
  744. NSMutableDictionary * movements = [NSMutableDictionary new];
  745. [movements setObject:motionCountObj forKey:@"movements"];
  746. //游戏总共经历的时长(秒数)
  747. NSTimeInterval durationTime = [[NSDate date] timeIntervalSinceDate:self.game_info.firstTime];
  748. [movements setObject:[NSNumber numberWithInt:durationTime] forKey:@"duration"];
  749. //时间戳
  750. [movements setObject: self.shoes_info.timestamp forKey:@"play_group"];
  751. NSDictionary * dict = [NSDictionary dictionaryWithDictionary:movements];
  752. //归档缓存
  753. [IOS_NSUSERDEFAULT setObject:dict forKey:IOSSDK_MOTIONCOUNT];
  754. [IOS_NSUSERDEFAULT synchronize];
  755. }
  756. @end