BTDataProcess.mm 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946
  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. // NSLog(@"advertisementData ========= %@ %@",peripheral.name,advertiseName);
  335. peripheral.advertiseName = advertiseName;
  336. if ([advertiseName hasPrefix:@"SH_"]||[advertiseName hasPrefix:@"fun_"]||[advertiseName hasPrefix:@"Fun_"]||[advertiseName hasPrefix:@"FUN_"]){//SH_DANCE BLE_LOOP Shoes_4530 Shoes_2A74
  337. // NSLog(@"主设备扫描发现有效的蓝牙设备 =============== %@ identifier == %@",peripheral.name,peripheral.identifier.UUIDString);
  338. if (self.deviceArray.count == 0){//数据源为0
  339. [self.deviceArray addObject:peripheral];
  340. //判断扫描到外设之后是否要链接蓝牙
  341. [self judgeConnect:peripheral];
  342. }else{
  343. BOOL isExist = NO;
  344. for (int i = 0; i < self.deviceArray.count; i++){
  345. CBPeripheral *per = [self.deviceArray objectAtIndex:i];
  346. if ([per.identifier.UUIDString isEqualToString:peripheral.identifier.UUIDString]){
  347. isExist = YES;
  348. [self.deviceArray replaceObjectAtIndex:i withObject:peripheral];
  349. }
  350. }
  351. if (!isExist){
  352. [self.self.deviceArray addObject:peripheral];
  353. //判断扫描到外设之后是否要链接蓝牙
  354. [self judgeConnect:peripheral];
  355. }
  356. }
  357. //数据回调给 搜索蓝牙弹窗
  358. self.searchDeviceVC.deviceArray = self.deviceArray;
  359. [self.searchDeviceVC reloadData];
  360. }
  361. };
  362. }
  363. #pragma mark ===============================================>> 主设备蓝牙数据
  364. //扫描还是直链
  365. -(void)ifHasLinks{
  366. [LEManager stopScan];
  367. // //已经被系统或者其他APP连接上的设备数组
  368. // NSArray *arr = [LEManager.centralManager retrieveConnectedPeripheralsWithServices:@[[CBUUID UUIDWithString:@"6E400001-B5A3-F393-E0A9-E50E24DCCA9E"]]];
  369. //
  370. // if (arr.count>0) {//已经链了一双鞋子了
  371. //
  372. // NSLog(@" ====================>> 已初始化 centralManager 有已经链接的鞋子");
  373. // //UUID是外设的服务UUID,满足UUID 的外设就会放在数组中
  374. // [arr enumerateObjectsUsingBlock:^(CBPeripheral *peripheral, NSUInteger idx, BOOL *stop){
  375. //
  376. // if ([peripheral.name hasPrefix:@"SH_"]){//SH_DANCE BLE_LOOP Shoes_4530 Shoes_2A74
  377. //
  378. // NSLog(@"主设备 已经链接到的 蓝牙设备 =============== %@ identifier == %@",peripheral.name,peripheral.identifier.UUIDString);
  379. //
  380. // LEManager.peripheral = peripheral;
  381. //
  382. // [self connectPeripheral:LEManager.peripheral];
  383. //
  384. // }
  385. //
  386. // }];
  387. //
  388. // }else{
  389. NSLog(@" ====================>> 已初始化 centralManager 直接开扫描");
  390. [LEManager scanForPeripheralsWithServices:nil options:nil];
  391. // }
  392. }
  393. //app跳转 断线重连 从后台返回
  394. -(void)judgeConnect:(CBPeripheral*)peripheral{
  395. // NSLog(@"self.shoes_info.macAddress = %@ peripheral.identifier.UUIDString = %@",self.shoes_info.macAddress,peripheral.identifier.UUIDString);
  396. if (self.shoes_info.macAddress.length>12 && [peripheral.identifier.UUIDString isEqualToString:self.shoes_info.macAddress]){
  397. self.game_info.deviceType = DEVICETYPE_MAIN;
  398. [self connectBLEManagerData:peripheral];
  399. }
  400. if (self.shoes_info.viceMacAddress.length>12 && [peripheral.identifier.UUIDString isEqualToString:self.shoes_info.viceMacAddress]){
  401. self.game_info.deviceType = DEVICETYPE_VICE;
  402. [self connectBLEManagerData:peripheral];
  403. }//
  404. }
  405. #pragma mark ===============================================>> public 链接蓝牙
  406. //搜索弹窗 点击
  407. //链接蓝牙
  408. -(void)connectBLEManagerData:(CBPeripheral*)peripheral{
  409. NSLog(@"peripheral.name ==>> %@",peripheral.name);
  410. if(instance == NULL || peripheral == NULL){return;}
  411. 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);
  412. //初始化运轨sdk
  413. if (self.game_info.deviceType==DEVICETYPE_MAIN){
  414. LEManager.peripheral = peripheral;
  415. game = new Game(self.game_info.game_type);
  416. //开始链接动画
  417. [[MainLoadingView shanreAnimationView] addAnimation];
  418. }else if (self.game_info.deviceType == DEVICETYPE_VICE){
  419. LEManager.vicePeripheral = peripheral;
  420. viceDeviceGame = new Game(self.game_info.game_type);
  421. //开始链接动画
  422. [[ViceLoadingView shanreAnimationView] addAnimation];
  423. }
  424. //链接蓝牙 此时 LEManager.peripheral || LEManager.vicePeripheral 还未init
  425. [LEManager connectPeripheral:peripheral options:nil];
  426. //蓝牙连接成功
  427. LEManager.successfulBlock = ^(CBPeripheral * _Nonnull peripheral){
  428. if (self.shoes_info.macAddress.length>12 && self.shoes_info.viceMacAddress.length == 0){//有主没副
  429. if (LEManager.peripheral.state == CBPeripheralStateConnected){//主设备已经连接上后 停止扫描
  430. NSLog(@"主设备蓝牙链接成功");
  431. [LEManager stopScan];
  432. }
  433. }else if(self.shoes_info.macAddress.length == 0 && self.shoes_info.viceMacAddress.length >12){//没主有副
  434. if (LEManager.vicePeripheral.state == CBPeripheralStateConnected){//副设备已经连接上后 停止扫描
  435. NSLog(@"副设备蓝牙链接成功");
  436. [LEManager stopScan];
  437. }
  438. }else if(self.shoes_info.macAddress.length>12 && self.shoes_info.viceMacAddress.length > 12){//有主有副
  439. if (LEManager.peripheral.state == CBPeripheralStateConnected && LEManager.vicePeripheral.state == CBPeripheralStateConnected){//主和副设备都已经连接上后 停止扫描
  440. NSLog(@"主设备 和 副设备 蓝牙链接成功");
  441. [LEManager stopScan];
  442. }
  443. }
  444. };
  445. //蓝牙连接失败
  446. LEManager.connectFailureBlock = ^(NSError * _Nonnull error){
  447. NSLog(@"蓝牙链接失败");
  448. };
  449. //蓝牙连接丢失
  450. LEManager.disConnectBlock = ^(CBPeripheral * _Nonnull peripheral, NSError * _Nonnull error){
  451. if (LEManager.peripheral!=nil && peripheral==LEManager.peripheral){
  452. [[IOSPlatformSDK sharedInstance] bridgingDeviceAction:DEVICETYPE_MAIN
  453. name:LEManager.peripheral.name
  454. address:LEManager.peripheral.identifier.UUIDString
  455. status:CONNECT_LOST
  456. electricity:0];
  457. if (self.shoes_info.macAddress.length>12){
  458. NSLog(@"主设备 蓝牙链接断开 被动断开 需要重连");
  459. [self newCentralManagerOrScan];
  460. }else{
  461. NSLog(@"主设备 蓝牙链接断开 主动断开 不需重连");
  462. }
  463. }
  464. if (LEManager.vicePeripheral!=nil && peripheral==LEManager.vicePeripheral){
  465. [[IOSPlatformSDK sharedInstance] bridgingDeviceAction:DEVICETYPE_VICE
  466. name:LEManager.vicePeripheral.name
  467. address:LEManager.vicePeripheral.identifier.UUIDString
  468. status:CONNECT_LOST
  469. electricity:0];
  470. //副设备 断线 手动断开的话不用重连,自动断开的要重连
  471. if (self.shoes_info.viceMacAddress.length>12){
  472. NSLog(@"副设备 蓝牙链接断开 被动断开 需要重连");
  473. [self newCentralManagerOrScan];
  474. }else{
  475. NSLog(@"副设备 蓝牙链接断开 主动断开 不需重连");
  476. }
  477. }
  478. };
  479. //发现服务和特征
  480. LEManager.discoverCharacteristicsBlock = ^(CBPeripheral * _Nonnull peripheral, CBService * _Nonnull service, NSArray * _Nonnull characteristics, NSError * _Nonnull error){
  481. if (peripheral==LEManager.peripheral){//主设备
  482. for (CBCharacteristic * cha in service.characteristics){
  483. if (cha.properties == 12){//写
  484. LEManager.write = cha;
  485. //获取到写的特征后才能向 主设备 蓝牙对象写入数据
  486. [self startGameModeAndQueryDevideInfo];
  487. //链接成功震动一次
  488. [BTDataSendInstance vibration:DEVICETYPE_MAIN duration:400 leftOrRight:0];
  489. [self initTimer];
  490. }else if (cha.properties == 16){//读
  491. LEManager.read = cha;
  492. [LEManager.peripheral readValueForCharacteristic:cha];
  493. [LEManager.peripheral setNotifyValue:YES forCharacteristic:cha];
  494. }
  495. }
  496. }else if (peripheral==LEManager.vicePeripheral){//副设备
  497. for (CBCharacteristic * cha in service.characteristics){
  498. if (cha.properties == 12){//写
  499. LEManager.viceWrite = cha;
  500. //获取到写的特征后才能向 副设备 蓝牙对象写入数据
  501. [self startGameModeAndQueryDevideInfo];
  502. //链接成功震动一次
  503. [BTDataSendInstance vibration:DEVICETYPE_VICE duration:400 leftOrRight:0];
  504. }else if (cha.properties == 16){//读
  505. LEManager.viceRead = cha;
  506. [LEManager.vicePeripheral readValueForCharacteristic:cha];
  507. [LEManager.vicePeripheral setNotifyValue:YES forCharacteristic:cha];
  508. }
  509. }
  510. }
  511. };
  512. //读取特征的报文数据
  513. LEManager.readValueForCharacteristicBlock = ^(CBPeripheral * _Nonnull peripheral, CBCharacteristic * _Nonnull characteristic, NSData * _Nonnull value, NSError * _Nonnull error){
  514. // NSLog(@"characteristic.value = %@ characteristic.UUID.UUIDString = %@",characteristic.value,characteristic.UUID.UUIDString);
  515. if ([characteristic.UUID.UUIDString isEqualToString:@"6E400003-B5A3-F393-E0A9-E50E24DCCA9E"]){//判断是不是我们设备
  516. //每收到数据包读取一次蓝牙RSSI 无论1秒内请求多少次rssi值,原生api每秒都最多返回一次RSSI
  517. [peripheral readRSSI];
  518. //带cmd位的有效数据 计算校验位
  519. if ([AlgorithmTool verificationRusult:characteristic.value]==YES){
  520. int dataType = [AlgorithmTool dataToChar:[characteristic.value subdataWithRange:NSMakeRange(3, 1)]];//cmd类型
  521. if (dataType == 4){//鞋子游戏数据
  522. if (characteristic.value.length < 64){ return; }
  523. //数据丢给算法计算轨迹
  524. if (peripheral==LEManager.peripheral&&LEManager.main_read == 0){
  525. // NSLog(@"LEManager.main_read = %d",LEManager.main_read);
  526. // NSLog(@"主设备 读取特征的报文 游戏数据 %ld dataType = %d %@",(long)type,dataType,characteristic.value);
  527. [[MainLoadingView shanreAnimationView] stopAnimation];
  528. LEManager.main_read = 1;
  529. [self shoseSDK:characteristic.value];
  530. }else if (peripheral==LEManager.vicePeripheral&&LEManager.vice_read == 0){
  531. [[ViceLoadingView shanreAnimationView] stopAnimation];
  532. LEManager.vice_read = 1;
  533. [self viceShoseSDK:characteristic.value];
  534. }
  535. }else if(dataType == -95){//鞋子状态信息
  536. if (characteristic.value.length<30){ return; }
  537. //嵌入式原始数据解析 --->> 回调蓝牙状态/电量给unity
  538. BTDataAnalysis * anly = [BTDataAnalysis new];
  539. [anly analysisCharacteristic:characteristic.value peripheral:peripheral];
  540. }
  541. }
  542. }
  543. };
  544. //蓝牙更新RSSI
  545. LEManager.rssiBlock = ^(NSNumber * _Nonnull RSSI){
  546. LEManager.RSSI = RSSI;
  547. };
  548. }
  549. #pragma mark ===============================================>> 读取特征后 鞋子打开游戏模式 & 激光开关 &查询鞋子蓝牙状态 & 主设备初始化缓存游戏步数
  550. //init定时器
  551. -(void)initTimer{
  552. //定时开启游戏模式 & 查询设备信息 & 开启激光检测下蹲
  553. if (self.timer!=nil){
  554. [self.timer invalidate];
  555. self.timer = nil;
  556. }
  557. self.timer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(startGameModeAndQueryDevideInfo) userInfo:nil repeats:YES];
  558. [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
  559. }
  560. //定时发送数据
  561. -(void)startGameModeAndQueryDevideInfo{
  562. //开启游戏模式&查询设备信息 初始化步数数据 (防止读取到的读写为空 延迟0.5s)
  563. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(),^{
  564. if (self.game_info.isBackGround){//程序在后台
  565. }else{//程序在前台
  566. [BTDataSendInstance startGameModel];
  567. [BTDataSendInstance queryDevideInfo];
  568. [BTDataSendInstance keepConnect];
  569. }
  570. });
  571. }
  572. #pragma mark ===============================================>> 主设备 报文数据解析后 -- 调用蓝牙鞋子SDK装换数据 -- ios call unity 更新游戏动作
  573. -(void)shoseSDK:(NSData*)characteristic{
  574. // NSLog(@"characteristic = %@",characteristic);
  575. /********************初始化 运动轨迹算法 SDK *****************/
  576. NSData * validData= [characteristic subdataWithRange:NSMakeRange(4, characteristic.length-4)];
  577. Byte * buff = (Byte*)[validData bytes];
  578. game->GameProcessBuf(buff, (int)validData.length);
  579. if (self.shoes_info.gameModel==YES){//当前是游戏模式
  580. /********************剑波 & 威严 要的图表数据 *****************/
  581. NSString * message = [NSString stringWithUTF8String:game->getGameDataStr().c_str()];
  582. [DebugViewInstance debugMessage:message shoesInfo:self.shoes_info];
  583. }
  584. /******************左右脚动作数据处理 + 回调*****************/
  585. int length = 10;
  586. int result[length];
  587. game->getGameResult(result);
  588. int motionLeft = result[0];//左脚的动作
  589. int motionRight = result[1];//右脚的动作
  590. int motionJump = result[2];//jump
  591. int motionDown = result[3];//down
  592. // //无效动作 过滤无效动作会导致步频加速无效
  593. // if (motionLeft==-1 && motionRight == -1&& motionJump == -1&& motionDown == -1){
  594. // return;
  595. // }
  596. //跳跃和蹲下的动作 双脚是同步的
  597. if (motionJump == MOTION_JUMP||motionJump == MOTION_JUMP_OC||motionJump == MOTION_JUMP_VERTICAL){
  598. motionLeft = motionJump;
  599. motionRight = motionJump;
  600. }
  601. if (motionDown == MOTION_DOWN){
  602. motionLeft = motionDown;
  603. motionRight = motionDown;
  604. }
  605. /******************当局游戏 鞋子子动作状态数据 缓存*****************/
  606. self.shoes_info.leftStepStatus = game->getStepStatus(LEFT_FOOT);
  607. self.shoes_info.leftStepFreq = game->getStepFreq(LEFT_FOOT);
  608. self.shoes_info.leftStepCount = game->getStepCount(LEFT_FOOT);
  609. self.shoes_info.rightStepStatus = game->getStepStatus(RIGHT_FOOT);
  610. self.shoes_info.rightStepFreq = game->getStepFreq(RIGHT_FOOT);
  611. self.shoes_info.rightStepCount = game->getStepCount(RIGHT_FOOT);
  612. [self cacheAllMotionCount];
  613. /******************鞋子动作状态数据 实时回调*****************/
  614. //左右脚动作:所有游戏都需要回调
  615. [[IOSPlatformSDK sharedInstance] bridgingMotionAction:DEVICETYPE_MAIN left:motionLeft right:motionRight];
  616. //步频状态:只有跑酷回调
  617. if (self.game_info.game_type == GAME_TYPE_RUN||self.game_info.game_type == GAME_TYPE_CYCLE){
  618. [[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];
  619. }
  620. //人物朝向 只有 三轮车 需要
  621. if (self.game_info.game_type == GAME_TYPE_CYCLE){
  622. int attLength = 3;
  623. int left[attLength];
  624. int right[attLength];
  625. game->getFootAtt(left, right);
  626. self.main_nativeAttX = left[0];
  627. // NSLog(@"self.nativeAttX = %d",self.nativeAttX);
  628. }
  629. /******************脚步交互数据 实时回调*****************/
  630. int interaction = game->getInteractionCMD();
  631. if (interaction==-1){
  632. return;
  633. }
  634. //自定义弹窗界面交互
  635. if (self.isPopUp == YES){
  636. NSLog(@"BTDataProcess 有效交互动作 ===>> %d",interaction);
  637. [self.searchDeviceVC getInteraction:interaction];
  638. [self.friendsListVC getInteraction:interaction];
  639. }else{
  640. //游戏界面交互
  641. [[IOSPlatformSDK sharedInstance] bridgingInteraction:DEVICETYPE_MAIN code:interaction];
  642. }
  643. }
  644. #pragma mark ===============================================>>副设备 报文数据解析后 -- 调用蓝牙鞋子SDK装换数据 -- ios call unity 更新游戏动作
  645. -(void)viceShoseSDK:(NSData*)characteristic{
  646. /********************初始化 运动轨迹算法 SDK *****************/
  647. //游戏数据
  648. NSData * validData= [characteristic subdataWithRange:NSMakeRange(4, characteristic.length-4)];
  649. Byte * buff = (Byte*)[validData bytes];
  650. viceDeviceGame->GameProcessBuf(buff, (int)validData.length);
  651. //当前是游戏模式
  652. // if (self.shoes_info.gameModel==YES){
  653. /******************左右脚动作数据处理 + 回调*****************/
  654. int length = 10;
  655. int result[length];
  656. viceDeviceGame->getGameResult(result);
  657. int motionLeft = result[0];//左脚的动作
  658. int motionRight = result[1];//右脚的动作
  659. int ivce_motionJump = result[2];//jump
  660. int ivce_motionDown = result[3];//down
  661. //跳跃和蹲下的动作 双脚是同步的
  662. if (ivce_motionJump == MOTION_JUMP||ivce_motionJump == MOTION_JUMP_OC||ivce_motionJump == MOTION_JUMP_VERTICAL){
  663. motionLeft = ivce_motionJump;
  664. motionRight = ivce_motionJump;
  665. }
  666. if (ivce_motionDown == MOTION_DOWN){
  667. motionLeft = ivce_motionDown;
  668. motionRight = ivce_motionDown;
  669. }
  670. /******************当局游戏 鞋子子动作状态数据 缓存*****************/
  671. int leftStepStatus = viceDeviceGame->getStepStatus(LEFT_FOOT);
  672. int leftStepFreq = viceDeviceGame->getStepFreq(LEFT_FOOT);
  673. // int leftStepCount = viceDeviceGame->getStepCount(LEFT_FOOT);
  674. int rightStepStatus = viceDeviceGame->getStepStatus(RIGHT_FOOT);
  675. int rightStepFreq = viceDeviceGame->getStepFreq(RIGHT_FOOT);
  676. // int rightStepCount = viceDeviceGame->getStepCount(RIGHT_FOOT);
  677. /******************鞋子动作状态数据 实时回调*****************/
  678. //左右脚动作:所有游戏都需要回调
  679. [[IOSPlatformSDK sharedInstance] bridgingMotionAction:DEVICETYPE_VICE left:motionLeft right:motionRight];
  680. //步频:跑酷和三轮车
  681. if (self.game_info.game_type == GAME_TYPE_RUN||self.game_info.game_type == GAME_TYPE_CYCLE){
  682. [[IOSPlatformSDK sharedInstance] bridgingStepAction:DEVICETYPE_VICE leftStatus:leftStepStatus rightStatus:rightStepStatus leftFrag:leftStepFreq rightFrag:rightStepFreq];
  683. }
  684. //人物朝向:三轮车
  685. if (self.game_info.game_type == GAME_TYPE_CYCLE){
  686. int attLength = 3;
  687. int left[attLength];
  688. int right[attLength];
  689. viceDeviceGame->getFootAtt(left, right);
  690. self.vice_nativeAttX = left[0];
  691. }
  692. // }
  693. /******************脚步交互数据 实时回调*****************/
  694. int interaction = viceDeviceGame->getInteractionCMD();
  695. if (interaction==-1){
  696. return;
  697. }
  698. if (self.isPopUp == YES){//自定义弹窗界面交互
  699. }else{
  700. //游戏界面交互
  701. [[IOSPlatformSDK sharedInstance] bridgingInteraction:DEVICETYPE_VICE code:interaction];
  702. }
  703. }
  704. #pragma mark ===============================================>> 懒加载 -- 蓝牙设备数据源
  705. -(NSMutableArray*)deviceArray{
  706. if (!_deviceArray){
  707. _deviceArray = [NSMutableArray new];
  708. }
  709. return _deviceArray;;
  710. }
  711. #pragma mark ===============================================>> 玩游戏过程中缓存 动作数据 和时间戳 数据存入plist
  712. -(void)cacheAllMotionCount{
  713. //总数
  714. int total_step_count = game->getMotionCount(STEP_COUNT) - self.game_info.step;
  715. int total_jump_count = game->getMotionCount(JUMP_COUNT) - self.game_info.jump;
  716. int total_crouch_count = game->getMotionCount(DOWN_COUNT) - self.game_info.crouch;
  717. int total_tick_count = game->getMotionCount(KICK_COUNT) - self.game_info.tick;
  718. int total_paper_count = game->getMotionCount(PAPER_COUNT) - self.game_info.paper;
  719. int total_scissors_count = game->getMotionCount(SCISSORS_COUNT) - self.game_info.scissors;
  720. int total_rock_count = game->getMotionCount(ROCK_COUNT) - self.game_info.rock;
  721. // int total_trample_count = game->getMotionCount(ROCK_COUNT) - self.game_info.trample;
  722. // 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);
  723. //缓存pilst文件
  724. NSMutableDictionary * motionCountObj = [NSMutableDictionary new];
  725. [motionCountObj setObject:[NSNumber numberWithInt:total_step_count] forKey:@"step"];
  726. [motionCountObj setObject:[NSNumber numberWithInt:total_jump_count] forKey:@"jump"];
  727. [motionCountObj setObject:[NSNumber numberWithInt:total_crouch_count] forKey:@"crouch"];
  728. [motionCountObj setObject:[NSNumber numberWithInt:total_tick_count] forKey:@"tick"];
  729. [motionCountObj setObject:[NSNumber numberWithInt:total_paper_count] forKey:@"paper"];
  730. [motionCountObj setObject:[NSNumber numberWithInt:total_scissors_count] forKey:@"scissors"];
  731. [motionCountObj setObject:[NSNumber numberWithInt:total_rock_count] forKey:@"rock"];
  732. [motionCountObj setObject:[NSNumber numberWithInt:0] forKey:@"trample"];
  733. NSMutableDictionary * movements = [NSMutableDictionary new];
  734. [movements setObject:motionCountObj forKey:@"movements"];
  735. //游戏总共经历的时长(秒数)
  736. NSTimeInterval durationTime = [[NSDate date] timeIntervalSinceDate:self.game_info.firstTime];
  737. [movements setObject:[NSNumber numberWithInt:durationTime] forKey:@"duration"];
  738. //时间戳
  739. [movements setObject: self.shoes_info.timestamp forKey:@"play_group"];
  740. NSDictionary * dict = [NSDictionary dictionaryWithDictionary:movements];
  741. //归档缓存
  742. [IOS_NSUSERDEFAULT setObject:dict forKey:IOSSDK_MOTIONCOUNT];
  743. [IOS_NSUSERDEFAULT synchronize];
  744. }
  745. @end