Parcourir la source

添加部分三轮车游戏用到的接口

leon il y a 2 ans
Parent
commit
8fbb7a3a50
100 fichiers modifiés avec 7652 ajouts et 4980 suppressions
  1. BIN
      .DS_Store
  2. 706 569
      IOSToUnitySDK.xcodeproj/project.pbxproj
  3. BIN
      IOSToUnitySDK.xcworkspace/xcuserdata/duowan123.xcuserdatad/UserInterfaceState.xcuserstate
  4. BIN
      SDK/.DS_Store
  5. 14 0
      SDK/BLE/BTDataAnalysis.h
  6. 131 0
      SDK/BLE/BTDataAnalysis.mm
  7. 25 37
      SDK/BLE/BTDataProcess.h
  8. 667 490
      SDK/BLE/BTDataProcess.mm
  9. 4 1
      SDK/BLE/BTDataSend.h
  10. 46 11
      SDK/BLE/BTDataSend.m
  11. 0 35
      SDK/BLE/DebugView.h
  12. 0 235
      SDK/BLE/DebugView.m
  13. 14 3
      SDK/BLE/LEONBLManager.h
  14. 58 32
      SDK/BLE/LEONBLManager.m
  15. 0 51
      SDK/BLE/MainShoesAnalysis.h
  16. 0 551
      SDK/BLE/MainShoesAnalysis.mm
  17. 0 16
      SDK/BLE/ViceShoesAnalysis.h
  18. 0 12
      SDK/BLE/ViceShoesAnalysis.m
  19. 60 0
      SDK/Entity /GameInfo.h
  20. 12 0
      SDK/Entity /GameInfo.m
  21. 35 0
      SDK/Entity /ShoesInfo.h
  22. 12 0
      SDK/Entity /ShoesInfo.m
  23. 4 23
      SDK/Entity /UserFriendsModel.h
  24. BIN
      SDK/HTTP/.DS_Store
  25. 22 18
      SDK/HTTP/HTTPDataProcession.h
  26. 105 99
      SDK/HTTP/HTTPDataProcession.m
  27. 72 47
      SDK/IOSPlatformSDK/IOSPlatformSDK.h
  28. 218 295
      SDK/IOSPlatformSDK/IOSPlatformSDK.mm
  29. 0 78
      SDK/PrefixHeader.h
  30. BIN
      SDK/ThirdClass/.DS_Store
  31. 0 0
      SDK/ThirdClass/AFNetworking/AFCompatibilityMacros.h
  32. 0 0
      SDK/ThirdClass/AFNetworking/AFHTTPSessionManager.h
  33. 0 4
      SDK/ThirdClass/AFNetworking/AFHTTPSessionManager.m
  34. 0 0
      SDK/ThirdClass/AFNetworking/AFNetworkReachabilityManager.h
  35. 0 0
      SDK/ThirdClass/AFNetworking/AFNetworkReachabilityManager.m
  36. 0 0
      SDK/ThirdClass/AFNetworking/AFNetworking.h
  37. 0 0
      SDK/ThirdClass/AFNetworking/AFSecurityPolicy.h
  38. 1 0
      SDK/ThirdClass/AFNetworking/AFSecurityPolicy.m
  39. 0 0
      SDK/ThirdClass/AFNetworking/AFURLRequestSerialization.h
  40. 0 0
      SDK/ThirdClass/AFNetworking/AFURLRequestSerialization.m
  41. 0 0
      SDK/ThirdClass/AFNetworking/AFURLResponseSerialization.h
  42. 0 0
      SDK/ThirdClass/AFNetworking/AFURLResponseSerialization.m
  43. 0 0
      SDK/ThirdClass/AFNetworking/AFURLSessionManager.h
  44. 0 0
      SDK/ThirdClass/AFNetworking/AFURLSessionManager.m
  45. 116 0
      SDK/ThirdClass/AvoidCrash/AvoidCrash.h
  46. 220 0
      SDK/ThirdClass/AvoidCrash/AvoidCrash.m
  47. 17 0
      SDK/ThirdClass/AvoidCrash/AvoidCrashProtocol.h
  48. 37 0
      SDK/ThirdClass/AvoidCrash/AvoidCrashStubProxy.h
  49. 18 0
      SDK/ThirdClass/AvoidCrash/AvoidCrashStubProxy.m
  50. 25 0
      SDK/ThirdClass/AvoidCrash/NSArray+AvoidCrash.h
  51. 257 0
      SDK/ThirdClass/AvoidCrash/NSArray+AvoidCrash.m
  52. 25 0
      SDK/ThirdClass/AvoidCrash/NSAttributedString+AvoidCrash.h
  53. 96 0
      SDK/ThirdClass/AvoidCrash/NSAttributedString+AvoidCrash.m
  54. 24 0
      SDK/ThirdClass/AvoidCrash/NSDictionary+AvoidCrash.h
  55. 56 0
      SDK/ThirdClass/AvoidCrash/NSDictionary+AvoidCrash.m
  56. 26 0
      SDK/ThirdClass/AvoidCrash/NSMutableArray+AvoidCrash.h
  57. 169 0
      SDK/ThirdClass/AvoidCrash/NSMutableArray+AvoidCrash.m
  58. 23 0
      SDK/ThirdClass/AvoidCrash/NSMutableAttributedString+AvoidCrash.h
  59. 74 0
      SDK/ThirdClass/AvoidCrash/NSMutableAttributedString+AvoidCrash.m
  60. 24 0
      SDK/ThirdClass/AvoidCrash/NSMutableDictionary+AvoidCrash.h
  61. 95 0
      SDK/ThirdClass/AvoidCrash/NSMutableDictionary+AvoidCrash.m
  62. 29 0
      SDK/ThirdClass/AvoidCrash/NSMutableString+AvoidCrash.h
  63. 97 0
      SDK/ThirdClass/AvoidCrash/NSMutableString+AvoidCrash.m
  64. 34 0
      SDK/ThirdClass/AvoidCrash/NSObject+AvoidCrash.h
  65. 220 0
      SDK/ThirdClass/AvoidCrash/NSObject+AvoidCrash.m
  66. 29 0
      SDK/ThirdClass/AvoidCrash/NSString+AvoidCrash.h
  67. 204 0
      SDK/ThirdClass/AvoidCrash/NSString+AvoidCrash.m
  68. BIN
      SDK/ThirdClass/Bugly-2.5.9/Bugly.framework/Bugly
  69. 163 0
      SDK/ThirdClass/Bugly-2.5.9/Bugly.framework/Headers/Bugly.h
  70. 141 0
      SDK/ThirdClass/Bugly-2.5.9/Bugly.framework/Headers/BuglyConfig.h
  71. 78 0
      SDK/ThirdClass/Bugly-2.5.9/Bugly.framework/Headers/BuglyLog.h
  72. 12 0
      SDK/ThirdClass/Bugly-2.5.9/Bugly.framework/Modules/module.modulemap
  73. 154 0
      SDK/ThirdClass/socket/SRWebSocket.h
  74. 1916 0
      SDK/ThirdClass/socket/SRWebSocket.m
  75. 23 0
      SDK/ThirdClass/socket/SocketRocketUtility.h
  76. 301 0
      SDK/ThirdClass/socket/SocketRocketUtility.m
  77. 2 1
      SDK/Tool/AlgorithmTool.h
  78. 10 25
      SDK/Tool/AlgorithmTool.m
  79. 16 0
      SDK/Tool/BugTool.h
  80. 47 0
      SDK/Tool/BugTool.m
  81. 29 0
      SDK/Tool/CacheTool.h
  82. 172 0
      SDK/Tool/CacheTool.m
  83. 0 157
      SDK/Tool/GameObjc.h
  84. 0 387
      SDK/Tool/GameObjc.mm
  85. 16 102
      SDK/Tool/MYFactoryManager.h
  86. 17 1232
      SDK/Tool/MYFactoryManager.m
  87. BIN
      SDK/UI/.DS_Store
  88. 0 286
      SDK/UI/AnimationVIew/AnimationView.m
  89. 5 8
      SDK/UI/AnimationVIew/MainLoadingView.h
  90. 116 0
      SDK/UI/AnimationVIew/MainLoadingView.m
  91. 30 0
      SDK/UI/AnimationVIew/ViceLoadingView.h
  92. 116 0
      SDK/UI/AnimationVIew/ViceLoadingView.m
  93. 2 2
      SDK/UI/CarouselView/SearchDeviceViewController.h
  94. 67 92
      SDK/UI/CarouselView/SearchDeviceViewController.m
  95. 5 10
      SDK/UI/CarouselView/ShoesCarouselView.h
  96. 67 41
      SDK/UI/CarouselView/ShoesCarouselView.m
  97. 3 3
      SDK/UI/CarouselView/ShoesCollectionCell.h
  98. 6 8
      SDK/UI/CarouselView/ShoesCollectionCell.m
  99. 10 12
      SDK/UI/CarouselView/ShoesCollectionCell.xib
  100. 7 7
      SDK/UI/CarouselView/ShoesPeripheralMolde.h

BIN
.DS_Store


Fichier diff supprimé car celui-ci est trop grand
+ 706 - 569
IOSToUnitySDK.xcodeproj/project.pbxproj


BIN
IOSToUnitySDK.xcworkspace/xcuserdata/duowan123.xcuserdatad/UserInterfaceState.xcuserstate


BIN
SDK/.DS_Store


+ 14 - 0
SDK/BLE/BTDataAnalysis.h

@@ -0,0 +1,14 @@
+//
+//  BTDataAnalysis.h
+//  Unity-iPhone
+//
+//  Created by duowan123 on 2022/1/26.
+//
+
+#import <Foundation/Foundation.h>
+#import "MYFactoryManager.h"
+
+@interface BTDataAnalysis : NSObject
+-(void)analysisCharacteristic:(NSData*)characteristic peripheral:(CBPeripheral*)peripheral;
+@end
+

+ 131 - 0
SDK/BLE/BTDataAnalysis.mm

@@ -0,0 +1,131 @@
+//
+//  BTDataAnalysis.m
+//  Unity-iPhone
+//
+//  Created by duowan123 on 2022/1/26.
+//
+
+#import "BTDataAnalysis.h"
+#import "IOSPlatformSDK.h"
+@implementation BTDataAnalysis
+
+#pragma mark ===============================================>> 校验 & 报文数据解析
+-(void)analysisCharacteristic:(NSData*)characteristic peripheral:(CBPeripheral*)peripheral{
+        
+////    NSLog(@"接收到的数据data = %@",characteristic);
+//    int frameHead = [AlgorithmTool dataToChar:[characteristic subdataWithRange:NSMakeRange(0, 1)]];//帧头数据aa
+//    int messageLength = [AlgorithmTool dataToChar:[characteristic subdataWithRange:NSMakeRange(1, 1)]];//报文长度
+//    int messageLengthNegation = ~messageLength;//报文长度取反
+//    int dataType = [AlgorithmTool dataToChar:[characteristic subdataWithRange:NSMakeRange(3, 1)]];//cmd类型
+//
+//      if (dataType == 4){//获取主动推过来的数据
+//            //右脚坐标数据
+//           int right_X = [AlgorithmTool dataToSwapBigIntToHost:characteristic andRange:NSMakeRange(4, 4)];
+//           int right_Y = [AlgorithmTool dataToSwapBigIntToHost:characteristic andRange:NSMakeRange(8, 4)];
+//           int right_Z = [AlgorithmTool dataToSwapBigIntToHost:characteristic andRange:NSMakeRange(12, 4)];
+//           int  right_pos[3] = {right_X,right_Y,right_Z};
+//          //左脚坐标数据
+//           int left_X = [AlgorithmTool dataToSwapBigIntToHost:characteristic andRange:NSMakeRange(16, 4)];
+//           int left_Y = [AlgorithmTool dataToSwapBigIntToHost:characteristic andRange:NSMakeRange(20, 4)];
+//           int left_Z = [AlgorithmTool dataToSwapBigIntToHost:characteristic andRange:NSMakeRange(24, 4)];
+//           int  left_pos[3] = {left_X,left_Y,left_Z};
+//           //右脚姿势数据
+//           short righrPosture_X = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(28, 2)];
+//           short righrPosture_Y = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(30, 2)];
+//           short righrPosture_Z = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(32, 2)];
+//           int  right_att[3] = {righrPosture_X,righrPosture_Y,righrPosture_Z};
+//           //左脚姿势数据
+//           short leftPosture_X = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(34, 2)];
+//           short leftPosture_Y = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(36, 2)];
+//           short leftPosture_Z = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(38, 2)];
+//           int  left_att[3] = {leftPosture_X,leftPosture_Y,leftPosture_Z};
+//           //右脚三维数据
+//           short righrAcc_x = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(40, 2)];
+//           short righrAcc_Y = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(42, 2)];
+//           short righrAcc_z = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(44, 2)];
+//           int  righr_acc[3] = {righrAcc_x,righrAcc_Y,righrAcc_z};
+//           //左脚三维数据
+//           short leftAcc_x = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(46, 2)];
+//           short leftAcc_y = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(48, 2)];
+//           short leftAcc_z = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(50, 2)];
+//           int  left_acc[3] = {leftAcc_x,leftAcc_y,leftAcc_z};
+//           //左脚、右脚、蹲 、跳四个动作信息数据
+//           int actionInformation =  [AlgorithmTool dataToChar:[characteristic subdataWithRange:NSMakeRange(52, 1)]];;//0c 16进制字符串
+//                       int girlShoes  = actionInformation & 16;
+//                       if (girlShoes!=0){
+//                           girlShoes=1;
+//                       }else{
+//                           girlShoes=0;
+//                       }
+//                       int rightZupt  = actionInformation & 8;
+//                       if (rightZupt!=0){
+//                           rightZupt=1;
+//                       }else{
+//                           rightZupt=0;
+//                       }
+//                       int leftZupt = actionInformation & 4;
+//                       if (leftZupt!=0){
+//                            leftZupt=1;
+//                        }else{
+//                            leftZupt=0;
+//                        }
+//                       int down  = actionInformation & 2;
+//                       if (down!=0){
+//                            down=1;
+//                        }else{
+//                            down=0;
+//                        }
+//                       int jump  = actionInformation & 1;
+//                       if (jump!=0){
+//                            jump=1;
+//                        }else{
+//                            jump=0;
+//                        }
+//
+//            int rssi = [AlgorithmTool dataToChar:[characteristic subdataWithRange:NSMakeRange(53, 1)]];//rssi 信号强度
+//            int ts = [AlgorithmTool dataToChar:[characteristic subdataWithRange:NSMakeRange(54, 1)]];;//ts 时间戳
+//            int right_press = [AlgorithmTool dataToInt:[characteristic subdataWithRange:NSMakeRange(55, 2)]];//3 29新增 右鞋压力
+//            int left_press = [AlgorithmTool dataToInt:[characteristic subdataWithRange:NSMakeRange(57, 2)]];//3 29新增 左鞋压力
+//            int frameCheck =  [AlgorithmTool dataToChar:[characteristic subdataWithRange:NSMakeRange(59, 1)]];//校验位
+//
+//              if (deviceType==DEVICETYPE_MAIN){//主设备
+//    //                   NSLog(@"主设备 接收到 鞋子动作数据 data = %@",characteristic);
+//                  //调取鞋子SDK
+//    //                   [self shoseSDKRight_pos:right_pos Right_att:right_att Right_acc:righr_acc LeftPos:left_pos Left_att:left_att Left_acc:left_acc ts:ts rightZupt:rightZupt leftZupt:leftZupt jump:jump down:down rssi:rssi girlShoes:girlShoes right_press:right_press left_press:left_press characteristic:characteristic];
+//
+//              }else if (deviceType==DEVICETYPE_VICE){//副设备动作数据
+//                  //调取鞋子SDK
+//    //                   [self viceShoseSDKRight_pos:right_pos Right_att:right_att Right_acc:righr_acc LeftPos:left_pos Left_att:left_att Left_acc:left_acc ts:ts rightZupt:rightZupt leftZupt:leftZupt jump:jump down:down rssi:rssi girlShoes:girlShoes right_press:right_press left_press:left_press characteristic:characteristic];
+//              }
+//
+//        }else if (dataType == -95 && characteristic.length == 26){//获取的是查询的数据 char-->int a1 = -95
+           //A1+1 >> 1: 设备数据(左鞋,右鞋)  aa 14 eb a1 01 64 00 1a 0000981d 64 00 17 00000000 f9
+    //        NSLog(@"主设备 读取特征的报文 硬件信息 %ld dataType = -95 %@ %ld",(long)deviceType,characteristic,characteristic.length);
+
+                int leftElectricity = [AlgorithmTool dataToInt:[characteristic subdataWithRange:NSMakeRange(5, 1)]];
+                int rightElectricity = [AlgorithmTool dataToInt:[characteristic subdataWithRange:NSMakeRange(15, 1)]];//龙哥新协议
+                
+                if (peripheral==LEManager.peripheral && LEManager.peripheral!=nil){//主设备
+//                    NSLog(@"主设备 接收到 鞋子硬件数据: %@  电量 %d %d %@ %@",characteristic,leftElectricity,rightElectricity,LEManager.peripheral.name,LEManager.peripheral.identifier.UUIDString);
+                    //主 设备定时器 60秒调一次   /******************ios call unity*****************/
+                     [[IOSPlatformSDK sharedInstance] bridgingDeviceAction:DEVICETYPE_MAIN
+                                                 name:LEManager.peripheral.name
+                                              address:LEManager.peripheral.identifier.UUIDString
+                                               status:CONNECT_ED
+                                          electricity:leftElectricity<=rightElectricity?leftElectricity:rightElectricity];
+                    
+                }else if (peripheral==LEManager.vicePeripheral && LEManager.vicePeripheral!=nil){//副设备
+//                    NSLog(@"副设备 接收到 鞋子硬件数据: %@  电量 %d %d",characteristic,leftElectricity,rightElectricity);
+                    //副 设备定时器 60秒调一次   /******************ios call unity*****************/
+                     [[IOSPlatformSDK sharedInstance] bridgingDeviceAction:DEVICETYPE_VICE
+                                                 name:LEManager.vicePeripheral.name
+                                              address:LEManager.vicePeripheral.identifier.UUIDString
+                                               status:CONNECT_ED
+                                          electricity:leftElectricity<=rightElectricity?leftElectricity:rightElectricity];
+                    
+                }
+//        }
+}
+
+
+@end

+ 25 - 37
SDK/BLE/BTDataProcess.h

@@ -6,16 +6,7 @@
 //
 
 #import <UIKit/UIKit.h>
-#import "MYFactoryManager.h"
-#import "LEONBLManager.h"
 
-//游戏类型
-typedef NS_ENUM(int, GAME_TYPE){
-    GAME_TYPE_DEMO =0, //
-    GAME_TYPE_RUN, //
-    GAME_TYPE_DANCE, //
-    GAME_TYPE_SDAER, //
-};
 
 //蓝牙状态
 typedef NS_ENUM(NSInteger, BLETOOTH_STUTAS){
@@ -25,42 +16,39 @@ typedef NS_ENUM(NSInteger, BLETOOTH_STUTAS){
     CONNECT_LOST, // 丢失链接 /链接失败
 };
 
-@interface BTDataProcess : UIViewController
-    
-//趣动跳转过来携带的mac 实际是蓝牙设备的identity
-@property(copy,nonatomic)NSString * macAddress;
-//弹窗 unity主动选择链接 主0 副1 设备
-@property(assign,nonatomic)DEVICE_TYPE deviceType;
-//游戏种类 1是跳舞 3是跑酷 2是赛达尔传说 4是demo->dance
-@property(assign,nonatomic)GAME_TYPE game_type;
-
-//蓝牙设备数据源回调给popSeaechView
-@property(copy,nonatomic)void (^deviceArrBLock)(NSMutableArray*arr);
-//脚步交互数据
-@property(copy,nonatomic)void (^getInteractionBlock)(int interaction);
+@interface BTDataProcess : NSObject
 
-//程序在前台还是后台
-@property(assign,nonatomic)int isBackGround;
+@property(assign,nonatomic)int main_nativeAttX;
+@property(assign,nonatomic)int vice_nativeAttX;
 
+/**
+ 趣动app call sdk
+ */
 //单例->初始化蓝牙
 +(instancetype)sharedInstance;
+//打开游戏
+-(void)startWithUrl:(NSURL*)url;
+
 
-//初始化中心管理
--(void)initCBCentralManager;
-//app跳转直接连 或 tableview 选中
--(void)connectPeripheral:(CBPeripheral*)peripheral;
-//unity或者趣动请求 外部断开蓝牙链接
--(void)disConnedctBle;
+/**
+ unity  call sdk
+ */
+//unity call 打开弹窗
+-(void)searchBLEAction:(int)type;
+//邀请好友弹窗
+-(void)showInviteFriend:(int)code inviteInof:(NSString*)inviteInof;
+//unity call ios 断开蓝牙链接
+-(void)disConnedctBle:(int)type;
 
 
-//监听通知开始游戏
+/**
+ 监听 IOSPlatformSDK 通知
+ */
+//开始游戏
 -(void)gameStartInitData;
-//监听通知结束游戏
+//结束游戏
 -(void)gameEndInitData;
-//监听通知震动
--(void)vibrationAction:(int)type duration:(int)duration;
+//通知震动
+-(void)vibrationAction:(int)type duration:(int)duration leftOrRight:(int)leftOrRight;
 
 @end
-
-
-

Fichier diff supprimé car celui-ci est trop grand
+ 667 - 490
SDK/BLE/BTDataProcess.mm


+ 4 - 1
SDK/BLE/BTDataSend.h

@@ -21,9 +21,12 @@ NS_ASSUME_NONNULL_BEGIN
 //打开游戏模式
 - (void)startGameModel;
 //设置震动
-- (void)vibration:(DEVICE_TYPE)deviceType duration:(int)duration;
+- (void)vibration:(DEVICE_TYPE)deviceType duration:(int)duration leftOrRight:(int)leftOrRight;
 //开启/关闭 激光模式
 - (void)laser:(int)state;
+
+-(void)keepConnect;
+
 @end
 
 NS_ASSUME_NONNULL_END

+ 46 - 11
SDK/BLE/BTDataSend.m

@@ -54,11 +54,11 @@ static BTDataSend* instance = nil;
 
     [writeData appendBytes:&bcc length:sizeof(bcc)];
 
-    if (LEManager.peripheral!=nil){
+    if (LEManager.peripheral!=nil&&LEManager.write!=nil){
         NSLog(@"发送的报文 主设备 查询设备信息 %@", writeData);
         [LEManager writeValue:writeData forCharacteristic:LEManager.write writeType:CBCharacteristicWriteWithResponse deviceType:DEVICETYPE_MAIN];
     }
-    if (LEManager.vicePeripheral!=nil){
+    if (LEManager.vicePeripheral!=nil&&LEManager.viceWrite!=nil){
         NSLog(@"发送的报文 副设备 查询设备信息 %@", writeData);
         [LEManager writeValue:writeData forCharacteristic:LEManager.viceWrite writeType:CBCharacteristicWriteWithResponse deviceType:DEVICETYPE_VICE];
     }
@@ -83,12 +83,12 @@ static BTDataSend* instance = nil;
     //传输数据 -->> NSData
     [writeData appendBytes:&bcc length:sizeof(bcc)];
 
-    if (LEManager.peripheral!=nil){
+    if (LEManager.peripheral!=nil&&LEManager.write!=nil){
         NSLog(@"发送的报文 主设备 开启游戏模式: %@", writeData);
         [LEManager writeValue:writeData forCharacteristic:LEManager.write writeType:CBCharacteristicWriteWithResponse deviceType:DEVICETYPE_MAIN];
     }
     
-    if (LEManager.vicePeripheral!=nil){
+    if (LEManager.vicePeripheral!=nil&&LEManager.viceWrite!=nil){
         NSLog(@"发送的报文 副设备 开启游戏模式: %@", writeData);
         [LEManager writeValue:writeData forCharacteristic:LEManager.viceWrite writeType:CBCharacteristicWriteWithResponse deviceType:DEVICETYPE_VICE];
     }
@@ -96,29 +96,35 @@ static BTDataSend* instance = nil;
 }
 
 //设置震动
-- (void)vibration:(DEVICE_TYPE)deviceType duration:(int)duration{
+- (void)vibration:(DEVICE_TYPE)deviceType duration:(int)duration leftOrRight:(int)leftOrRight{
     
     //头帧AA + 数据长度 + 长度取反 + cmd + 数据 + 校验
      NSMutableData * writeData = [NSMutableData new];
      Byte header = 0xaa;
-     Byte length = 0x07;//长度A1->6  A2->5  A3->7
+     Byte length = 0x08;//长度A1->6  A2->5  A3->7
      Byte lengthNegation = ~length;
      Byte cmd = 0xA4;
+    
      //振动时间 2字节
-     short  ms = 400;//400毫秒
+     short ms = 400;//400毫秒
      Byte mslow = (Byte) (0x00FF & ms);//定义第一个byte
      Byte mshigh = (Byte) (0x00FF & (ms>>8));//定义第二个byte
+    
+    Byte leftOrRightByte = 0x00;//全部
+//     Byte leftOrRight = 0x01;//左脚
+//     Byte leftOrRight = 0x02;//右脚
+    
     //计算校验位
-     Byte bytes[] = {header,length,lengthNegation,cmd,mshigh,mslow};
+     Byte bytes[] = {header,length,lengthNegation,cmd,mshigh,mslow,leftOrRightByte};
      Byte bcc = [AlgorithmTool bbcByte:bytes];
     //传输数据 Byte -->> NSData
-     Byte newByte[] = {header,length,lengthNegation,cmd,mshigh,mslow,bcc};
+     Byte newByte[] = {header,length,lengthNegation,cmd,mshigh,mslow,leftOrRightByte,bcc};
      writeData = [[NSMutableData alloc] initWithBytes:newByte length:sizeof(newByte)];
 
-    if (deviceType==DEVICETYPE_MAIN){
+    if (deviceType==DEVICETYPE_MAIN&&LEManager.write!=nil){
         NSLog(@"发送的报文 主设备 设备震动 %@", writeData);
         [LEManager writeValue:writeData forCharacteristic:LEManager.write writeType:CBCharacteristicWriteWithResponse deviceType:DEVICETYPE_MAIN];
-    }else if (deviceType == DEVICETYPE_VICE){
+    }else if (deviceType == DEVICETYPE_VICE&&LEManager.viceWrite!=nil){
         NSLog(@"发送的报文 副设备 设备震动 %@", writeData);
         [LEManager writeValue:writeData forCharacteristic:LEManager.viceWrite writeType:CBCharacteristicWriteWithResponse deviceType:DEVICETYPE_VICE];
     }
@@ -160,4 +166,33 @@ static BTDataSend* instance = nil;
     
 }
 
+-(void)keepConnect{
+    
+    //头帧AA + 数据长度 + 长度取反 + cmd + 数据 + 校验
+    NSMutableData * writeData = [NSMutableData new];
+    
+    Byte header = 0xaa;
+    Byte length = 0x06;//长度A1->6  A2->5  A3->7
+    Byte lengthNegation = ~length;
+    Byte cmd = 0xB0;
+    Byte data = 0x01;
+
+    Byte byte[] = {header,length,lengthNegation,cmd,data};
+    writeData = [[NSMutableData alloc] initWithBytes:byte length:sizeof(byte)];
+//        [writeData appendData:msData];
+    Byte bcc = [AlgorithmTool byteSumBBC:writeData];
+
+    [writeData appendBytes:&bcc length:sizeof(bcc)];
+
+    if (LEManager.peripheral!=nil&&LEManager.write!=nil){
+        NSLog(@"发送的报文 主设备 保持链接 %@", writeData);
+        [LEManager writeValue:writeData forCharacteristic:LEManager.write writeType:CBCharacteristicWriteWithResponse deviceType:DEVICETYPE_MAIN];
+    }
+    if (LEManager.vicePeripheral!=nil&&LEManager.viceWrite!=nil){
+        NSLog(@"发送的报文 副设备 保持链接 %@", writeData);
+        [LEManager writeValue:writeData forCharacteristic:LEManager.viceWrite writeType:CBCharacteristicWriteWithResponse deviceType:DEVICETYPE_VICE];
+    }
+    
+}
+
 @end

+ 0 - 35
SDK/BLE/DebugView.h

@@ -1,35 +0,0 @@
-//
-//  DebugView.h
-//  Unity-iPhone
-//
-//  Created by duowan123 on 2021/12/22.
-//
-
-#import <UIKit/UIKit.h>
-#import "MYFactoryManager.h"
-
-#define DebugViewInstance [DebugView sharedInstance]
-#define Game_Type @"run"
-#define JBSDKLog @"runLog.txt"
-
-@interface DebugView : UIView
-/*****测试*******/
-@property (nonatomic,strong)UILabel * testLabel;//调试框
-@property (nonatomic,strong)UIButton * uploadButton;//上传
-@property (nonatomic,strong)UIButton * clearnButton;//上传
-
-//当前的时间戳+丢包
-@property (nonatomic,strong)NSString * tempStepString;//剑波要的字符串数据 缓存plist
-@property(nonatomic,assign) NSNumber *RSSI;//威严要的测试数据
-@property(nonatomic,assign) int currentTS;//颖嘉要的测试数据
-
-+(instancetype)sharedInstance;
-
-#pragma mark ===============================================>> DEBUG
--(void)inittestLabel;
-
-//数据写入沙河
--(void)writeFileToplist;
-    
-@end
-

+ 0 - 235
SDK/BLE/DebugView.m

@@ -1,235 +0,0 @@
-//
-//  DebugView.m
-//  Unity-iPhone
-//
-//  Created by duowan123 on 2021/12/22.
-//
-
-#import "DebugView.h"
-
-@implementation DebugView
-#pragma mark ===============================================>> 静态的初始化方法  init的时候(建立蓝牙中心管理类,设置代理)
-//单例静态
-static DebugView* instance = nil;
-+(instancetype)sharedInstance{
-//    NSLog(@"创建单例一次 1");
-     return [[self alloc] init];
-}
-
-+ (instancetype)allocWithZone:(struct _NSZone *)zone{
-//    NSLog(@"创建单例一次 2");
-  static dispatch_once_t onceToken;
-  dispatch_once(&onceToken, ^{
-      instance = [super allocWithZone:zone];
-  });
-  return instance;
-}
-
-- (instancetype)init{
-//    NSLog(@"创建单例一次 3");
-    static dispatch_once_t onceToken;
-    dispatch_once(&onceToken, ^{
-        instance = [super init];
-    });
-    return instance;
-}
-
-
-#pragma mark ===============================================>> DEBUG
--(void)inittestLabel{
-
-    if (self.testLabel!=nil){
-        [self.testLabel removeFromSuperview];
-    }
-    
-    if (self.uploadButton!=nil){
-        [self.uploadButton removeFromSuperview];
-    }
-    
-    if (self.clearnButton!=nil){
-        [self.clearnButton removeFromSuperview];
-    }
-    
-    self.uploadButton = [UIButton buttonWithType:UIButtonTypeCustom];
-    self.uploadButton.frame = CGRectMake(30, SCREEN_HEIGHT-40-10, SCALEoefficient(75), SCALEoefficient(30));
-    self.uploadButton.backgroundColor = [UIColor redColor];
-    [self.uploadButton addTarget: self action: @selector (button1BackGroundHighlighted:) forControlEvents:UIControlEventTouchDown];
-    [self.uploadButton addTarget: self action: @selector (button1BackGroundNormal:) forControlEvents:UIControlEventTouchUpInside];
-    [self.uploadButton setFont: [UIFont boldSystemFontOfSize:SCALEoefficient(15)]];
-    [self.uploadButton setTitle:@"上传" forState:UIControlStateNormal];
-    [self.uploadButton addTarget:self action:@selector(uploadpPlistFile) forControlEvents:UIControlEventTouchUpInside];
-    
-    self.clearnButton = [UIButton buttonWithType:UIButtonTypeCustom];
-    self.clearnButton.frame = CGRectMake(30+SCALEoefficient(75)+20, SCREEN_HEIGHT-40-10, SCALEoefficient(75), SCALEoefficient(30));
-    self.clearnButton.backgroundColor = [UIColor redColor];
-//    [self.clearnButton addTarget:self action:@selector(button1BackGroundHighlighted:) forControlEvents:UIControlEventTouchDown];
-//    [self.clearnButton addTarget:self action:@selector(button1BackGroundNormal:) forControlEvents:UIControlEventTouchUpInside];
-    [self.clearnButton setFont: [UIFont boldSystemFontOfSize:SCALEoefficient(15)]];
-    [self.clearnButton setTitle:@"清理缓存" forState:UIControlStateNormal];
-    [self.clearnButton addTarget:self action:@selector(clearCacheWithFilePath) forControlEvents:UIControlEventTouchUpInside];
-    
-    self.testLabel = [[UILabel alloc] initWithFrame:CGRectMake(SCALEoefficient(20), 0, [UIScreen mainScreen].bounds.size.width-100, SCALEoefficient(160))];
-    self.testLabel.textColor = [UIColor redColor];
-    self.testLabel.font = [UIFont boldSystemFontOfSize:SCALEoefficient(14)];
-    self.testLabel.backgroundColor = [UIColor clearColor];
-    self.testLabel.textAlignment = NSTextAlignmentCenter;
-    self.testLabel.numberOfLines = 0;
-
-    if ([UIApplication sharedApplication].keyWindow != nil){
-        [[UIApplication sharedApplication].keyWindow addSubview:self.uploadButton];
-        [[UIApplication sharedApplication].keyWindow addSubview:self.clearnButton];
-        [[UIApplication sharedApplication].keyWindow addSubview:self.testLabel];
-    }
-
-}
-
-//  button普通状态下的背景色
-- (void )button1BackGroundNormal:(UIButton *)sender
-{
-     sender.backgroundColor = [UIColor redColor];
-}
- 
-//  button高亮状态下的背景色
-- (void )button1BackGroundHighlighted:(UIButton *)sender
-{
-     sender.backgroundColor = [UIColor orangeColor];
-}
-
-#pragma mark ===============================================>> 存储和上传数据
-//清理缓存
-- (void)clearCacheWithFilePath{
-    
-    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
-    //获取完整路径
-    NSString *documentsDirectory = [paths objectAtIndex:0];
-    NSString *filePath = [documentsDirectory stringByAppendingPathComponent:JBSDKLog];//这里就是你将要存储的沙盒路径(.plist文件,名字自定义)
-    NSError *error = nil;
-    //删除子文件夹
-    [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
-    if (error){
-        NSLog(@"清理缓存失败");
-        [PopupView showCusHUDA:@"清理失败"];
-    }else{
-        NSLog(@"清理缓存成功");
-        [PopupView showCusHUDA:@"清理成功"];
-    }
-    
-}
-
-//数据写入沙河
--(void)writeFileToplist{
-    
-    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
-    //获取完整路径
-    NSString *documentsDirectory = [paths objectAtIndex:0];
-    NSString *filePath = [documentsDirectory stringByAppendingPathComponent:JBSDKLog];//这里就是你将要存储的沙盒路径(.plist文件,名字自定义)
-
-    if(![[NSFileManager defaultManager] fileExistsAtPath:filePath]){//plistPath这个文件\文件夹是否存在
-
-        NSLog(@"-------文件不存在,写入文件----------");
-
-               NSError *error;
-               if([self.tempStepString writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:&error]){
-                   NSLog(@"------写入文件------success");
-               }else{
-                    NSLog(@"------写入文件------fail,error==%@",error);
-               };
-
-    }else{
-
-//     NSLog(@"-------文件存在,追加文件----------");
-       NSFileHandle *fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:filePath];
-       [fileHandle seekToEndOfFile];  //将节点跳到文件的末尾
-       NSData* stringData  = [self.tempStepString dataUsingEncoding:NSUTF8StringEncoding];
-       [fileHandle writeData:stringData]; //追加写入数据
-       [fileHandle closeFile];
-
-    }
-
-}
-
--(void)uploadpPlistFile{
-    
-    //这个方法获取出的结果是一个数组.因为有可以搜索到多个路径.
-    NSArray *array =  NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
-    //在这里,我们指定搜索的是Cache目录,所以结果只有一个,取出Cache目录
-    NSString *documentsDirectory = array[0];
-//    NSLog(@"%@",documentsDirectory);
-    //拼接文件路径
-    NSString *filePathName = [documentsDirectory stringByAppendingPathComponent:JBSDKLog];
-    //如果保存的是一个数组.那就通过数组从文件当中加载.
-    NSString *string = [NSString stringWithContentsOfFile:filePathName encoding:NSUTF8StringEncoding error:nil];
-//    NSLog(@"%@",string);
-    //4.设置请求体
-    NSData *upData = [string dataUsingEncoding:NSUTF8StringEncoding];
-    //
-    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
-    manager.requestSerializer.timeoutInterval=15;
-    [manager.requestSerializer setValue:@"multipart/form-data" forHTTPHeaderField:@"Content-Type"];
-    manager.requestSerializer = [AFJSONRequestSerializer serializer];
-    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain",@"text/html",@"application/json",@"text/javascript",@"image/jpeg",@"image/png",@"application/octet-stream",@"application/x-www-form-urlencoded", nil];
-    //    NSLog(@"请求URL ===================>> %@",urlString);
-    NSLog(@"******************* 请求头参数 = %@ ***************************",manager.requestSerializer.HTTPRequestHeaders);
-    
-    AFHTTPSessionManager *sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:nil];
-    [sessionManager POST:@"http://172.16.14.127:8080/upload" parameters:nil headers:nil constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData){
-
-        [formData  appendPartWithFileData:upData name:@"file" fileName:[NSString stringWithFormat:@"ios_%@_%@.txt",Game_Type,[self getNowTimeTimestamp]] mimeType:@"text/plain"];
-
-        }progress:^(NSProgress * _Nonnull uploadProgress){
-            NSLog(@"上传进度 = %@",uploadProgress);
-
-        }success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject){
-            NSLog(@"上传成功");
-
-        }failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error){
-
-            for (NSString * key  in error.userInfo){
-
-                if ([key isEqualToString:@"com.alamofire.serialization.response.error.data"]){
-
-                    id errorObject = [NSJSONSerialization JSONObjectWithData:error.userInfo[key] options:1  error:nil];
-
-                    NSLog(@"上传失败 ===>> %@",errorObject);
-                    if (errorObject !=nil && [errorObject isKindOfClass:[NSDictionary class]]){
-                        NSString * result = errorObject[@"result"];
-                        if ([result intValue] ==1){
-                            [PopupView showCusHUDA:@"上传成功"];
-                        }
-                        
-                    }
-
-                }
-                
-          }
-            
-    }];
- 
-}
-
-//获取当前时间戳有两种方法(以秒为单位)
--(NSString *)getNowTimeTimestamp{
-
-    NSDateFormatter *formatter = [[NSDateFormatter alloc] init] ;
-
-    [formatter setDateStyle:NSDateFormatterMediumStyle];
-
-    [formatter setTimeStyle:NSDateFormatterShortStyle];
-
-    [formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"]; // ----------设置你想要的格式,hh与HH的区别:分别表示12小时制,24小时制
-
-    //设置时区,这个对于时间的处理有时很重要
-
-    NSTimeZone* timeZone = [NSTimeZone timeZoneWithName:@"Asia/Shanghai"];
-
-    [formatter setTimeZone:timeZone];
-
-    NSDate *datenow = [NSDate date];//现在时间,你可以输出来看下是什么格式
-
-    NSString *timeSp = [NSString stringWithFormat:@"%ld", (long)[datenow timeIntervalSince1970]];
-
-    return timeSp;
-
-}
-   
-@end

+ 14 - 3
SDK/BLE/LEONBLManager.h

@@ -9,7 +9,7 @@
 #import <CoreBluetooth/CoreBluetooth.h>
 
 //设备类型
-typedef NS_ENUM(NSInteger, DEVICE_TYPE){
+typedef NS_ENUM(int, DEVICE_TYPE){
     DEVICETYPE_MAIN =0, //主设备
     DEVICETYPE_VICE, //副设备
 };
@@ -42,7 +42,7 @@ typedef void(^LEDiscoveredServicesBlock)(CBPeripheral *peripheral, NSArray *serv
 typedef void(^LEDiscoverCharacteristicsBlock)(CBPeripheral *peripheral, CBService *service, NSArray *characteristics, NSError *error);
 
 /** 收到摸个特性中数据的回调 */
-typedef void(^LEReadValueForCharacteristicBlock)(CBPeripheral *peripheral,CBCharacteristic *characteristic, NSData *value, NSError *error,DEVICE_TYPE type);
+typedef void(^LEReadValueForCharacteristicBlock)(CBPeripheral *peripheral,CBCharacteristic *characteristic, NSData *value, NSError *error);
 
 /** 往特性中写入数据的回调 */
 typedef void(^LEWriteToCharacteristicBlock)(CBPeripheral *peripheral,CBCharacteristic *characteristic, NSError *error,DEVICE_TYPE type);
@@ -78,6 +78,17 @@ typedef void(^RSSIBlock)(NSNumber *RSSI);
 @property(nonatomic,strong)CBCharacteristic * viceWrite;
 @property(nonatomic,strong)CBCharacteristic * viceRead;
 
+//防止同一条数据回调多次
+@property(assign,nonatomic)int main_read;
+@property(assign,nonatomic)int vice_read;
+
+/**测试参数start*/
+@property(assign,nonatomic)int totalPackages;
+@property(assign,nonatomic)int totalLoss;
+@property(assign,nonatomic)int tempTs;
+@property(nonatomic,assign) NSNumber *RSSI;//设备到手机的实时信号强度
+/**测试参数end*/
+
 /**
  声明单例类
  */
@@ -111,7 +122,7 @@ typedef void(^RSSIBlock)(NSNumber *RSSI);
  外部主动断开蓝牙链接
  @param peripheral 待断开的CBPeripheral对象
  */
-- (void)cancelPeripheralConnection;
+- (void)cancelPeripheralConnection:(int)type;
 
 #pragma mark -------------- public methon ==>> 外部 操作 CBPeripheral
 

+ 58 - 32
SDK/BLE/LEONBLManager.m

@@ -5,6 +5,7 @@
 //  Created by Leon on 2021/4/23.
 
 #import "LEONBLManager.h"
+#import "AlgorithmTool.h"
 
 //CBCentralManagerDelegate 蓝牙外设回调代理
 //CBPeripheralDelegate 蓝牙链接后的数据回调代理
@@ -60,6 +61,7 @@ static LEONBLManager * instance;
 //    NSDictionary *options = @{CBCentralManagerOptionShowPowerAlertKey:@(YES)};
     NSDictionary *options = @{CBCentralManagerScanOptionAllowDuplicatesKey:@(YES)};
     self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue() options:options];
+    NSLog(@"LEONBLManager ===>> initCBCentralManager");
     
 }
 
@@ -71,7 +73,7 @@ static LEONBLManager * instance;
  */
 - (void)scanForPeripheralsWithServices:(nullable NSArray<CBUUID *> *)serviceUUIDs options:(nullable NSDictionary<NSString *, id> *)options{
     [self.centralManager scanForPeripheralsWithServices:serviceUUIDs options:options];
-//    NSLog(@"开始扫描外设");
+    NSLog(@"开始扫描外设");
 }
 
 /**
@@ -83,12 +85,12 @@ static LEONBLManager * instance;
 }
  
 /**
- 外部主动断开蓝牙链接
+ 外部主动链接蓝牙
  @param peripheral 待链接的CBPeripheral对象
  @param options 一个可选的字典,指定连接行为选项
  */
 - (void)connectPeripheral:(CBPeripheral *)peripheral options:(nullable NSDictionary<NSString *, id> *)options{
-    
+       
     if (peripheral==self.peripheral){
         [self.centralManager connectPeripheral:self.peripheral options:options];
         NSLog(@"主设备 主动连接蓝牙外设 = %@  %p  %p",self.peripheral.name,self.peripheral,peripheral);
@@ -103,18 +105,17 @@ static LEONBLManager * instance;
  外部主动断开蓝牙链接
  @param peripheral 待断开的CBPeripheral对象
  */
-- (void)cancelPeripheralConnection{
+- (void)cancelPeripheralConnection:(int)type{
     
-    if (self.peripheral!=nil){
-        
+    if (self.peripheral!=nil&&type==0){
         [self.centralManager cancelPeripheralConnection:self.peripheral];
-        NSLog(@"主动断开蓝牙链接 = %@",self.peripheral.name);
+        NSLog(@"主设备 主动断开蓝牙链接 = %@",self.peripheral.name);
 //        self.peripheral = nil;
 
-    }else if (self.vicePeripheral!=nil){
+    }else if (self.vicePeripheral!=nil&&type==1){
         
         [self.centralManager cancelPeripheralConnection:self.vicePeripheral];
-        NSLog(@"主动断开蓝牙链接 = %@",self.vicePeripheral.name);
+        NSLog(@"副设备 主动断开蓝牙链接 = %@",self.vicePeripheral.name);
 //        self.vicePeripheral = nil;
 
     }
@@ -204,7 +205,7 @@ static LEONBLManager * instance;
     
 }
 
-//丢失蓝牙链接
+//蓝牙链接断开
 - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error{
     
     if (_disConnectBlock){
@@ -228,20 +229,16 @@ static LEONBLManager * instance;
     }
     
     if (peripheral == self.peripheral){
-        
-        for (CBService * service in peripheral.services){
-                
-            NSLog(@"主设备发现 %@ 的服务值:%@ 开始查找它的特征",peripheral.name,service);
-
-        }
-        
+            NSLog(@"主设备发现 %@ 的服务值:%@ 开始查找它的特征",peripheral.name,peripheral.services);
     }else if (peripheral == self.vicePeripheral){
-        NSLog(@"副设备发现 %@ 的服务值:%@ 开始查找它的特征",peripheral.name,peripheral.services);
+           NSLog(@"副设备发现 %@ 的服务值:%@ 开始查找它的特征",peripheral.name,peripheral.services);
     }
     
     //扫描所有的特征
     for (CBService *service in peripheral.services){
-    [peripheral discoverCharacteristics:nil forService:service];
+//        NSLog(@"扫描所有的特征 %@",service);
+//        peripheral.delegate = self;
+        [peripheral discoverCharacteristics:nil forService:service];
     }
     
 }
@@ -250,10 +247,10 @@ static LEONBLManager * instance;
 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(nullable NSError *)error{
     
 //    NSLog(@"发现所有服务+特征的值  %p  %p %p",self.peripheral,self.vicePeripheral,peripheral);
-
+    __weak __typeof(self)weakself = self;
     if (_discoverCharacteristicsBlock){
         
-        if (peripheral==self.peripheral){
+        if (peripheral == weakself.peripheral){
             
             _discoverCharacteristicsBlock(peripheral,service,service.characteristics,error);
             
@@ -271,7 +268,7 @@ static LEONBLManager * instance;
 
             }
 
-        }else if (peripheral == self.vicePeripheral){
+        }else if (peripheral == weakself.vicePeripheral){
             
             _discoverCharacteristicsBlock(peripheral,service,service.characteristics,error);
             NSLog(@"副设备 发现 %@ 服务+特征",peripheral.name);
@@ -285,18 +282,45 @@ static LEONBLManager * instance;
 //收到数据的回调
 - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
     
+    __weak __typeof(self)weakself = self;
     if (_readValueForCharacteristicBlock){
-        
+                
         NSData *data = characteristic.value;
 
-        if (peripheral==self.peripheral){
+        if (peripheral == weakself.peripheral){
             
-            _readValueForCharacteristicBlock(self.peripheral,characteristic,data,error,DEVICETYPE_MAIN);
-//            NSLog(@"收到主设备 %@ 推送的报文 %@",peripheral.name,data);
+            if (characteristic.value.length >60){
 
-        }else if (peripheral == self.vicePeripheral){
+                weakself.main_read = 0;
+
+                int newTs = [AlgorithmTool dataToChar:[characteristic.value subdataWithRange:NSMakeRange(54, 1)]];;//ts 时间戳
+
+                self.totalPackages++;
+                int total_loss = self.tempTs - abs(newTs);
+                int abs_loss = abs(total_loss);
+//                NSLog(@"收到主设备 推送的报文 时间戳 ================ >>%d %d 【%d - %d = %d】",self.totalPackages,newTs,self.tempTs,abs(newTs),abs_loss);
+
+                if (abs_loss>2){
+                self.totalLoss = self.totalLoss+(abs_loss/2-1);
+//                NSLog(@"系统api丢包 ===================================================================== >> %d %d/%d",abs_loss/2-1,self.totalLoss,self.totalPackages);
+                }
+
+                self.tempTs = abs(newTs);
+
+            }
+            
+            _readValueForCharacteristicBlock(weakself.peripheral,characteristic,data,error);
+//            NSLog(@"收到主设备 %@ 推送的报文 %@",peripheral.name,data);
+           
+        }else if (peripheral == weakself.vicePeripheral){
             
-            _readValueForCharacteristicBlock(self.vicePeripheral,characteristic,data,error,DEVICETYPE_VICE);
+            if (characteristic.value.length >60){
+//                int ts = [AlgorithmTool dataToChar:[characteristic.value subdataWithRange:NSMakeRange(54, 1)]];;//ts 时间戳
+//                NSLog(@"收到副设备 推送的报文 时间戳 ==============>> %d",ts);
+                weakself.vice_read = 0;
+            }
+            
+            _readValueForCharacteristicBlock(weakself.vicePeripheral,characteristic,data,error);
 //            NSLog(@"收到副设备 %@ 推送的报文 %@",peripheral.name,data);
 
         }
@@ -308,16 +332,18 @@ static LEONBLManager * instance;
 //写入数据的回调
 - (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error{
   
+    __weak __typeof(self)weakself = self;
+
     if (_writeToCharacteristicBlock){
         
-        if (peripheral==self.peripheral){
+        if (peripheral==weakself.peripheral){
             
-            _writeToCharacteristicBlock(self.peripheral,characteristic,error,DEVICETYPE_MAIN);
+            _writeToCharacteristicBlock(weakself.peripheral,characteristic,error,DEVICETYPE_MAIN);
 //            NSLog(@"收到主设备 %@ 的response",peripheral.name);
 
-        }else if (peripheral == self.vicePeripheral){
+        }else if (peripheral == weakself.vicePeripheral){
             
-            _writeToCharacteristicBlock(self.vicePeripheral,characteristic,error,DEVICETYPE_VICE);
+            _writeToCharacteristicBlock(weakself.vicePeripheral,characteristic,error,DEVICETYPE_VICE);
 //            NSLog(@"收到附设备 %@ 的response",peripheral.name);
 
         }

+ 0 - 51
SDK/BLE/MainShoesAnalysis.h

@@ -1,51 +0,0 @@
-////
-////  MainShoesAnalysis.h
-////  Unity-iPhone
-////
-////  Created by duowan123 on 2021/12/4.
-////
-//
-//#import <Foundation/Foundation.h>
-//#import "MYFactoryManager.h"
-//
-//NS_ASSUME_NONNULL_BEGIN
-//
-//@interface MainShoesAnalysis : NSObject
-//
-//
-//+(instancetype)sharedInstance;
-//
-////弹窗 unity主动选择链接 主0 副1 设备
-//@property(assign,nonatomic)DEVICE_TYPE deviceType;
-////游戏种类 1是跳舞 3是跑酷 2是赛达尔传说 4是demo->dance
-//@property(assign,nonatomic)GAME_TYPE game_type;
-//
-////主设备跳起 下蹲 步数 的总数
-//@property(assign,nonatomic)int initial_jump_count;
-//@property(assign,nonatomic)int initial_down_count;
-////步数回调缓存
-//@property(copy,nonatomic)void (^allMotionCountBLock)(int jump_count,int crouch_count,int step_count);//蓝牙设备数据源
-////脚步交互数据
-//@property(copy,nonatomic)void (^getInteractionBlock)(int interaction);//蓝牙设备数据源
-//
-//@property(assign,nonatomic)int isBackGround;//程序在前台还是后台
-//
-//@property(nonatomic,assign)BOOL gameModel;//是否开启游戏模式
-//
-///*****测试*******/
-//@property (nonatomic,strong)UILabel * testLabel;//调试框
-//@property (nonatomic,strong)UIButton * uploadButton;//上传
-//@property (nonatomic,strong)UIButton * clearnButton;//上传
-//
-////当前的时间戳+丢包
-//@property (nonatomic,assign)int  tempTs;
-//@property (nonatomic,assign)int  loss;
-//@property (nonatomic,assign)int  totalPackages;
-//@property (nonatomic,strong)NSString * tempStepString;//剑波要的字符串数据 缓存plist
-//@property(nonatomic,assign) NSNumber *RSSI;//威严要的测试数据
-//@property(nonatomic,assign) int currentTS;//颖嘉要的测试数据
-//
-//
-//@end
-//
-//NS_ASSUME_NONNULL_END

+ 0 - 551
SDK/BLE/MainShoesAnalysis.mm

@@ -1,551 +0,0 @@
-////
-////  MainShoesAnalysis.m
-////  Unity-iPhone
-////
-////  Created by duowan123 on 2021/12/4.
-////
-//
-//#import "MainShoesAnalysis.h"
-//
-//@interface MainShoesAnalysis()
-//{
-//@private
-//Game *game;
-//}
-//
-//@end
-//
-//@implementation MainShoesAnalysis
-//
-////单例静态
-//static MainShoesAnalysis* instance = nil;
-//+(instancetype)sharedInstance{
-////    NSLog(@"创建单例一次 1");
-//     return [[self alloc] init];
-//}
-//
-//+ (instancetype)allocWithZone:(struct _NSZone *)zone{
-////    NSLog(@"创建单例一次 2");
-//  static dispatch_once_t onceToken;
-//  dispatch_once(&onceToken, ^{
-//      instance = [super allocWithZone:zone];
-//  });
-//  return instance;
-//}
-//
-//- (instancetype)init{
-////    NSLog(@"创建单例一次 3");
-//    static dispatch_once_t onceToken;
-//    dispatch_once(&onceToken, ^{
-//        instance = [super init];
-//    });
-//    return instance;
-//}
-//
-//#pragma mark ===============================================>> 校验 & 报文数据解析
-//-(void)verifyData:(CBCharacteristic*)characteristic deviceType:(DEVICE_TYPE)deviceType{
-//    
-//     if (characteristic.value.length>3){
-//         
-//         //带cmd位的有效数据  计算校验位
-//         if ([AlgorithmTool verificationRusult:characteristic.value]==YES){
-//             
-//             [self analysisCharacteristic:characteristic.value deviceType:deviceType];
-//                              
-//         }
-//         
-//     }else{
-//         
-//         NSLog(@"无效报文");
-//         
-//     }
-//     
-//}
-//
-//-(void)analysisCharacteristic:(NSData*)characteristic deviceType:(DEVICE_TYPE)deviceType{
-//        
-////        NSLog(@"接收到的数据data = %@",characteristic);
-//    
-//    int frameHead = [AlgorithmTool dataToChar:[characteristic subdataWithRange:NSMakeRange(0, 1)]];//帧头数据aa
-//    int messageLength = [AlgorithmTool dataToChar:[characteristic subdataWithRange:NSMakeRange(1, 1)]];//报文长度
-//    int messageLengthNegation = ~messageLength;//报文长度取反
-//    int dataType = [AlgorithmTool dataToChar:[characteristic subdataWithRange:NSMakeRange(3, 1)]];//cmd类型
-//    
-//      if (dataType == 4){//获取主动推过来的数据
-//            //右脚坐标数据
-//           int right_X = [AlgorithmTool dataToSwapBigIntToHost:characteristic andRange:NSMakeRange(4, 4)];
-//           int right_Y = [AlgorithmTool dataToSwapBigIntToHost:characteristic andRange:NSMakeRange(8, 4)];
-//           int right_Z = [AlgorithmTool dataToSwapBigIntToHost:characteristic andRange:NSMakeRange(12, 4)];
-//           int  right_pos[3] = {right_X,right_Y,right_Z};
-//          //左脚坐标数据
-//           int left_X = [AlgorithmTool dataToSwapBigIntToHost:characteristic andRange:NSMakeRange(16, 4)];
-//           int left_Y = [AlgorithmTool dataToSwapBigIntToHost:characteristic andRange:NSMakeRange(20, 4)];
-//           int left_Z = [AlgorithmTool dataToSwapBigIntToHost:characteristic andRange:NSMakeRange(24, 4)];
-//           int  left_pos[3] = {left_X,left_Y,left_Z};
-//           //右脚姿势数据
-//           short righrPosture_X = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(28, 2)];
-//           short righrPosture_Y = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(30, 2)];
-//           short righrPosture_Z = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(32, 2)];
-//           int  right_att[3] = {righrPosture_X,righrPosture_Y,righrPosture_Z};
-//           //左脚姿势数据
-//           short leftPosture_X = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(34, 2)];
-//           short leftPosture_Y = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(36, 2)];
-//           short leftPosture_Z = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(38, 2)];
-//           int  left_att[3] = {leftPosture_X,leftPosture_Y,leftPosture_Z};
-//           //右脚三维数据
-//           short righrAcc_x = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(40, 2)];
-//           short righrAcc_Y = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(42, 2)];
-//           short righrAcc_z = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(44, 2)];
-//           int  righrAcc[3] = {righrAcc_x,righrAcc_Y,righrAcc_z};
-//           //左脚三维数据
-//           short leftAcc_x = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(46, 2)];
-//           short leftAcc_y = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(48, 2)];
-//           short leftAcc_z = [AlgorithmTool dataToSwapBigShortToHost:characteristic andRange:NSMakeRange(50, 2)];
-//           int  left_acc[3] = {leftAcc_x,leftAcc_y,leftAcc_z};
-//           //左脚、右脚、蹲 、跳四个动作信息数据
-//           int actionInformation =  [AlgorithmTool dataToChar:[characteristic subdataWithRange:NSMakeRange(52, 1)]];;//0c 16进制字符串
-//                       int girlShoes  = actionInformation & 16;
-//                       if (girlShoes!=0){
-//                           girlShoes=1;
-//                       }else{
-//                           girlShoes=0;
-//                       }
-//                       int rightZupt  = actionInformation & 8;
-//                       if (rightZupt!=0){
-//                           rightZupt=1;
-//                       }else{
-//                           rightZupt=0;
-//                       }
-//                       int leftZupt = actionInformation & 4;
-//                       if (leftZupt!=0){
-//                            leftZupt=1;
-//                        }else{
-//                            leftZupt=0;
-//                        }
-//                       int down  = actionInformation & 2;
-//                       if (down!=0){
-//                            down=1;
-//                        }else{
-//                            down=0;
-//                        }
-//                       int jump  = actionInformation & 1;
-//                       if (jump!=0){
-//                            jump=1;
-//                        }else{
-//                            jump=0;
-//                        }
-//          
-//            int rssi = [AlgorithmTool dataToChar:[characteristic subdataWithRange:NSMakeRange(53, 1)]];//rssi 信号强度
-//            int ts = [AlgorithmTool dataToChar:[characteristic subdataWithRange:NSMakeRange(54, 1)]];;//ts 时间戳
-//            int right_press = [AlgorithmTool dataToInt:[characteristic subdataWithRange:NSMakeRange(55, 2)]];//3 29新增 右鞋压力
-//            int left_press = [AlgorithmTool dataToInt:[characteristic subdataWithRange:NSMakeRange(57, 2)]];//3 29新增 左鞋压力
-//            int frameCheck =  [AlgorithmTool dataToChar:[characteristic subdataWithRange:NSMakeRange(59, 1)]];//校验位
-//        
-//               if (deviceType==DEVICETYPE_MAIN){//主设备
-//                   
-////                   NSLog(@"主设备 接收到 鞋子动作数据 data = %@",characteristic);
-//                   //调取鞋子SDK
-//                   [self shoseSDKRight_pos:right_pos Right_att:right_att Right_acc:righrAcc LeftPos:left_pos Left_att:left_att Left_acc:left_acc ts:ts rightZupt:rightZupt leftZupt:leftZupt jump:jump down:down rssi:rssi girlShoes:girlShoes right_press:right_press left_press:left_press characteristic:characteristic];
-//                   
-//               }else if (deviceType==DEVICETYPE_VICE){//副设备动作数据
-//                   
-////                   NSLog(@"副设备 接收到 鞋子动作数据 data = %@",characteristic);
-//                   //调取鞋子SDK
-//  
-//                   
-//               }
-//              
-//        }else if (dataType == -95){//获取的是查询的数据 char-->int a1 = -95
-//
-//            if (characteristic.length == 74){//A1+0  >> 0: 设备基本信息 ==>> 预留参数 趣动app用 sdk暂未调用
-//                
-////                NSString *deviceModel = [[NSString alloc] initWithData:[characteristic subdataWithRange:NSMakeRange(5, 18)] encoding:NSUTF8StringEncoding];
-////                NSString *softwareVer = [AlgorithmTool hexadecimalString:[characteristic subdataWithRange:NSMakeRange(69, 2)]];//0102
-////                NSString *hardwareVer = [AlgorithmTool hexadecimalString:[characteristic subdataWithRange:NSMakeRange(71, 2)]];//0104
-//                
-//            }else if (characteristic.length == 26){//A1+1 >> 1: 设备数据(左鞋,右鞋)  aa 14 eb a1 01 64 00 1a 0000981d 64 00 17 00000000 f9
-//                
-//                int leftElectricity = [AlgorithmTool dataToInt:[characteristic subdataWithRange:NSMakeRange(5, 1)]];
-////                int leftTempreature = [AlgorithmTool dataToInt:[characteristic subdataWithRange:NSMakeRange(6, 1)]];
-////                int leftPressure = [AlgorithmTool dataToInt:[characteristic subdataWithRange:NSMakeRange(7, 4)]];
-////                int leftStepCount = [AlgorithmTool dataToInt:[characteristic subdataWithRange:NSMakeRange(11, 4)]];
-////                int rightElectricity = [self dataToInt:[characteristic subdataWithRange:NSMakeRange(12, 1)]];
-//                int rightElectricity = [AlgorithmTool dataToInt:[characteristic subdataWithRange:NSMakeRange(15, 1)]];//龙哥新协议
-////                int rightTempreature = [AlgorithmTool dataToInt:[characteristic subdataWithRange:NSMakeRange(16, 1)]];
-////                int rightPressure = [AlgorithmTool dataToInt:[characteristic subdataWithRange:NSMakeRange(17, 4)]];
-////                int rightStepCount = [AlgorithmTool dataToInt:[characteristic subdataWithRange:NSMakeRange(21, 4)]];
-//                
-//                if (deviceType==DEVICETYPE_MAIN && LEManager.peripheral!=nil){//主设备
-//                    
-////                    NSLog(@"主设备 接收到 鞋子硬件数据 data 26 = %@  电量 %d %d %@ %@",characteristic,leftElectricity,rightElectricity,LEManager.peripheral.name,LEManager.peripheral.identifier.UUIDString);
-//
-//                    //主 设备定时器 60秒调一次   /******************ios call unity*****************/
-//                     [[IOSPlatformSDK sharedInstance] bridgingDeviceAction:DEVICETYPE_MAIN
-//                                                 name:LEManager.peripheral.name
-//                                              address:LEManager.peripheral.identifier.UUIDString
-//                                               status:CONNECT_ED
-//                                          electricity:20];
-//             
-//                }else if (deviceType==DEVICETYPE_VICE && LEManager.vicePeripheral!=nil){//副设备
-//                    
-//                    NSLog(@"副设备 接收到 鞋子硬件数据 26 = %@  电量 %d %d",characteristic,leftElectricity,rightElectricity);
-//
-//                    //副 设备定时器 60秒调一次   /******************ios call unity*****************/
-//                     [[IOSPlatformSDK sharedInstance] bridgingDeviceAction:DEVICETYPE_VICE
-//                                                 name:LEManager.vicePeripheral.name
-//                                              address:LEManager.vicePeripheral.identifier.UUIDString
-//                                               status:CONNECT_ED
-//                                          electricity:leftElectricity<=rightElectricity?leftElectricity:rightElectricity];
-//                    
-//                }
-//             
-//           }
-//            
-//      }
-//    
-//}
-//
-//#pragma mark ===============================================>> 主设备 报文数据解析后 -- 调用蓝牙鞋子SDK装换数据 -- ios call unity 更新游戏动作
-//-(void)shoseSDKRight_pos:(int[3])right_pos
-//               Right_att:(int[3])right_att
-//               Right_acc:(int[3])right_acc
-//                 LeftPos:(int[3])left_pos
-//                Left_att:(int[3])left_att
-//                Left_acc:(int[3])left_acc
-//                      ts:(int)ts
-//               rightZupt:(int)rightZupt
-//                leftZupt:(int)leftZupt
-//                    jump:(int)jump
-//                    down:(int)down
-//                    rssi:(int)rssi
-//               girlShoes:(int)girlShoes
-//             right_press:(int)right_press
-//              left_press:(int)left_press
-//          characteristic:(NSData*)characteristic{
-//    
-//    /********************初始化 运动轨迹算法 SDK *****************/
-//    //游戏数据
-//    NSData * validData= [characteristic subdataWithRange:NSMakeRange(4, characteristic.length-4)];
-//    Byte * buff = (Byte*)[validData bytes];
-//    game->GameProcessBuf(buff, (int)validData.length);
-//    
-//    int length = 4;
-//    int result[length];
-//    game->getGameResult(result);
-//    //   NSLog(@"result == %d %d %d %d \n",result[0],result[1],result[2],result[3]);
-//
-//    
-//    /******************步频数据处理 + 回调*****************/
-//    int leftStepStatus =  game->getStepStatus(LEFT_FOOT);
-//    int leftStepFreq =  game->getStepFreq(LEFT_FOOT);
-//    int leftStepCount =  game->getStepCount(LEFT_FOOT);
-//    int rightStepStatus =  game->getStepStatus(RIGHT_FOOT);
-//    int rightStepFreq =  game->getStepFreq(RIGHT_FOOT);
-//    int rightStepCount =  game->getStepCount(RIGHT_FOOT);
-//        
-//    /******************左右脚动作数据处理 + 回调*****************/
-//    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;
-////    }else{
-//        //跳跃和蹲下的动作 双脚是同步的
-//        if (motionJump == MOTION_JUMP){
-//            motionLeft = motionJump;
-//            motionRight = motionJump;
-//            NSLog(@" 主设备 ================================== 跳起来 ");
-//        }
-//    
-//        if (motionDown == MOTION_DOWN){
-//            motionLeft = motionDown;
-//            motionRight = motionDown;
-//            NSLog(@" 主设备 =================================== 蹲下去 ");
-//        }
-////    }
-//    
-//    /****************** ios call unity*****************/
-//        if (self.gameModel==YES){//当前是游戏模式
-//
-//            //跑酷需要回调步频
-//            if (self.game_type == GAME_TYPE_RUN){
-//                [[IOSPlatformSDK sharedInstance] bridgingStepAction:DEVICETYPE_MAIN leftStatus:leftStepStatus rightStatus:rightStepStatus leftFrag:leftStepFreq rightFrag:rightStepFreq];
-//            }
-//            //左右脚动作
-//            [[IOSPlatformSDK sharedInstance] bridgingMotionAction:DEVICETYPE_MAIN left:motionLeft right:motionRight];
-//
-//        }else{//当前是交互模式
-//
-//            int interaction = game->getInteractionCMD();
-////            NSLog(@"主设备 当前的脚步交互动作 ===== >> %d",interaction);
-//            [[IOSPlatformSDK sharedInstance] bridgingInteraction:DEVICETYPE_MAIN code:interaction];
-//            if (self.getInteractionBlock){
-//                self.getInteractionBlock(interaction);
-//            }
-//        }
-//    
-//    /******************数据回调缓存*****************/
-//    //标记初始值
-//    if (self.initial_jump_count==0){
-//        self.initial_jump_count = game->getGameJumpCount();
-//    }
-//    if (self.initial_down_count==0) {
-//        self.initial_down_count = game->getGameDownCount();
-//    }
-//    //总数
-//    int total_jump_count = game->getGameJumpCount();
-//    int total_dump_count = game->getGameDownCount();
-//    //当局游戏次数
-//    int current_jump_count = total_jump_count - self.initial_jump_count;
-//    int current_dump_count = total_dump_count - self.initial_down_count;
-//    //数据回调缓存
-//    if (self.allMotionCountBLock){
-//        self.allMotionCountBLock(current_jump_count, current_dump_count, leftStepCount + rightStepCount);
-//    }
-//    
-//    /********************剑波 & 威严 要的图表数据 *****************/
-//    NSString * aString = [NSString stringWithUTF8String:game->getGameDataStr().c_str()];
-//    if (self.RSSI==nil){
-//        self.RSSI = 0;
-//    }
-//     aString = [NSString stringWithFormat:@"%@,%@",aString,self.RSSI];
-//    self.tempStepString = [NSString stringWithFormat:@"%@\n",aString];
-//    if (self.tempStepString!=nil && self.tempStepString.length>1){
-//        [self writeFileToplist];
-//    }
-//  
-//    /********************调试窗数据 *****************/
-//    NSArray *aArray = [self.tempStepString componentsSeparatedByString:@","];
-////    dispatch_async(dispatch_get_main_queue(), ^{
-//        if (self.testLabel!=nil){
-//            self.testLabel.text = [NSString stringWithFormat:@"right:[%d,%d,%d] [%d,%d,%d] [%d,%d,%d] \nleft:[%d,%d,%d] [%d,%d,%d] [%d,%d,%d] \nZupt:[%d,%d]  press:[%d,%d] \nj&d[%d %d]  rssi:[%d %@] ts:%d \n脚步: %@ %@\n步频: %d %d ",right_pos[0],right_pos[1],right_pos[2],right_att[0],right_att[1],right_att[2],right_acc[0],right_acc[1],right_acc[2],left_pos[0],left_pos[1],left_pos[2],left_att[0],left_att[1],left_att[2],left_acc[0],left_acc[1],left_acc[2],rightZupt,leftZupt,right_press,left_press,jump,down,rssi,self.RSSI,ts,aArray[aArray.count-2],aArray.lastObject,leftStepFreq,rightStepFreq];
-//        }
-////    });
-//    
-//    /********************颖嘉+的ts丢包数据 *****************/
-//    NSString * tsString =  aArray[aArray.count-4];
-//    int tsInt = [tsString  intValue];
-//    int total;
-//    //1....255
-//    if (tsInt > self.currentTS){
-//         total = tsInt - self.currentTS - 1;
-//    }
-//    //255...1
-//    if (tsInt < self.currentTS){
-//        if (tsInt ==0) {
-//            total = (255-self.currentTS) + tsInt + 1 - 1;
-//        }else{
-//            total = (255-self.currentTS) + tsInt - 1;
-//        }
-//    }
-////    NSLog(@"tsInt = %d  currentTS = %d total = %d",tsInt,self.currentTS,total);
-//    if (total > 20){
-//        dispatch_async(dispatch_get_main_queue(), ^{
-//            AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
-//            [PopupView showCusHUDA:[NSString stringWithFormat:@"丢包数: %d",total]];
-//        });
-//    }
-//    self.currentTS = tsInt;
-//    
-//}
-//
-//
-//#pragma mark ===============================================>> DEBUG
-//-(void)inittestLabel{
-//
-//    if (self.testLabel!=nil){
-//        [self.testLabel removeFromSuperview];
-//    }
-//    
-//    if (self.uploadButton!=nil){
-//        [self.uploadButton removeFromSuperview];
-//    }
-//    
-//    if (self.clearnButton!=nil){
-//        [self.clearnButton removeFromSuperview];
-//    }
-//    
-//    self.uploadButton = [UIButton buttonWithType:UIButtonTypeCustom];
-//    self.uploadButton.frame = CGRectMake(30, SCREEN_HEIGHT-40-10, SCALEoefficient(75), SCALEoefficient(30));
-//    self.uploadButton.backgroundColor = [UIColor redColor];
-//    [self.uploadButton addTarget: self action: @selector (button1BackGroundHighlighted:) forControlEvents:UIControlEventTouchDown];
-//    [self.uploadButton addTarget: self action: @selector (button1BackGroundNormal:) forControlEvents:UIControlEventTouchUpInside];
-//    [self.uploadButton setFont: [UIFont boldSystemFontOfSize:SCALEoefficient(15)]];
-//    [self.uploadButton setTitle:@"上传" forState:UIControlStateNormal];
-//    [self.uploadButton addTarget:self action:@selector(uploadpPlistFile) forControlEvents:UIControlEventTouchUpInside];
-//    
-//    self.clearnButton = [UIButton buttonWithType:UIButtonTypeCustom];
-//    self.clearnButton.frame = CGRectMake(30+SCALEoefficient(75)+20, SCREEN_HEIGHT-40-10, SCALEoefficient(75), SCALEoefficient(30));
-//    self.clearnButton.backgroundColor = [UIColor redColor];
-////    [self.clearnButton addTarget:self action:@selector(button1BackGroundHighlighted:) forControlEvents:UIControlEventTouchDown];
-////    [self.clearnButton addTarget:self action:@selector(button1BackGroundNormal:) forControlEvents:UIControlEventTouchUpInside];
-//    [self.clearnButton setFont: [UIFont boldSystemFontOfSize:SCALEoefficient(15)]];
-//    [self.clearnButton setTitle:@"清理缓存" forState:UIControlStateNormal];
-//    [self.clearnButton addTarget:self action:@selector(clearCacheWithFilePath) forControlEvents:UIControlEventTouchUpInside];
-//    
-//    self.testLabel = [[UILabel alloc] initWithFrame:CGRectMake(SCALEoefficient(20), 0, [UIScreen mainScreen].bounds.size.width-100, SCALEoefficient(160))];
-//    self.testLabel.textColor = [UIColor redColor];
-//    self.testLabel.font = [UIFont boldSystemFontOfSize:SCALEoefficient(14)];
-//    self.testLabel.backgroundColor = [UIColor clearColor];
-//    self.testLabel.textAlignment = NSTextAlignmentCenter;
-//    self.testLabel.numberOfLines = 0;
-//
-//    if ([UIApplication sharedApplication].keyWindow != nil){
-//        [[UIApplication sharedApplication].keyWindow addSubview:self.uploadButton];
-//        [[UIApplication sharedApplication].keyWindow addSubview:self.clearnButton];
-//        [[UIApplication sharedApplication].keyWindow addSubview:self.testLabel];
-//    }
-//
-//}
-//
-////  button普通状态下的背景色
-//- ( void )button1BackGroundNormal:(UIButton *)sender
-//{
-//     sender.backgroundColor = [UIColor redColor];
-//}
-// 
-////  button高亮状态下的背景色
-//- ( void )button1BackGroundHighlighted:(UIButton *)sender
-//{
-//     sender.backgroundColor = [UIColor orangeColor];
-//}
-//
-//#pragma mark ===============================================>> 存储和上传数据
-//- (void)clearCacheWithFilePath{
-//    
-//    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
-//    //获取完整路径
-//    NSString *documentsDirectory = [paths objectAtIndex:0];
-//    NSString *filePath = [documentsDirectory stringByAppendingPathComponent:JBSDKLog];//这里就是你将要存储的沙盒路径(.plist文件,名字自定义)
-//    NSError *error = nil;
-//    //删除子文件夹
-//    [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
-//    if (error){
-//        NSLog(@"清理缓存失败");
-//        [PopupView showCusHUDA:@"清理失败"];
-//    }else{
-//        NSLog(@"清理缓存成功");
-//        [PopupView showCusHUDA:@"清理成功"];
-//    }
-//    
-//}
-//
-////数据写入沙河
-//-(void)writeFileToplist{
-//    
-//    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
-//    //获取完整路径
-//    NSString *documentsDirectory = [paths objectAtIndex:0];
-//    NSString *filePath = [documentsDirectory stringByAppendingPathComponent:JBSDKLog];//这里就是你将要存储的沙盒路径(.plist文件,名字自定义)
-//
-//    if(![[NSFileManager defaultManager] fileExistsAtPath:filePath]){//plistPath这个文件\文件夹是否存在
-//
-//        NSLog(@"-------文件不存在,写入文件----------");
-//
-//               NSError *error;
-//               if([self.tempStepString writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:&error]){
-//                   NSLog(@"------写入文件------success");
-//               }else{
-//                    NSLog(@"------写入文件------fail,error==%@",error);
-//               };
-//
-//    }else{
-//
-////     NSLog(@"-------文件存在,追加文件----------");
-//       NSFileHandle *fileHandle = [NSFileHandle fileHandleForUpdatingAtPath:filePath];
-//       [fileHandle seekToEndOfFile];  //将节点跳到文件的末尾
-//       NSData* stringData  = [self.tempStepString dataUsingEncoding:NSUTF8StringEncoding];
-//       [fileHandle writeData:stringData]; //追加写入数据
-//       [fileHandle closeFile];
-//
-//    }
-//
-//}
-//
-//-(void)uploadpPlistFile{
-//    
-//    //这个方法获取出的结果是一个数组.因为有可以搜索到多个路径.
-//    NSArray *array =  NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
-//    //在这里,我们指定搜索的是Cache目录,所以结果只有一个,取出Cache目录
-//    NSString *documentsDirectory = array[0];
-////    NSLog(@"%@",documentsDirectory);
-//    //拼接文件路径
-//    NSString *filePathName = [documentsDirectory stringByAppendingPathComponent:JBSDKLog];
-//    //如果保存的是一个数组.那就通过数组从文件当中加载.
-//    NSString *string = [NSString stringWithContentsOfFile:filePathName encoding:NSUTF8StringEncoding error:nil];
-////    NSLog(@"%@",string);
-//    //4.设置请求体
-//    NSData *upData = [string dataUsingEncoding:NSUTF8StringEncoding];
-//    //
-//    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
-//    manager.requestSerializer.timeoutInterval=15;
-//    [manager.requestSerializer setValue:@"multipart/form-data" forHTTPHeaderField:@"Content-Type"];
-//    manager.requestSerializer = [AFJSONRequestSerializer serializer];
-//    manager.responseSerializer.acceptableContentTypes = [NSSet setWithObjects:@"text/plain",@"text/html",@"application/json",@"text/javascript",@"image/jpeg",@"image/png",@"application/octet-stream",@"application/x-www-form-urlencoded", nil];
-//    //    NSLog(@"请求URL ===================>> %@",urlString);
-//    NSLog(@"******************* 请求头参数 = %@ ***************************",manager.requestSerializer.HTTPRequestHeaders);
-//    
-//    AFHTTPSessionManager *sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:nil];
-//    [sessionManager POST:@"http://172.16.14.127:8080/upload" parameters:nil headers:nil constructingBodyWithBlock:^(id<AFMultipartFormData>  _Nonnull formData){
-//
-//        [formData  appendPartWithFileData:upData name:@"file" fileName:[NSString stringWithFormat:@"ios_%@_%@.txt",Game_Type,[self getNowTimeTimestamp]] mimeType:@"text/plain"];
-//
-//        }progress:^(NSProgress * _Nonnull uploadProgress){
-//            NSLog(@"上传进度 = %@",uploadProgress);
-//
-//        }success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject){
-//            NSLog(@"上传成功");
-//
-//        }failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error){
-//
-//            for (NSString * key  in error.userInfo){
-//
-//                if ([key isEqualToString:@"com.alamofire.serialization.response.error.data"]){
-//
-//                    id errorObject = [NSJSONSerialization JSONObjectWithData:error.userInfo[key] options:1  error:nil];
-//
-//                    NSLog(@"上传失败 ===>> %@",errorObject);
-//                    if (errorObject !=nil && [errorObject isKindOfClass:[NSDictionary class]]){
-//                        NSString * result = errorObject[@"result"];
-//                        if ([result intValue] ==1){
-//                            [PopupView showCusHUDA:@"上传成功"];
-//                        }
-//                        
-//                    }
-//
-//                }
-//                
-//          }
-//            
-//    }];
-// 
-//}
-//
-////获取当前时间戳有两种方法(以秒为单位)
-//-(NSString *)getNowTimeTimestamp{
-//
-//    NSDateFormatter *formatter = [[NSDateFormatter alloc] init] ;
-//
-//    [formatter setDateStyle:NSDateFormatterMediumStyle];
-//
-//    [formatter setTimeStyle:NSDateFormatterShortStyle];
-//
-//    [formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"]; // ----------设置你想要的格式,hh与HH的区别:分别表示12小时制,24小时制
-//
-//    //设置时区,这个对于时间的处理有时很重要
-//
-//    NSTimeZone* timeZone = [NSTimeZone timeZoneWithName:@"Asia/Shanghai"];
-//
-//    [formatter setTimeZone:timeZone];
-//
-//    NSDate *datenow = [NSDate date];//现在时间,你可以输出来看下是什么格式
-//
-//    NSString *timeSp = [NSString stringWithFormat:@"%ld", (long)[datenow timeIntervalSince1970]];
-//
-//    return timeSp;
-//
-//}
-//   
-//@end
-//

+ 0 - 16
SDK/BLE/ViceShoesAnalysis.h

@@ -1,16 +0,0 @@
-//
-//  ViceShoesAnalysis.h
-//  Unity-iPhone
-//
-//  Created by duowan123 on 2021/12/4.
-//
-
-#import <Foundation/Foundation.h>
-
-NS_ASSUME_NONNULL_BEGIN
-
-@interface ViceShoesAnalysis : NSObject
-
-@end
-
-NS_ASSUME_NONNULL_END

+ 0 - 12
SDK/BLE/ViceShoesAnalysis.m

@@ -1,12 +0,0 @@
-//
-//  ViceShoesAnalysis.m
-//  Unity-iPhone
-//
-//  Created by duowan123 on 2021/12/4.
-//
-
-#import "ViceShoesAnalysis.h"
-
-@implementation ViceShoesAnalysis
-
-@end

+ 60 - 0
SDK/Entity /GameInfo.h

@@ -0,0 +1,60 @@
+//
+//  GameInfo.h
+//  Unity-iPhone
+//
+//  Created by duowan123 on 2022/4/28.
+//
+
+#import <Foundation/Foundation.h>
+#import "LEONBLManager.h"
+
+//游戏类型
+typedef NS_ENUM(int, GAME_TYPE){
+    GAME_TYPE_DEMO =0, //
+    GAME_TYPE_RUN, //
+    GAME_TYPE_DANCE, //
+    GAME_TYPE_H5GAME, //
+    GAME_TYPE_MONSTER, //
+    GAME_TYPE_RUINSE, //
+    GAME_TYPE_CYCLE, //
+    GAME_TYPE_BIGFOOT, //
+    GAME_TYPE_FINGERGUESSING, //
+    GAME_TYPE_AEROBICS, //
+    GAME_TYPE_KONGFU
+};
+
+@interface GameInfo : NSObject
+
+//弹窗 unity主动选择链接 主0 副1 设备
+@property(assign,nonatomic)DEVICE_TYPE deviceType;
+
+//游戏种类
+@property(assign,nonatomic)GAME_TYPE game_type;
+
+//程序在前台还是后台
+@property(assign,nonatomic)int isBackGround;
+
+//当局游戏时长
+@property(nonatomic,strong)NSDate * firstTime;
+
+//趣动跳转过来携带的的环境
+@property(nonatomic,strong)NSString * debug;
+
+//趣动判断鞋子要不要震动
+@property(nonatomic,strong)NSString * vibrate;
+
+//
+@property(nonatomic,strong)NSString * inviteInfo;
+
+//当局游戏动作数据
+@property(assign,nonatomic)int step;
+@property(assign,nonatomic)int jump;
+@property(assign,nonatomic)int crouch;
+@property(assign,nonatomic)int tick;
+@property(assign,nonatomic)int trample;
+@property(assign,nonatomic)int scissors;
+@property(assign,nonatomic)int rock;
+@property(assign,nonatomic)int paper;
+
+@end
+

+ 12 - 0
SDK/Entity /GameInfo.m

@@ -0,0 +1,12 @@
+//
+//  GameInfo.m
+//  Unity-iPhone
+//
+//  Created by duowan123 on 2022/4/28.
+//
+
+#import "GameInfo.h"
+
+@implementation GameInfo
+
+@end

+ 35 - 0
SDK/Entity /ShoesInfo.h

@@ -0,0 +1,35 @@
+//
+//  ShoesInfo.h
+//  Unity-iPhone
+//
+//  Created by duowan123 on 2022/4/28.
+//
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface ShoesInfo : NSObject
+
+//趣动跳转过来携带的mac 实际是蓝牙设备的identity
+@property(strong,nonatomic)NSString * macAddress;
+
+@property(strong,nonatomic)NSString * viceMacAddress;
+
+//鞋子是否开启游戏模式
+@property(nonatomic,assign)BOOL gameModel;
+
+//每次从趣动跳转过来 固定一个时间戳
+@property(strong,nonatomic)NSString * timestamp;
+
+//游戏鞋子状态
+@property(assign,nonatomic)int leftStepStatus;
+@property(assign,nonatomic)int leftStepFreq;
+@property(assign,nonatomic)int leftStepCount;
+@property(assign,nonatomic)int rightStepStatus;
+@property(assign,nonatomic)int rightStepFreq;
+@property(assign,nonatomic)int rightStepCount;
+
+@end
+
+NS_ASSUME_NONNULL_END

+ 12 - 0
SDK/Entity /ShoesInfo.m

@@ -0,0 +1,12 @@
+//
+//  ShoesInfo.m
+//  Unity-iPhone
+//
+//  Created by duowan123 on 2022/4/28.
+//
+
+#import "ShoesInfo.h"
+
+@implementation ShoesInfo
+
+@end

+ 4 - 23
SDK/Entity /UserFriendsModel.h

@@ -10,9 +10,11 @@
 
 @interface UserFriendsModel : NSObject
 
-@property (nonatomic, assign) int code;    //为0
+@property (nonatomic, assign) NSInteger numberId;//自定义排序
 
-@property (nonatomic, assign) int trans_id;    //业务id,避免关键字转换成非关键字
+@property (nonatomic, assign) int code;//为0
+
+@property (nonatomic, assign) int trans_id;//业务id,避免关键字转换成非关键字
 @property (nonatomic, assign) NSString * nickname;
 @property (nonatomic, assign) NSString * avatar;
 @property (nonatomic, assign) int  gender;
@@ -25,25 +27,6 @@
 
 @interface RankModel : NSObject
 
-//               "id":70,
-//               "rank_id":5,
-//               "game_id":3,
-//               "user_id":144,
-//               "score":8924,
-//               "duration":349,
-//               "consume":0,
-//               "finish_at":"2021-09-06 09:54:09",
-//               "rate_begin":"2021-09-01",
-//               "rate_end":"2021-09-30",
-//               "user_name":"用户不存在",
-//               "user_avatar":"http://static.ouj.com/shoes/test/avatar/avatar_144_791469ce78a423b24a65e06921a1777a.jpg",
-//               "user_level":3,
-//               "user_gender":1,
-//               "user_age":null,
-//               "achievements":Array[13],
-//               "achievements_show":Array[4],
-//               "position":1
-
 @property (nonatomic, assign) int trans_id;
 @property (nonatomic, assign) int rank_id;
 @property (nonatomic, assign) int game_id;
@@ -68,6 +51,4 @@
 
 @property (nonatomic, assign) int  position;
 
-
-
 @end

BIN
SDK/HTTP/.DS_Store


+ 22 - 18
SDK/HTTP/HTTPDataProcession.h

@@ -15,29 +15,27 @@
 #define CFBundleVersion [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]
 #define OS @"2"
 
-//#define BASE_URL @"http://shoes-api.hiyd.com"//正式环境
-#define BASE_URL @"http://test-shoes-api.hiyd.com"//测试环境
-//#define GAME_INVITE [NSString stringWithFormat:@"%@%@",BASE_URL,@"/game/invite"]
-//#define GAME_RECORD [NSString stringWithFormat:@"%@%@",BASE_URL,@"/gameRecord/addGame"]
-//#define GAME_FRIENDS [NSString stringWithFormat:@"%@%@",BASE_URL,@"/forum/friends"]
-//#define GAME_RANK [NSString stringWithFormat:@"%@%@",BASE_URL,@"/rank/game"]
-//#define GAME_START [NSString stringWithFormat:@"%@%@",BASE_URL,@"/game/start"]
-//#define GAME_END [NSString stringWithFormat:@"%@%@",BASE_URL,@"/game/end"]
-
-#define GAME_INVITE [NSString stringWithFormat:@"%@%@?v=%@&os=%@",BASE_URL,@"/game/invite",CFBundleVersion,OS]
-#define GAME_RECORD [NSString stringWithFormat:@"%@%@?v=%@&os=%@",BASE_URL,@"/gameRecord/addGame",CFBundleVersion,OS]
-#define GAME_FRIENDS [NSString stringWithFormat:@"%@%@?v=%@&os=%@",BASE_URL,@"/forum/friends",CFBundleVersion,OS]
-#define GAME_RANK [NSString stringWithFormat:@"%@%@?v=%@&os=%@",BASE_URL,@"/rank/game",CFBundleVersion,OS]
-#define GAME_START [NSString stringWithFormat:@"%@%@?v=%@&os=%@",BASE_URL,@"/game/start",CFBundleVersion,OS]
-#define GAME_END [NSString stringWithFormat:@"%@%@?v=%@&os=%@",BASE_URL,@"/game/end",CFBundleVersion,OS]
+////api
+//#ifdef DEBUG
+//#define BASE_URL @"https://test-shoes-api.funfet.com"//测试环境
+//#else
+//#define BASE_URL @"https://shoes-api.funfet.com"//正式环境
+//#endif
+
+#define GAME_INVITE [NSString stringWithFormat:@"%@%@?v=%@&os=%@",[HTTPDataProcession getBaseUrl],@"/game/invite",CFBundleVersion,OS]
+#define GAME_RECORD [NSString stringWithFormat:@"%@%@?v=%@&os=%@",[HTTPDataProcession getBaseUrl],@"/gameRecord/addGame",CFBundleVersion,OS]
+#define GAME_FRIENDS [NSString stringWithFormat:@"%@%@?v=%@&os=%@",[HTTPDataProcession getBaseUrl],@"/forum/friends",CFBundleVersion,OS]
+#define GAME_RANK [NSString stringWithFormat:@"%@%@?v=%@&os=%@",[HTTPDataProcession getBaseUrl],@"/rank/game",CFBundleVersion,OS]
+#define GAME_START [NSString stringWithFormat:@"%@%@?v=%@&os=%@",[HTTPDataProcession getBaseUrl],@"/game/start",CFBundleVersion,OS]
+#define GAME_END [NSString stringWithFormat:@"%@%@?v=%@&os=%@",[HTTPDataProcession getBaseUrl],@"/game/end",CFBundleVersion,OS]
 
 typedef void(^SuccessBlock)(id data);
 typedef void(^FailBlock)(id errorDes);
 
-typedef void(^UserFriendsDataBlock)(int code,const char * jsonString);//获取好友列表
+typedef void(^UserFriendsDataBlock)(int code,const char * jsonString,NSMutableArray * dataArr);//获取好友列表
 typedef void(^RankDataBlock)(const char * jsonString);//游戏榜单
 typedef void(^InviteDataBlock)(NSString * jsonString);//邀请好友
-typedef void(^GameEndDataBlock)(NSString * jsonString);//游戏结束
+typedef void(^GameEndDataBlock)(const char * jsonString);//游戏结束
 
 @interface HTTPDataProcession : NSObject
 
@@ -45,12 +43,16 @@ typedef void(^GameEndDataBlock)(NSString * jsonString);//游戏结束
 
 + (void)postHTTPDataProcession:(NSString *)urlString  withParams:(NSDictionary *)params token:(NSString*)token success:(SuccessBlock)successBlock fail:(FailBlock)failBlock;
 
+//获取服务器baseurl
++(NSString*)getBaseUrl;
+
 /**
 发起邀请好友
 @param friendid 被邀请人用户id
 @param info 附带的信息
 */
-+ (void)inviteFriends:(int)friendid info:(char*)info inviteDataBlock:(InviteDataBlock)inviteDataBlock;
++ (void)inviteFriends:(int)friendid inviteInfo:(NSString*)inviteInfo inviteDataBlock:(InviteDataBlock)inviteDataBlock;
+
 
 /**
 获取好友榜单数据
@@ -58,12 +60,14 @@ typedef void(^GameEndDataBlock)(NSString * jsonString);//游戏结束
 */
 + (void)GetRank:(int)type rankDataBlock:(RankDataBlock)rankDataBlock;
 
+
 /**
  获取好友列表
  @param type if (type == 0) "world" else "friend"
 */
 +(void)getFriendsList:(UserFriendsDataBlock)userFriendsDataBlock;
 
+
 /**
   上传游戏数据
  @param level 等级

+ 105 - 99
SDK/HTTP/HTTPDataProcession.m

@@ -14,7 +14,6 @@
 @implementation HTTPDataProcession
 
 #pragma mark - 网络请求数据
-/// 向网络请求数据
 + (void)getHTTPDataProcession:(NSString*)urlString token:(NSString*)token success:(SuccessBlock)successBlock fail:(FailBlock)failBlock{
     
     // 1.创建url
@@ -67,7 +66,6 @@
     
 }
 
-/// 向网络请求数据
 + (void)postHTTPDataProcession:(NSString *)urlString  withParams:(NSDictionary *)params token:(NSString*)token success:(SuccessBlock)successBlock fail:(FailBlock)failBlock{
     
       NSURL *url = [NSURL URLWithString:urlString];
@@ -114,7 +112,7 @@
         
 }
 
-//
+//字典转json字符串
 +(NSString*)getKeyValueStringWithDictionary:(NSDictionary*)dic{
     
     if (!dic||dic.count==0){
@@ -134,7 +132,7 @@
             result = [result stringByAppendingString:temp];
         }
     }
-    NSLog(@"result = %@",result);
+    NSLog(@"json = %@",result);
 
     return result;
     
@@ -143,12 +141,10 @@
 
 #pragma mark --------- request
 +(void)getFriendsList:(UserFriendsDataBlock)userFriendsDataBlock{
-
-    NSLog(@"gameFriends token ===>> %@ ",IOSSDK_TOKEN);
     
     NSString *urlString =  [NSString stringWithFormat:@"%@&limit=%@&v=%@&os=%@",GAME_FRIENDS,@"1000",CFBundleVersion,OS];
-
-    [HTTPDataProcession getHTTPDataProcession:urlString token:IOSSDK_TOKEN  success:^(id data){
+    NSLog(@"urlString = %@",urlString);
+    [HTTPDataProcession getHTTPDataProcession:urlString token:[CacheTool getToken]  success:^(id data){
             // 网络访问成功
 //            NSLog(@"data=%@",[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
             NSError * error;
@@ -156,7 +152,7 @@
         
 //                NSLog(@"gameFriends dictionary === %@ ",dictionary);
 
-            if (!error){
+            if (!error && dictionary!=nil &&![dictionary isKindOfClass:[NSNull class]]){
                 
                 int code = [dictionary[@"code"] intValue];
 
@@ -164,44 +160,47 @@
                     
                     NSDictionary * dict = dictionary[@"data"];
                     NSArray * arr = dict[@"list"];
+                    if (arr == nil || [arr isKindOfClass:[NSNull class]]) {
+                        return;
+                    }
                     
-                    NSMutableArray * userArr = [NSMutableArray new];//存储数据
+                    NSMutableArray * jsonArr = [NSMutableArray new];//存储数据
 
                     for (NSDictionary * object in arr){
                         
-                    NSDictionary * socialInfo = object[@"socialInfo"];
-    //                    NSDictionary * dataDict = data[@"data"];
-    //                    NSString * token = dataDict[@"token"];
-    //                    NSLog(@"获取token值成功");
-                    UserFriendsModel * model = [UserFriendsModel new];
-                    model.code = 0;
-                    [model setValuesForKeysWithDictionary:socialInfo];
-                    
-//                NSLog(@"model =========== >>> %d %@ %@ %d %@ %@",model.trans_id,model.nickname,model.city,model.gender,model.status,model.avatar);
-                    
-                    NSMutableDictionary * gameFriends = [NSMutableDictionary new];
-                    [gameFriends setValue:model.status forKey:@"status"];
-                    NSMutableDictionary * userInfo = [NSMutableDictionary new];
-                    [userInfo setObject:[NSNumber numberWithInt:model.trans_id] forKey:@"id"];
-                    [userInfo setValue:model.nickname forKey:@"nickname"];
-                    [userInfo setObject:[NSNumber numberWithInt:model.gender] forKey:@"gender"];
-                    [userInfo setValue:model.city forKey:@"city"];
-                    [userInfo setValue:model.avatar forKey:@"avatar"];
-                    [gameFriends setValue:userInfo forKey:@"user"];
-                    
-//                        NSLog(@"gameFriends =========== >>>%@",gameFriends);
-                    [userArr addObject:gameFriends];
+                        NSDictionary * socialInfo = object[@"socialInfo"];
+                        UserFriendsModel * model = [UserFriendsModel new];
+                        model.code = 0;
+                        [model setValuesForKeysWithDictionary:socialInfo];
+                        
+    //                NSLog(@"model =========== >>> %d %@ %@ %d %@ %@",model.trans_id,model.nickname,model.city,model.gender,model.status,model.avatar);
+                        
+                        NSMutableDictionary * gameFriends = [NSMutableDictionary new];
+                        
+                        NSMutableDictionary * userInfo = [NSMutableDictionary new];
+                        [userInfo setObject:[NSNumber numberWithInt:model.trans_id] forKey:@"id"];
+                        [userInfo setValue:model.nickname forKey:@"nickname"];
+                        [userInfo setObject:[NSNumber numberWithInt:model.gender] forKey:@"gender"];
+                        [userInfo setValue:model.city forKey:@"city"];
+                        [userInfo setValue:model.avatar forKey:@"avatar"];
+                        
+                        [gameFriends setValue:model.status forKey:@"status"];
+                        [gameFriends setValue:userInfo forKey:@"user"];
+                        [jsonArr addObject:gameFriends];
+                        //                        NSLog(@"gameFriends =========== >>>%@",gameFriends);
+
                     }
                     
-                    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:userArr options:NSJSONWritingPrettyPrinted error:nil];
+                    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonArr options:NSJSONWritingPrettyPrinted error:nil];
                     
                     NSString * jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
                     
-                    NSLog(@"GetUserFriends ==>> unity 请求好友列表  %@ ",jsonString);
+//                    NSLog(@"GetUserFriends ==>> unity 请求好友列表  %@ ",jsonString);
                     
                     const char * cusChar =[jsonString UTF8String];
                     
-                    userFriendsDataBlock(code,cusChar);
+                    userFriendsDataBlock(code,cusChar,jsonArr);
+                    
                  }
                 
               }
@@ -212,27 +211,20 @@
     
 }
 
-
-+ (void)inviteFriends:(int)friendid info:(char*)info inviteDataBlock:(InviteDataBlock)inviteDataBlock{
+//邀请好友
++ (void)inviteFriends:(int)friendid inviteInfo:(NSString*)inviteInfo inviteDataBlock:(InviteDataBlock)inviteDataBlock{
     
-    NSDictionary * jsonDict = [IOS_NSUSERDEFAULT objectForKey:IOSSDK_USERINFO];
-
-    NSString * token = [jsonDict objectForKey:@"token"];
     NSString * invite_user_id = [NSString stringWithFormat:@"%d",friendid];
-    NSString * invite = [NSString stringWithFormat:@"%s",info];
-    NSString * game_id = jsonDict[@"game_id"];
-    NSLog(@"InviteFriend ===>> token:%@  friendid:%d  info:%s",token,friendid,info);
-    
-    NSString *urlString = [NSString stringWithFormat:@"%@&invite_user_id=%@&invite=%@&game_id=%@",GAME_INVITE,invite_user_id,invite,game_id];
+    NSString *urlString = [NSString stringWithFormat:@"%@&invite_user_id=%@&invite=%@&game_id=%@",GAME_INVITE,invite_user_id,inviteInfo,[CacheTool getGameId]];
     NSLog(@"InviteFriend urlString ===>> %@",urlString);
 
-    [HTTPDataProcession getHTTPDataProcession:urlString token:token  success:^(id data){
+    [HTTPDataProcession getHTTPDataProcession:urlString token:[CacheTool getToken]  success:^(id data){
         
             NSError * error;
             NSDictionary *dictionary =[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error];
 //                NSLog(@"gameFriends dictionary === %@ ",dictionary);
 
-            if (!error){
+        if (!error && dictionary!=nil &&![dictionary isKindOfClass:[NSNull class]]){
                 
                 int code = [dictionary[@"code"] intValue];
 
@@ -250,6 +242,7 @@
     
 }
 
+//获取排行榜
 + (void)GetRank:(int)type rankDataBlock:(RankDataBlock)rankDataBlock{
 
     NSString * scoreType;
@@ -259,18 +252,18 @@
         scoreType = @"friend";
     }
     
-    NSString *urlString = [NSString stringWithFormat:@"%@&game_id=%@&scope=%@",GAME_RANK,IOSSDK_GAMEID,scoreType];
+    NSString *urlString = [NSString stringWithFormat:@"%@&game_id=%@&scope=%@",GAME_RANK,[CacheTool getGameId],scoreType];
 
     NSLog(@"urlString == %@",urlString);
     
-    [HTTPDataProcession getHTTPDataProcession:urlString token:IOSSDK_TOKEN  success:^(id data){
+    [HTTPDataProcession getHTTPDataProcession:urlString token:[CacheTool getToken]  success:^(id data){
 
             NSError * error;
             NSDictionary *dictionary =[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error];
         
 //            NSLog(@"GetRank dictionary === %@ ",dictionary);
         
-            if (!error){
+        if (!error && dictionary!=nil &&![dictionary isKindOfClass:[NSNull class]]){
 
                 int code = [dictionary[@"code"] intValue];
 
@@ -286,7 +279,9 @@
                             
                             NSDictionary * dict = dictionary[@"data"];
                             NSArray * arr = dict[@"records"];
-                            
+                            if (arr == nil || [arr isKindOfClass:[NSNull class]]) {
+                                return;
+                            }
                             NSMutableArray * userArr = [NSMutableArray new];//存储数据
                             
                             NSMutableDictionary * list = [NSMutableDictionary new];
@@ -349,18 +344,17 @@
 
 /**
  开始游戏
- @param level 等级
 */
 +(void)gameStart{
 
-    NSString *urlString = [NSString stringWithFormat:@"%@&id=%@",GAME_START,IOSSDK_GAMEID];
-    [HTTPDataProcession getHTTPDataProcession:urlString token:IOSSDK_TOKEN  success:^(id data){
+    NSString *urlString = [NSString stringWithFormat:@"%@&id=%@",GAME_START,[CacheTool getGameId]];
+    [HTTPDataProcession getHTTPDataProcession:urlString token:[CacheTool getToken]  success:^(id data){
         
             NSError * error;
             NSDictionary *dictionary =[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error];
 //                NSLog(@"gameFriends dictionary === %@ ",dictionary);
 
-            if (!error){
+        if (!error && dictionary!=nil && ![dictionary isKindOfClass:[NSNull class]]){
                 
                 int code = [dictionary[@"code"] intValue];
 
@@ -383,18 +377,17 @@
 
 /**
  结束游戏
- @param level 等级
 */
 +(void)gameEnd{
     
-    NSString *urlString = [NSString stringWithFormat:@"%@&id=%@",GAME_END,IOSSDK_GAMEID];
-    [HTTPDataProcession getHTTPDataProcession:urlString token:IOSSDK_TOKEN  success:^(id data){
+    NSString *urlString = [NSString stringWithFormat:@"%@&id=%@",GAME_END,[CacheTool getGameId]];
+    [HTTPDataProcession getHTTPDataProcession:urlString token:[CacheTool getToken]  success:^(id data){
         
             NSError * error;
             NSDictionary *dictionary =[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&error];
 //                NSLog(@"gameFriends dictionary === %@ ",dictionary);
 
-            if (!error){
+        if (!error && dictionary!=nil &&![dictionary isKindOfClass:[NSNull class]]){
                 
                 int code = [dictionary[@"code"] intValue];
 
@@ -414,6 +407,9 @@
     
 }
 
+/**
+ 上传运动数据
+*/
 +(void)postGameRecord:(int)level
                 score:(double)score
                record:(int)record
@@ -421,69 +417,79 @@
            opponentId:(int)opponentId
      gameEndDataBlock:(GameEndDataBlock)gameEndDataBlock{
     
-    NSMutableDictionary * sportRecord = [NSMutableDictionary new];
+    NSMutableDictionary * gameRecord = [NSMutableDictionary new];
     //缓存的token、game_id
-    NSString * token = IOSSDK_TOKEN;
-    NSString * game_id = IOSSDK_GAMEID;
-    [sportRecord setObject:game_id forKey:@"game_id"];//游戏类型
+    NSString * game_id = [CacheTool getGameId];
+    [gameRecord setObject:game_id forKey:@"game_id"];//游戏类型
     //预留字段:默认
-    [sportRecord setObject:@0 forKey:@"consume"];//卡路里默认0
-    [sportRecord setObject:@0 forKey:@"screen"];//默认0
-    [sportRecord setObject:@0 forKey:@"distance"];//废弃
-    [sportRecord setObject:@0 forKey:@"is_cancel"];//是否正常停止游戏 正常0 不正常1
+    [gameRecord setObject:@0 forKey:@"distance"];//废弃
+    [gameRecord setObject:@0 forKey:@"is_cancel"];//是否正常停止游戏 正常0 不正常1
     //unity回调数据
-    [sportRecord setObject:[NSNumber numberWithInt:level] forKey:@"level"];
-    [sportRecord setObject:[NSNumber numberWithDouble:score] forKey:@"score"];
-    [sportRecord setObject:[NSNumber numberWithInt:record] forKey:@"record"];
-    [sportRecord setObject:[NSNumber numberWithInt:mode] forKey:@"mode"];
-    [sportRecord setObject:[NSNumber numberWithInt:opponentId] forKey:@"opponentId"];
+    [gameRecord setObject:[NSNumber numberWithDouble:score] forKey:@"score"];
+    [gameRecord setObject:[NSNumber numberWithInt:mode] forKey:@"mode"];
    
-   //新增加时间戳字段
-    if ( [IOS_NSUSERDEFAULT objectForKey:IOSSDK_TIMESTAMP]!=nil){
-        NSString * timestamp =  [IOS_NSUSERDEFAULT objectForKey:IOSSDK_TIMESTAMP];
-        [sportRecord setObject:timestamp forKey:@"play_group"];
-    }else{
-        [sportRecord setObject:[AlgorithmTool returnTimestamp] forKey:@"play_group"];
-    }
-  
     //缓存的动作数据和持续时间
-    NSDictionary * acheDict = [IOS_NSUSERDEFAULT objectForKey:IOSSDK_BLESDKDATA];
-    if (acheDict!=nil){
-        [sportRecord addEntriesFromDictionary:acheDict];
-    }else{
-        [sportRecord setObject:@0 forKey:@"jump"];
-        [sportRecord setObject:@0 forKey:@"crouch"];
-        [sportRecord setObject:@0 forKey:@"step"];
-        [sportRecord setObject:@0 forKey:@"duration"];
+    NSDictionary * movements = [IOS_NSUSERDEFAULT objectForKey:IOSSDK_MOTIONCOUNT];
+    if (movements!=nil){
+        NSDictionary * sub = movements[@"movements"];
+       NSData * jsonData = [NSJSONSerialization dataWithJSONObject:sub options:NSJSONWritingPrettyPrinted error:nil];
+       NSString * jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
+        [gameRecord setObject:jsonString forKey:@"movements"];
+        [gameRecord setObject:movements[@"duration"] forKey:@"duration"];
+        [gameRecord setObject:movements[@"play_group"] forKey:@"play_group"];
     }
     
-    NSLog(@"%@",sportRecord);
+//    NSLog(@"gameRecord = %@",gameRecord);
 
-    [HTTPDataProcession postHTTPDataProcession:GAME_RECORD withParams:sportRecord  token:token success:^(id data){
-           
-        NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
+    [HTTPDataProcession postHTTPDataProcession:GAME_RECORD withParams:gameRecord  token:[CacheTool getToken] success:^(id data){
+        NSError * error;
+        NSDictionary *dictionary = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:&error];
 
-        if (dic!=nil){
+        if (!error && dictionary!=nil &&![dictionary isKindOfClass:[NSNull class]]){
 
-            int code = [dic[@"code"] intValue];
+            int code = [dictionary[@"code"] intValue];
 
             if (code==0){
                 
-                NSLog(@"GameEnd 上传成功 %@",dic);
-                gameEndDataBlock(@"上传成功");
+                NSDictionary * data = dictionary[@"data"];
+                if (data!=nil) {
+                    NSDictionary * record = data[@"record"];
+                    if (record!=nil) {
+                        NSData *jsonData = [NSJSONSerialization dataWithJSONObject:record options:NSJSONWritingPrettyPrinted error:nil];
+                        NSString * jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
+                        const char * cusChar =[jsonString UTF8String];
+                        gameEndDataBlock(cusChar);
+                        NSLog(@"gameRecord 上传成功 %@",record);
+                    }
+                }
+
                 
-        }else{
-                NSLog(@"请求错误 =========== >>> %@",dic[@"msg"]);
+            }else{
+                NSLog(@"gameRecord 请求错误 =========== >>> %@",dictionary[@"msg"]);
              }
             
         }
         
     }fail:^(id errorDes){
         
-        NSLog(@"请求失败 =========== >>> %@",errorDes);
+        NSLog(@"gameRecord 请求失败 =========== >>> %@",errorDes);
 
     }];
     
+    
+}
+
+//
++(NSString*)getBaseUrl{
+    NSString * baseUrl;
+    int isdebug = [[CacheTool getGameDebug] intValue];
+    if (isdebug == 1){//测试环境
+        baseUrl = @"https://test-shoes-api.funfet.com";
+    }else{
+        baseUrl = @"https://shoes-api.funfet.com";
+    }
+    return baseUrl;
 }
 
+
 @end

+ 72 - 47
SDK/IOSPlatformSDK.h → SDK/IOSPlatformSDK/IOSPlatformSDK.h

@@ -7,14 +7,13 @@
 //
 #import <Foundation/Foundation.h>
 #import <UIKit/UIKit.h>
-#import "MYFactoryManager.h"
 
 @interface IOSPlatformSDK : NSObject
 
 //****************** public Method ******************//
 +(instancetype)sharedInstance;
 -(void)startWithUrl:(NSURL*)url;
-@property(strong,nonatomic)NSString * openStyle;//测试数据 监听app的打开方式
+
 //****************** ios call unity  start ******************//
 /**
  * cusid:主/副设备
@@ -60,16 +59,69 @@
 */
 -(void)bridgingInteraction:(int)cusid
                       code:(int)code;
+
+/**
+*趣动通知好友邀请事件
+ * code:
+ * userChar:
+ * infoChar:
+*/
+-(void)bridgingInvite:(int)code
+                  userChar:(const char *)userChar
+                  infoChar:(const char *)infoChar;
+
 @end
 
 //****************** unity call  ios  start ******************//
 /**
+ * unity获取用户信息 -->> 解析从Spotr App的传过来的RL_Seme  ios返回json数据给游戏
+ */
+extern "C" {
+extern char *  GetUserInfoJson();
+}
+/**
+ * unity获取用户好友 -->> ios端根据用户token值请求http好友列表 ios将列表json的数组数据传给unity
+ */
+extern "C" {
+extern void GetUserFriends();
+}
+/**
+* Unity call ios 获取游戏榜单数据
+ *if (type == 0) "world" else "friend"
+ *ios 请求完数据后用 PointerGetRankHandler 回调数据给unity
+*/
+extern "C" {
+void GetRank(int type);
+}
+/**
+ * 主动邀请好友
+ * friendid: 游戏好友ID
+ */
+extern "C" {
+extern void InviteFriend(int friendid,char * info);
+}
+/**
+ * unity界面准备好后可以申请邀请信息,回调在inviteFriendHandler
+ * friendid: 游戏好友ID
+ */
+extern "C" {
+extern void GetInviteInfo();
+}
+/**
+* Unity call ios 弹出邀请好友弹窗
+ * 旧版游戏暂未用到
+*/
+extern "C" {
+void ShowInviteFriend(int code, char * info);
+}
+
+
+/**
  * 游戏开始
  */
 extern "C" {
 extern void GameStart();
 }
-
 /**
  * 游戏结束
  * level: level
@@ -81,7 +133,6 @@ extern void GameStart();
 extern "C" {
 extern void GameEnd(int level, double score, int record, int mode, int opponentId);
 }
-
 /**
  * 搜索设备
  * type: 设备ID
@@ -89,7 +140,6 @@ extern void GameEnd(int level, double score, int record, int mode, int opponentI
 extern "C" {
 extern void SearchDevice(int type);
 }
-
 /**
  * 链接设备
  * type: 设备ID
@@ -97,53 +147,38 @@ extern void SearchDevice(int type);
 extern "C" {
 extern void ConnectDevice(int type);
 }
-
 /**
- * 震动
+ * 链接设备
  * type: 设备ID
- * duration: 时长 ms [100 .. 1000]
  */
 extern "C" {
-extern void  Vibrate(int type,int duration);
-}
-
-/**
- * unity获取用户好友 -->> ios端根据用户token值请求http好友列表 ios将列表json的数组数据传给unity
- */
-extern "C" {
-extern void GetUserFriends();
+extern void DisConnectDevice(int type);
 }
-
 /**
- * unity获取用户信息 -->> 解析从Spotr App的传过来的RL_Seme  ios返回json数据给游戏
+ * 震动
+ * type: 设备ID
+ * duration: 时长 ms [100 .. 1000]
+ leftOrRight:针对三轮车
  */
 extern "C" {
-extern char *  GetUserInfoJson();
+extern void  Vibrate(int type,int duration);
 }
-
 /**
- * unity可以主动断开链接
- * type: 设备类型 0: 主, 1: 副
+ * 震动
+ * type:设备ID
+ * duration: 时长 ms [100 .. 1000]
+ * leftOrRight: 左右鞋 针对三轮车
  */
 extern "C" {
-extern void DisConnectDevice(int type);
+void  VibrateS(int type,int duration,int leftOrRight);
 }
-
 /**
- * 主动邀请好友
- * friendid: 游戏好友ID
- */
+* Unity call ios 获取鞋子角度
+*/
 extern "C" {
-extern void InviteFriend(int friendid,char * info);
+int NativeGetAttX(int cusId);
 }
 
-/**
- * unity界面准备好后可以申请邀请信息,回调在inviteFriendHandler
- * friendid: 游戏好友ID
- */
-extern "C" {
-extern void GetInviteInfo();
-}
 
 /**
  * 投屏
@@ -153,18 +188,8 @@ extern void ScreenProjection();
 }
 
 /**
-* Unity call ios 弹出邀请好友弹窗
- * 旧版游戏暂未用到
-*/
-extern "C" {
-void ShowInviteFriend(int code, char * info);
-}
-
-/**
-* Unity call ios 获取游戏榜单数据
- *if (type == 0) "world" else "friend"
- *ios 请求完数据后用 PointerGetRankHandler 回调数据给unity
+* Unity call ios 返回app
 */
 extern "C" {
-void GetRank(int type);
+void OnBackPressed();
 }

+ 218 - 295
SDK/IOSPlatformSDK.mm → SDK/IOSPlatformSDK/IOSPlatformSDK.mm

@@ -1,14 +1,16 @@
 //
 //  IOSPlatformSDK.m
 //  OYGameSKD
-//
 //  Created by leon on 2021/1/21.
 //  Copyright © 2021 Oujia. All rights reserved.
 
-
 #import "IOSPlatformSDK.h"
+#import "BugTool.h"
+#include <sys/signal.h>
+#import "MYFactoryManager.h"
 
-#pragma mark ============================>> ios call unity C语言指针声明 start
+#pragma mark ============================>> ios call unity (定义名字参数和C#类一样的方法)
+//大概流程就是先将C#的函数指针存入OC内存,在OC需要回调unity的时候就可以使用不同的指针来回调不同的unity方法
 /**
 *运动数据
 * left: 左鞋动作代码
@@ -61,19 +63,30 @@ typedef void (* ActionHandler) (int cusid, int code);
 */
 typedef void (* GetRankHandler)(int conde,const char * userJson);
 
-ActionHandler actionHandler;
-MotionHandler motionHandler;
-StepHandler stepHandler;
-DeviceHandler deviceHandler;
-UserFriendsHandler userFriendsHandler;
-InviteFriendHandler inviteFriendHandler;
-GetRankHandler getRankHandler;
 
-//
-#pragma mark ============================>> ios call unity C语言指针声明 结束
+/** array: x,y,z姿态数据
+* 单位:弧度
+* 使用时要将数据 除以 10000
+* 转换角度可以使用 Mathf.Rad2Deg
+*/
+typedef void (* RotateHandler)(int cusid, short lx, short ly, short lz, short rx, short ry, short rz);
 
-@interface IOSPlatformSDK ()
-@end
+
+/**addGame post 游戏结束后回调给游戏的数据
+* json字符串
+*/
+typedef void (* GameEndResponseHandler)(int code, const char * userJson);
+
+#pragma mark ============================>> 声明 静态指针变量的实例 在unity call ios时候将该指针存储在内存中,在需要ios call unity时,用该指针调用unity的函数接口
+static ActionHandler actionHandler;
+static MotionHandler motionHandler;
+static StepHandler stepHandler;
+static DeviceHandler deviceHandler;
+static UserFriendsHandler userFriendsHandler;
+static InviteFriendHandler inviteFriendHandler;
+static GetRankHandler getRankHandler;
+static RotateHandler rotateHandler;
+static GameEndResponseHandler gameEndResponseHandler;
 
 @implementation IOSPlatformSDK
 
@@ -95,190 +108,37 @@ static IOSPlatformSDK * instance;
     static dispatch_once_t onceToken;
     dispatch_once(&onceToken, ^{
         instance = [super init];
-        [self initData];
+        //初始蓝牙链接
+        [BTDataProcess sharedInstance];
+        //开始bug监控
+        [BugTool startAvoidBug];
     });
     return instance;
 }
 
-#pragma mark ============================>> public method app跳转直链
--(void)startWithUrl:(NSURL*)url{//
-    
-    if (url==nil){
-        return;
-    }
-    NSString * urlString = [url absoluteString];
-    NSArray * stringArr = [urlString componentsSeparatedByString:@"//"];
-    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];
-  
-    if (urlDict!=nil){
-        //主副设备:deviceType  游戏种类:game_type  mac地址:macAddress
-        BTDataInstance.deviceType = DEVICETYPE_MAIN;
-        NSString * game_type = urlDict[@"game_type"];
-        BTDataInstance.game_type = (GAME_TYPE)[game_type intValue];
-        if ([urlDict objectForKey:@"mac"]!=nil){
-            BTDataInstance.macAddress = [urlDict objectForKey:@"mac"];
-        }
-        //链接蓝牙
-        [BTDataInstance initCBCentralManager];
-     
-    }
-    
-}
-
-#pragma mark ============================>> private 各类通知处理事件
--(void)initData{
-    
-    //固定一个时间戳
-    NSString * timestamp =   [AlgorithmTool returnTimestamp];
-    [IOS_NSUSERDEFAULT setObject:timestamp forKey:IOSSDK_TIMESTAMP];
-    [IOS_NSUSERDEFAULT synchronize];
-    
-    //监听 趣动 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");
-    BTDataInstance.isBackGround = YES;
-}
--(void)willEnterForeground{
-//    NSLog(@"leon UIApplicationWillEnterForegroundNotification");
-    BTDataInstance.isBackGround = NO;
-    NSLog(@"程序从后台返回 重连蓝牙 peripheral.state = %ld",LEManager.peripheral.state);
-    [BTDataInstance initCBCentralManager];
-}
-
-void disConnectBle (CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo){
-    [BTDataInstance disConnedctBle];
-}
-
-void inviteFriends (CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo){
-        
-    //group.com.Oujia.AppAndGame 沙河数据
-    NSUserDefaults* userDefault = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.Oujia.AppAndGame"];
-    //趣动传过来的 invite json字符串转字典
-    NSString * string = [userDefault objectForKey:@"invite"];
-    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);
-        inviteFriendHandler(0,userChar,infoChar);
-    }
-    
-}
-
-//unity call instance弹出蓝牙搜索框
--(void)searchBLEAction:(int)type{
-    
-    /***************************初始化蓝牙数据处理工具***************************/
-    //主副设备:deviceType  游戏种类:game_type  mac地址:macAddress
-    BTDataInstance.deviceType = (DEVICE_TYPE)type;
-    NSDictionary * jsonDict = [IOS_NSUSERDEFAULT objectForKey:IOSSDK_USERINFO];
-    NSString * game_type = jsonDict[@"game_type"];
-    BTDataInstance.game_type = (GAME_TYPE)[game_type intValue];
-    BTDataInstance.macAddress = @"";
-    //初始化蓝牙CBCentralManager
-    [BTDataInstance initCBCentralManager];
-
-    /***************************搜索蓝牙外设弹窗***************************/
-    SearchDeviceViewController  * searchVC = [SearchDeviceViewController  new];
-    [self addTOwindow:searchVC];
-    //searchVC搜索蓝牙Button
-    searchVC.searchDeviceTask = ^{
-        [BTDataInstance initCBCentralManager];
-    };
-    //BTDataProces搜索到的蓝牙外设-->searchVC
-    BTDataInstance.deviceArrBLock = ^(NSMutableArray * arr){//蓝牙数据回调 刷新popView数据
-        searchVC.deviceArray = arr;
-        [searchVC reloadData];
-    };
-    //点击searchVC的tableViewCell链接选中的蓝牙
-    searchVC.connectDeviceBlock = ^(CBPeripheral * peripheral){
-        BTDataInstance.deviceType = (DEVICE_TYPE)type;
-        [BTDataInstance connectPeripheral:peripheral];
-        BTDataInstance.macAddress = peripheral.identifier.UUIDString;
-    };
-    
-    //bleInstance脚步交互动作-->searchVC
-    BTDataInstance.getInteractionBlock = ^(int interaction){
-        if (interaction!=-1){
-            NSLog(@"BTDataProcess 有效交互动作 ===>> %d",interaction);
-//            [searchVC getInteraction:interaction];
-        }else{
-//            NSLog(@"BTDataProcess 无效交互动作 ===>> %@",@"原地");
-        }
-    };
-    
-}
-
-#pragma mark ============================>> private
-//全局弹窗
--(void)addTOwindow:(UIViewController*)searchVC{
-    
-    UIViewController *rootVC = [[UIApplication sharedApplication].delegate window].rootViewController;
-    UIViewController *parent = rootVC;
-    while ((parent = rootVC.presentedViewController) != nil ){
-    rootVC = parent;
-    }
-    while ([rootVC isKindOfClass:[UINavigationController class]]){
-    rootVC = [(UINavigationController *)rootVC topViewController];
-    }
-    [rootVC addChildViewController:searchVC];
-    [rootVC.view addSubview:searchVC.view];
-    
+#pragma mark ============================>> public method app 跳转直链
+-(void)startWithUrl:(NSURL*)url{
+    [BTDataInstance startWithUrl:url];
 }
 
+//
 #pragma mark ============================>> private
 //是否已经缓存到用户信息
 -(BOOL)existUserInfo{
     
     NSDictionary * jsonDict = [IOS_NSUSERDEFAULT objectForKey:IOSSDK_USERINFO];
-     if (jsonDict==nil){
-//         [PopupView showCusHUDA:@"请从趣动App启动"];
+     if ([jsonDict isKindOfClass:[NSNull class]] || jsonDict == nil || [jsonDict isEqual:[NSNull null]]){
+         [PopupView showCusHUDA:@"获取用户信息失败,请从趣动启动"];
          return NO;
      }else{
          return YES;
      }
     
+//    UIDevice
+    
 }
 
-#pragma mark ============================>> ios call unity
+#pragma mark ============================>> ios call unity (数据处理后的回调)
 -(void)bridgingMotionAction:(int)cusid
                        left:(int)left
                       right:(int)right{
@@ -292,7 +152,7 @@ void inviteFriends (CFNotificationCenterRef center, void *observer, CFStringRef
               rightStatus:(int)rightStatus
                  leftFrag:(int)leftFrag
                 rightFrag:(int)rightFrag{
-    if (stepHandler != nil) {
+    if (stepHandler != nil){
         stepHandler(cusid,leftStatus,rightStatus,leftFrag,rightFrag);
     }
 }
@@ -305,7 +165,7 @@ void inviteFriends (CFNotificationCenterRef center, void *observer, CFStringRef
 //        NSLog(@"deviceHandler ===>> %d %@ %@ %d %d",cusid,name,address,status,electricity);
     const char * charName =[name UTF8String];
     const char * charAddress =[address UTF8String];
-    if (deviceHandler != nil) {
+    if (deviceHandler != nil){
         deviceHandler(cusid,charName,charAddress,status,electricity);
     }
     
@@ -314,14 +174,20 @@ void inviteFriends (CFNotificationCenterRef center, void *observer, CFStringRef
 -(void)bridgingInteraction:(int)cusid
                       code:(int)code{
     //传给unity ---> 旧版游戏未用到
-    if (actionHandler != nil) {
-//            actionHandler(cusid,code);
+    if (actionHandler != nil){
+            actionHandler(cusid,code);
     }
 }
 
+-(void)bridgingInvite:(int)code
+             userChar:(const char *)userChar
+             infoChar:(const char *)infoChar{
+        inviteFriendHandler(0,userChar,infoChar);
+}
+
 @end
 
-#pragma mark ============================>> unity call ios
+#pragma mark ============================>> unity call ios (声明unity call ios的托管函数 & 接收unity传过来的指针)
 /**
  * c语言字符串指针malloc
  */
@@ -375,7 +241,6 @@ extern "C" {void PointerActionHandler(ActionHandler  handler){
    }
 }
 
-
 /**
  * unity call ios 主动接收 函数指针
  * UserFriendsHandler 用于ios回调 "当前用户好友列表",在👇🏻GetUserFriends中实现
@@ -406,6 +271,125 @@ extern "C" {void PointerGetRankHandler(GetRankHandler  handler){
    }
 }
 
+extern "C" {void PointerRotateHandler(RotateHandler  handler){
+    rotateHandler = handler;
+    NSLog(@"PutIntPtr RotateHandler 指针内存地址 ===>> %p",&rotateHandler);
+   }
+}
+
+
+extern "C" {void PointerGameEndResponseHandler(GameEndResponseHandler  handler){
+    gameEndResponseHandler = handler;
+    NSLog(@"PutIntPtr GameEndResponseHandler 指针内存地址 ===>> %p",&gameEndResponseHandler);
+   }
+}
+
+
+/**
+* unity获取用户信息 -->> 解析从Spotr App的传过来的RL_Seme  ios返回json数据给游戏
+*/
+ char *  GetUserInfoJson(){
+     
+//     NSLog(@"Unity 请求用户信息 GetUserInfoJson ===>>");
+     if ([instance existUserInfo]==NO){
+         return MakeStringCopy("");
+     }else{
+         const char * cuschart = [[CacheTool getUserInfo] UTF8String];
+//         NSLog(@"IOS_SKD 回调用户信息 GetUserInfoJson ===> %@",[CacheTool getUserInfo]);
+         //要先copy 不然c#调用free的时候回闪退
+         return MakeStringCopy(cuschart);
+     }
+     
+}
+
+/**
+* unity获取用户好友列表 -->> ios端根据用户token值请求http好友列表 ios将列表json的数组数据传给unity
+*/
+void GetUserFriends(){
+//    NSLog(@"Unity 请求好友列表 GetUserFriends ===>>");
+    if ([instance existUserInfo]==NO){
+        return;
+    }
+    [HTTPDataProcession getFriendsList:^(int code, const char *jsonString, NSMutableArray *dataArr){
+        NSLog(@"IOS_SKD 回调好友列表 GetUserFriends ===> %s",jsonString);
+        userFriendsHandler(code,jsonString);//异步回调
+    }];
+}
+
+/**
+* Unity call ios 获取游戏榜单数据
+ *if (type == 0) "world" else "friend"
+ *ios 请求完数据后用 PointerGetRankHandler 回调数据给unity
+*/
+void GetRank(int type){
+//    NSLog(@"Unity 获取榜单列表数据 GetRank ===>> %d",type);
+    if ([instance existUserInfo]==NO){
+        return;
+    }
+    [HTTPDataProcession GetRank:type rankDataBlock:^(const char *jsonString){
+        NSLog(@"IOS_SKD 回调 榜单列表数据 GetRank ===>> %d %s",type,jsonString);
+        getRankHandler(type,jsonString);
+    }];
+
+}
+
+/**
+* 游戏在准备界面  Unity call ios申请申请邀请信息,ios用inviteFriendHandler指针回调数据给unity
+*/
+void GetInviteInfo(){
+    
+    NSLog(@"Unity获取好友邀请信息 GetInviteInfo ===>>");
+    if ([instance existUserInfo]==NO){
+        return;
+    }
+    //user字典 -> 字符串 -> Char
+    const char * userChar = [[CacheTool getInviteUser] UTF8String];
+    //info字符串 -> Char
+    const char * infoChar =[[CacheTool getInviteInfo] UTF8String];
+    NSLog(@"IOS_SKD 回调好友邀请信息 GetInviteInfo ===>>  %s , %s",userChar,infoChar);
+    if (infoChar!=nil&&strlen(infoChar)>1) {
+            inviteFriendHandler(0,userChar,infoChar);
+    }
+    //
+}
+
+/**
+* Unity call ios 主动邀请好友(跳舞和跑酷游戏)
+* friendid: 游戏好友ID
+* info: 邀请信息
+*/
+void InviteFriend(int friendid,char * info){
+    
+    NSLog(@"Unity 点击邀请好友 InviteFriend ===>> %s",info);
+    
+    if ([instance existUserInfo]==NO){
+        return;
+    }
+    NSString * inviteInof = [NSString stringWithFormat:@"%s",info];
+    [HTTPDataProcession inviteFriends:friendid inviteInfo:inviteInof  inviteDataBlock:^(NSString *jsonString){
+//        NSLog(@"IOS_SKD 回调点击邀请好友事件 InviteFriend ===>>");
+        dispatch_async(dispatch_get_main_queue(), ^{
+        [PopupView showCusHUDA:jsonString];
+        });
+    }];
+    
+}
+
+/**
+* Unity call ios 弹出邀请好友弹窗(三轮车游戏)
+* code: 邀请信息
+* info: 邀请信息
+*/
+void ShowInviteFriend(int code, char * info){
+    NSLog(@"Unity 请求打开好友列表弹窗 ShowInviteFriend ===>> %s",info);
+    if ([instance existUserInfo]==NO){
+        return;
+    }
+    NSString * inviteInof = [NSString stringWithFormat:@"%s",info];
+    [BTDataInstance showInviteFriend:code inviteInof:inviteInof];
+}
+
+
 /**
  * 游戏开始
  */
@@ -420,6 +404,7 @@ void GameStart(){
     [HTTPDataProcession gameStart];
 }
 
+
 /**
 * 游戏结束
 * level: level
@@ -434,16 +419,19 @@ void GameEnd(int level, double score, int record, int mode, int opponentId){
     if ([instance existUserInfo]==NO){
         return;
     }
-    
     [BTDataInstance gameEndInitData];
     //http
     [HTTPDataProcession gameEnd];
     //上传数据
-    [HTTPDataProcession postGameRecord:level score:score record:record mode:mode opponentId:opponentId gameEndDataBlock:^(NSString *jsonString){
-        NSLog(@"IOS_SKD 回调结束游戏请求 GameEnd ===> %@",jsonString);
+    [HTTPDataProcession postGameRecord:level score:score record:record mode:mode opponentId:opponentId gameEndDataBlock:^(const char * jsonString){
+        NSLog(@"IOS_SKD 回调结束游戏请求 GameEnd ===> %s",jsonString);
+        gameEndResponseHandler(0,jsonString);
     }];
+    
 }
 
+
+
 /**
 * 搜索设备
 * type: 设备ID
@@ -451,12 +439,14 @@ void GameEnd(int level, double score, int record, int mode, int opponentId){
 void SearchDevice(int type){
     //unity 有两个search按钮 type 0是主设备 1是副设备
     NSLog(@"Unity 请求搜索设备 type ===>> %d",type);
-//    if ([instance existUserInfo]==NO){
-//        return;
-//    }
-    [instance searchBLEAction:type];
+    if ([instance existUserInfo]==NO){
+        return;
+    }
+    [BTDataInstance searchBLEAction:type];
+    
 }
 
+
 /**
 * 链接设备
 * type: 设备ID
@@ -470,111 +460,55 @@ void ConnectDevice(int type){
 }
 
 /**
-* 震动
-* type: 设备ID
-* duration: 时长 ms [100 .. 1000]
+* unity可以主动断开链接
+* type: 设备类型 0: 主, 1: 副
 */
-void  Vibrate(int type,int duration){
+void DisConnectDevice(int type){
+    NSLog(@"Unity 请求断开蓝牙链接 disConnectDevice ===>> %d",type);
     if ([instance existUserInfo]==NO){
         return;
     }
-    [BTDataInstance vibrationAction:type duration:duration];
+    [BTDataInstance disConnedctBle:type];
 }
 
+
 /**
-* unity获取用户好友列表 -->> ios端根据用户token值请求http好友列表 ios将列表json的数组数据传给unity
+* 震动
+* type: 设备ID
+* duration: 时长 ms [100 .. 1000]
 */
-void GetUserFriends(){
-//    NSLog(@"Unity 请求好友列表 GetUserFriends ===>>");
+void  Vibrate(int type,int duration){
     if ([instance existUserInfo]==NO){
         return;
     }
-    [HTTPDataProcession getFriendsList:^(int code, const char *jsonString){
-        NSLog(@"IOS_SKD 回调好友列表 GetUserFriends ===> %s",jsonString);
-        userFriendsHandler(code,jsonString);//异步回调
-    }];
-}
+    [BTDataInstance vibrationAction:type duration:duration leftOrRight:0];
 
-/**
-* unity获取用户信息 -->> 解析从Spotr App的传过来的RL_Seme  ios返回json数据给游戏
-*/
- char *  GetUserInfoJson(){
-//     NSLog(@"Unity 请求用户信息 GetUserInfoJson ===>>");
-     if ([instance existUserInfo]==NO){
-         return MakeStringCopy("");
-     }else{
-         NSDictionary * jsonDict = [IOS_NSUSERDEFAULT objectForKey:IOSSDK_USERINFO];
-         NSDictionary * user = jsonDict[@"user"];
-         if (user!=nil){
-             NSData *jsonData = [NSJSONSerialization dataWithJSONObject:user options:NSJSONWritingPrettyPrinted error:nil];
-             NSString * userJsonString =  [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
-             const char * cuschart =[userJsonString UTF8String];
-             NSLog(@"IOS_SKD 回调用户信息 GetUserInfoJson ===> %@",userJsonString);
-             //要先copy 不然c#调用free的时候回闪退
-             return MakeStringCopy(cuschart);
-         }else{
-             return MakeStringCopy("");
-         }
-         
-     }
-     
 }
 
 /**
-* unity可以主动断开链接
-* type: 设备类型 0: 主, 1: 副
+* 震动
+* type: 设备ID
+* duration: 时长 ms [100 .. 1000]
 */
-void DisConnectDevice(int type){
-    NSLog(@"Unity 请求断开蓝牙链接 disConnectDevice ===>>");
+void  VibrateS(int type,int duration,int leftOrRight){
     if ([instance existUserInfo]==NO){
         return;
     }
+    NSLog(@"Unity 请求震动 VibrateS ===>> %d",leftOrRight);
+    [BTDataInstance vibrationAction:type duration:duration leftOrRight:leftOrRight];
 }
 
 /**
-* 主动邀请好友
-* friendid: 游戏好友ID
+ * Unity call ios 获取鞋子角度
 */
-void InviteFriend(int friendid,char * info){
-    NSLog(@"Unity 点击邀请好友 InviteFriend ===>>");
-    if ([instance existUserInfo]==NO){
-        return;
+int NativeGetAttX(int cusId){
+    if (cusId==0) {
+        return BTDataInstance.main_nativeAttX;
+    }else{
+        return BTDataInstance.vice_nativeAttX;
     }
-    [HTTPDataProcession inviteFriends:friendid info:info inviteDataBlock:^(NSString *jsonString){
-//        NSLog(@"IOS_SKD 回调点击邀请好友事件 InviteFriend ===>>");
-        dispatch_async(dispatch_get_main_queue(), ^{
-        [PopupView showCusHUDA:jsonString];
-        });
-        
-    }];
 }
 
-/**
-* unity界面准备好后可以申请邀请信息,回调在inviteFriendHandler
-* friendid: 游戏好友ID
-*/
-void GetInviteInfo(){
-    
-    NSLog(@"Unity获取好友邀请信息 GetInviteInfo ===>>");
-    if ([instance existUserInfo]==NO){
-        return;
-    }
-    NSDictionary * jsonDict = [IOS_NSUSERDEFAULT objectForKey:IOSSDK_USERINFO];
-    NSDictionary * invite = jsonDict[@"invite"];
-    if (invite!=nil){
-        //user字典 -> 字符串 -> Char
-        NSDictionary * user =  [invite objectForKey:@"user"];
-        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 * info = invite[@"info"];
-        const char * infoChar =[info UTF8String];
-        NSLog(@"IOS_SKD 回调好友邀请信息 GetInviteInfo ===>>  %s , %s",userChar,infoChar);
-        inviteFriendHandler(0,userChar,infoChar);
-    }
-    
-}
 
 /**
 * 投屏
@@ -587,29 +521,18 @@ void ScreenProjection(){
 }
 
 /**
-* Unity call ios 弹出邀请好友弹窗
- * 旧版游戏暂未用到
+* Unity call ios 返回趣动app
 */
-void ShowInviteFriend(int code, char * info){
-    NSLog(@"Unity 请求打开好友列表弹窗 ShowInviteFriend ===>>");
-    if ([instance existUserInfo]==NO){
-        return;
-    }
-}
-
-/**
-* Unity call ios 获取游戏榜单数据
- *if (type == 0) "world" else "friend"
- *ios 请求完数据后用 PointerGetRankHandler 回调数据给unity
-*/
-void GetRank(int type){
-//    NSLog(@"Unity 获取榜单列表数据 GetRank ===>> %d",type);
-    if ([instance existUserInfo]==NO){
-        return;
+void OnBackPressed(){
+    
+    NSLog(@"Unity 返回app OnBackPressed");
+    NSString * urlStr = @"com.cheedo.oujia://";
+    if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:urlStr]]){
+            [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlStr] options:@{} completionHandler:nil];
     }
-    [HTTPDataProcession GetRank:type rankDataBlock:^(const char *jsonString){
-        NSLog(@"IOS_SKD 回调 榜单列表数据 GetRank ===>> %d %s",type,jsonString);
-        getRankHandler(type,jsonString);
-    }];
-
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+        //杀死进程
+        kill(getpid(), 9);
+    });
+    
 }

+ 0 - 78
SDK/PrefixHeader.h

@@ -1,78 +0,0 @@
-////
-////  PrefixHeader.h
-////  Unity-iPhone
-////
-////  Created by duowan123 on 2021/11/2.
-////
-//
-//#ifndef PrefixHeader_h
-//#define PrefixHeader_h
-//
-//
-///*************************** 获取屏幕 宽度、高度 ***************************/
-//#define SCREEN_WIDTH ([UIScreen mainScreen].bounds.size.width)
-//#define SCREEN_HEIGHT ([UIScreen mainScreen].bounds.size.height)
-///*************************** 状态栏+导航栏 高度 ***************************/
-//#define getRectNavAndStatusHight  self.navigationController.navigationBar.frame.size.height+[[UIApplication sharedApplication] statusBarFrame].size.height
-//#define getTarbarHight (SCREEN_HEIGHT>=812?83:49)
-///*************************** 比例系数布局  ***************************/
-//#define SCALEoefficient(num)   (SCREEN_WIDTH/667.0)*(num)
-//#define SCALE_HIGHT_oefficient(num)   (SCREEN_HEIGHT/375.0)*(num)
-///*************************** 字号大小  ***************************/
-//#define SCALEoefficient_20 20.0*(SCREEN_WIDTH/320.0)///<大标题
-//#define SCALEoefficient_18 18.0*(SCREEN_WIDTH/320.0)///<附标题
-//#define SCALEoefficient_16 16.0*(SCREEN_WIDTH/320.0)///<中标题
-//#define SCALEoefficient_14 14.0*(SCREEN_WIDTH/320.0)///<小标题
-//
-////app跳转 用户信息
-//#define IOSSDK_USERINFO @"iosSdk_userInfo"
-////缓存的步频数据
-//#define IOSSDK_BLESDKDATA @"iosSdk_bleSdk_frequency"
-////custom System UserDefaults
-//#define IOS_NSUSERDEFAULT [NSUserDefaults standardUserDefaults]
-//#define CUS_NOTIFICATIONCENTER [NSNotificationCenter defaultCenter]
-//#define IOSSDK_TOKEN [[IOS_NSUSERDEFAULT objectForKey:IOSSDK_USERINFO] objectForKey:@"token"]
-//#define IOSSDK_GAMEID [[IOS_NSUSERDEFAULT objectForKey:IOSSDK_USERINFO] objectForKey:@"game_type"]
-////#define IOSSDK_GAMEID @"3"
-////#define IOSSDK_TOKEN @"shoes:61652aa99523f9.65681365I94"
-//
-//
-//#ifdef __OBJC__
-//
-//#import <UIKit/UIKit.h>
-//#import <Foundation/Foundation.h>
-//
-////tool
-//#import "MYFactoryManager.h"
-//#import "UIView+ST.h"
-//#import "AlgorithmTool.h"
-//#import "UIColor+Hex.h"
-//
-//////
-////#import "IOSPlatformSDK.h"
-////
-////蓝牙
-//#import <CoreBluetooth/CoreBluetooth.h>
-//#import "LEONBLManager.h"
-//#import "BTDataProcess.h"
-////蓝牙提供的sdk算法
-//#import "GameObjc.h"
-//#define LEFT_FOOT_OC 1
-//#define RIGHT_FOOT_OC 2
-//
-////http
-//#import "HTTPDataProcession.h"
-//#import "UserFriendsModel.h"
-////第三方
-//#import "AFNetworking.h"
-//#import "MBProgressHUD.h"
-////UI
-//#import "SearchDeviceViewController.h"
-//#import "AnimationView.h"
-//#import "PopupView.h"
-//#import "NoDeviceTip.h"
-//
-//#endif
-//
-//
-//#endif /* PrefixHeader_h */

BIN
SDK/ThirdClass/.DS_Store


+ 0 - 0
SDK/HTTP/AFNetworking/AFCompatibilityMacros.h → SDK/ThirdClass/AFNetworking/AFCompatibilityMacros.h


+ 0 - 0
SDK/HTTP/AFNetworking/AFHTTPSessionManager.h → SDK/ThirdClass/AFNetworking/AFHTTPSessionManager.h


+ 0 - 4
SDK/HTTP/AFNetworking/AFHTTPSessionManager.m → SDK/ThirdClass/AFNetworking/AFHTTPSessionManager.m

@@ -94,7 +94,6 @@
 
 - (void)setResponseSerializer:(AFHTTPResponseSerializer <AFURLResponseSerialization> *)responseSerializer {
     NSParameterAssert(responseSerializer);
-
     [super setResponseSerializer:responseSerializer];
 }
 
@@ -111,7 +110,6 @@
         NSString *reason = [NSString stringWithFormat:@"A security policy configured with `%@` can only be applied on a manager with a secure base URL (i.e. https)", pinningMode];
         @throw [NSException exceptionWithName:@"Invalid Security Policy" reason:reason userInfo:nil];
     }
-
     [super setSecurityPolicy:securityPolicy];
 }
 
@@ -299,7 +297,6 @@
 }
 
 #pragma mark - NSSecureCoding
-
 + (BOOL)supportsSecureCoding {
     return YES;
 }
@@ -347,7 +344,6 @@
 
 - (instancetype)copyWithZone:(NSZone *)zone {
     AFHTTPSessionManager *HTTPClient = [[[self class] allocWithZone:zone] initWithBaseURL:self.baseURL sessionConfiguration:self.session.configuration];
-
     HTTPClient.requestSerializer = [self.requestSerializer copyWithZone:zone];
     HTTPClient.responseSerializer = [self.responseSerializer copyWithZone:zone];
     HTTPClient.securityPolicy = [self.securityPolicy copyWithZone:zone];

+ 0 - 0
SDK/HTTP/AFNetworking/AFNetworkReachabilityManager.h → SDK/ThirdClass/AFNetworking/AFNetworkReachabilityManager.h


+ 0 - 0
SDK/HTTP/AFNetworking/AFNetworkReachabilityManager.m → SDK/ThirdClass/AFNetworking/AFNetworkReachabilityManager.m


+ 0 - 0
SDK/HTTP/AFNetworking/AFNetworking.h → SDK/ThirdClass/AFNetworking/AFNetworking.h


+ 0 - 0
SDK/HTTP/AFNetworking/AFSecurityPolicy.h → SDK/ThirdClass/AFNetworking/AFSecurityPolicy.h


+ 1 - 0
SDK/HTTP/AFNetworking/AFSecurityPolicy.m → SDK/ThirdClass/AFNetworking/AFSecurityPolicy.m

@@ -336,6 +336,7 @@ static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) {
     securityPolicy.pinnedCertificates = [self.pinnedCertificates copyWithZone:zone];
 
     return securityPolicy;
+    
 }
 
 @end

+ 0 - 0
SDK/HTTP/AFNetworking/AFURLRequestSerialization.h → SDK/ThirdClass/AFNetworking/AFURLRequestSerialization.h


+ 0 - 0
SDK/HTTP/AFNetworking/AFURLRequestSerialization.m → SDK/ThirdClass/AFNetworking/AFURLRequestSerialization.m


+ 0 - 0
SDK/HTTP/AFNetworking/AFURLResponseSerialization.h → SDK/ThirdClass/AFNetworking/AFURLResponseSerialization.h


+ 0 - 0
SDK/HTTP/AFNetworking/AFURLResponseSerialization.m → SDK/ThirdClass/AFNetworking/AFURLResponseSerialization.m


+ 0 - 0
SDK/HTTP/AFNetworking/AFURLSessionManager.h → SDK/ThirdClass/AFNetworking/AFURLSessionManager.h


+ 0 - 0
SDK/HTTP/AFNetworking/AFURLSessionManager.m → SDK/ThirdClass/AFNetworking/AFURLSessionManager.m


+ 116 - 0
SDK/ThirdClass/AvoidCrash/AvoidCrash.h

@@ -0,0 +1,116 @@
+//
+//  AvoidCrash.h
+//  https://github.com/chenfanfang/AvoidCrash
+//
+//  Created by mac on 16/9/21.
+//  Copyright © 2016年 chenfanfang. All rights reserved.
+//
+
+//===================================================
+//   使用方法和注意事项:
+//   https://www.jianshu.com/p/2b90aa96c0a0
+//===================================================
+
+#import <Foundation/Foundation.h>
+#import <objc/runtime.h>
+
+//category
+#import "NSObject+AvoidCrash.h"
+
+#import "NSArray+AvoidCrash.h"
+#import "NSMutableArray+AvoidCrash.h"
+
+#import "NSDictionary+AvoidCrash.h"
+#import "NSMutableDictionary+AvoidCrash.h"
+
+#import "NSString+AvoidCrash.h"
+#import "NSMutableString+AvoidCrash.h"
+
+#import "NSAttributedString+AvoidCrash.h"
+#import "NSMutableAttributedString+AvoidCrash.h"
+
+//define
+#import "AvoidCrashStubProxy.h"
+
+
+
+
+
+@interface AvoidCrash : NSObject
+
+//===================================================
+//   使用方法和注意事项:
+//   https://www.jianshu.com/p/2b90aa96c0a0
+//===================================================
+
+
+
+/**
+ *  
+ *  开始生效.你可以在AppDelegate的didFinishLaunchingWithOptions方法中调用becomeEffective方法
+ *  【默认不开启  对”unrecognized selector sent to instance”防止崩溃的处理】
+ *
+ *  这是全局生效,若你只需要部分生效,你可以单个进行处理,比如:
+ *  [NSArray avoidCrashExchangeMethod];
+ *  [NSMutableArray avoidCrashExchangeMethod];
+ *  .................
+ *  .................
+ *
+ */
++ (void)becomeEffective;
+
+
+/** 
+ *  相比于becomeEffective,增加
+ *  对”unrecognized selector sent to instance”防止崩溃的处理
+ *
+ *  但是必须配合:
+ *            setupClassStringsArr:和
+ *            setupNoneSelClassStringPrefixsArr
+ *            这两个方法可以同时使用
+ */
++ (void)makeAllEffective;
+
+
+
+/** 
+ *  初始化一个需要防止”unrecognized selector sent to instance”的崩溃的类名数组
+ *  ⚠️不可将@"NSObject"加入classStrings数组中
+ *  ⚠️不可将UI前缀的字符串加入classStrings数组中
+ */
++ (void)setupNoneSelClassStringsArr:(NSArray<NSString *> *)classStrings;
+
+
+/**
+ *  初始化一个需要防止”unrecognized selector sent to instance”的崩溃的类名前缀的数组
+ *  ⚠️不可将UI前缀的字符串(包括@"UI")加入classStringPrefixs数组中
+ *  ⚠️不可将NS前缀的字符串(包括@"NS")加入classStringPrefixs数组中
+ */
++ (void)setupNoneSelClassStringPrefixsArr:(NSArray<NSString *> *)classStringPrefixs;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+//您可以忽略以下方法
+
++ (void)exchangeClassMethod:(Class)anClass method1Sel:(SEL)method1Sel method2Sel:(SEL)method2Sel;
+
++ (void)exchangeInstanceMethod:(Class)anClass method1Sel:(SEL)method1Sel method2Sel:(SEL)method2Sel;
+
++ (void)noteErrorWithException:(NSException *)exception defaultToDo:(NSString *)defaultToDo;
+
+
+@end

+ 220 - 0
SDK/ThirdClass/AvoidCrash/AvoidCrash.m

@@ -0,0 +1,220 @@
+//
+//  AvoidCrash.m
+//  https://github.com/chenfanfang/AvoidCrash
+//
+//  Created by mac on 16/9/21.
+//  Copyright © 2016年 chenfanfang. All rights reserved.
+//
+
+#import "AvoidCrash.h"
+
+
+
+
+#define key_errorName        @"errorName"
+#define key_errorReason      @"errorReason"
+#define key_errorPlace       @"errorPlace"
+#define key_defaultToDo      @"defaultToDo"
+#define key_callStackSymbols @"callStackSymbols"
+#define key_exception        @"exception"
+
+
+@implementation AvoidCrash
+
+
++ (void)becomeEffective {
+    [self effectiveIfDealWithNoneSel:NO];
+    
+}
+
++ (void)makeAllEffective {
+    [self effectiveIfDealWithNoneSel:YES];
+}
+
++ (void)effectiveIfDealWithNoneSel:(BOOL)dealWithNoneSel {
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        
+        [NSObject avoidCrashExchangeMethodIfDealWithNoneSel:dealWithNoneSel];
+        
+        [NSArray avoidCrashExchangeMethod];
+        [NSMutableArray avoidCrashExchangeMethod];
+        
+        [NSDictionary avoidCrashExchangeMethod];
+        [NSMutableDictionary avoidCrashExchangeMethod];
+        
+        [NSString avoidCrashExchangeMethod];
+        [NSMutableString avoidCrashExchangeMethod];
+        
+        [NSAttributedString avoidCrashExchangeMethod];
+        [NSMutableAttributedString avoidCrashExchangeMethod];
+        
+    });
+}
+
++ (void)setupNoneSelClassStringsArr:(NSArray<NSString *> *)classStrings {
+    [NSObject setupNoneSelClassStringsArr:classStrings];
+}
+
+/**
+ *  初始化一个需要防止”unrecognized selector sent to instance”的崩溃的类名前缀的数组
+ */
++ (void)setupNoneSelClassStringPrefixsArr:(NSArray<NSString *> *)classStringPrefixs {
+    [NSObject setupNoneSelClassStringPrefixsArr:classStringPrefixs];
+}
+
+
+/**
+ *  类方法的交换
+ *
+ *  @param anClass    哪个类
+ *  @param method1Sel 方法1
+ *  @param method2Sel 方法2
+ */
++ (void)exchangeClassMethod:(Class)anClass method1Sel:(SEL)method1Sel method2Sel:(SEL)method2Sel {
+    Method method1 = class_getClassMethod(anClass, method1Sel);
+    Method method2 = class_getClassMethod(anClass, method2Sel);
+    method_exchangeImplementations(method1, method2);
+}
+
+
+/**
+ *  对象方法的交换
+ *
+ *  @param anClass    哪个类
+ *  @param method1Sel 方法1(原本的方法)
+ *  @param method2Sel 方法2(要替换成的方法)
+ */
++ (void)exchangeInstanceMethod:(Class)anClass method1Sel:(SEL)method1Sel method2Sel:(SEL)method2Sel {
+    
+    
+    Method originalMethod = class_getInstanceMethod(anClass, method1Sel);
+    Method swizzledMethod = class_getInstanceMethod(anClass, method2Sel);
+    
+    BOOL didAddMethod =
+    class_addMethod(anClass,
+                    method1Sel,
+                    method_getImplementation(swizzledMethod),
+                    method_getTypeEncoding(swizzledMethod));
+    
+    if (didAddMethod) {
+        class_replaceMethod(anClass,
+                            method2Sel,
+                            method_getImplementation(originalMethod),
+                            method_getTypeEncoding(originalMethod));
+    }
+    
+    else {
+        method_exchangeImplementations(originalMethod, swizzledMethod);
+    }
+    
+}
+
+
+
+/**
+ *  获取堆栈主要崩溃精简化的信息<根据正则表达式匹配出来>
+ *
+ *  @param callStackSymbols 堆栈主要崩溃信息
+ *
+ *  @return 堆栈主要崩溃精简化的信息
+ */
+
++ (NSString *)getMainCallStackSymbolMessageWithCallStackSymbols:(NSArray<NSString *> *)callStackSymbols {
+    
+    //mainCallStackSymbolMsg的格式为   +[类名 方法名]  或者 -[类名 方法名]
+    __block NSString *mainCallStackSymbolMsg = nil;
+    
+    //匹配出来的格式为 +[类名 方法名]  或者 -[类名 方法名]
+    NSString *regularExpStr = @"[-\\+]\\[.+\\]";
+    
+    
+    NSRegularExpression *regularExp = [[NSRegularExpression alloc] initWithPattern:regularExpStr options:NSRegularExpressionCaseInsensitive error:nil];
+    
+    
+    for (int index = 2; index < callStackSymbols.count; index++) {
+        NSString *callStackSymbol = callStackSymbols[index];
+        
+        [regularExp enumerateMatchesInString:callStackSymbol options:NSMatchingReportProgress range:NSMakeRange(0, callStackSymbol.length) usingBlock:^(NSTextCheckingResult * _Nullable result, NSMatchingFlags flags, BOOL * _Nonnull stop) {
+            if (result) {
+                NSString* tempCallStackSymbolMsg = [callStackSymbol substringWithRange:result.range];
+                
+                //get className
+                NSString *className = [tempCallStackSymbolMsg componentsSeparatedByString:@" "].firstObject;
+                className = [className componentsSeparatedByString:@"["].lastObject;
+                
+                NSBundle *bundle = [NSBundle bundleForClass:NSClassFromString(className)];
+                
+                //filter category and system class
+                if (![className hasSuffix:@")"] && bundle == [NSBundle mainBundle]) {
+                    mainCallStackSymbolMsg = tempCallStackSymbolMsg;
+                    
+                }
+                *stop = YES;
+            }
+        }];
+        
+        if (mainCallStackSymbolMsg.length) {
+            break;
+        }
+    }
+    
+    return mainCallStackSymbolMsg;
+}
+
+
+/**
+ *  提示崩溃的信息(控制台输出、通知)
+ *
+ *  @param exception   捕获到的异常
+ *  @param defaultToDo 这个框架里默认的做法
+ */
++ (void)noteErrorWithException:(NSException *)exception defaultToDo:(NSString *)defaultToDo {
+
+    //堆栈数据
+    NSArray *callStackSymbolsArr = [NSThread callStackSymbols];
+    
+    //获取在哪个类的哪个方法中实例化的数组  字符串格式 -[类名 方法名]  或者 +[类名 方法名]
+    NSString *mainCallStackSymbolMsg = [AvoidCrash getMainCallStackSymbolMessageWithCallStackSymbols:callStackSymbolsArr];
+    
+    if (mainCallStackSymbolMsg == nil) {
+        
+        mainCallStackSymbolMsg = @"崩溃方法定位失败,请您查看函数调用栈来排查错误原因";
+        
+    }
+    
+    NSString *errorName = exception.name;
+    NSString *errorReason = exception.reason;
+    //errorReason 可能为 -[__NSCFConstantString avoidCrashCharacterAtIndex:]: Range or index out of bounds
+    //将avoidCrash去掉
+    errorReason = [errorReason stringByReplacingOccurrencesOfString:@"avoidCrash" withString:@""];
+    
+    NSString *errorPlace = [NSString stringWithFormat:@"Error Place:%@",mainCallStackSymbolMsg];
+    
+    NSString *logErrorMessage = [NSString stringWithFormat:@"\n\n%@\n\n%@\n%@\n%@\n%@",AvoidCrashSeparatorWithFlag, errorName, errorReason, errorPlace, defaultToDo];
+    
+    logErrorMessage = [NSString stringWithFormat:@"%@\n\n%@\n\n",logErrorMessage,AvoidCrashSeparator];
+    AvoidCrashLog(@"%@",logErrorMessage);
+    
+    
+    //请忽略下面的赋值,目的只是为了能顺利上传到cocoapods
+    logErrorMessage = logErrorMessage;
+    
+    NSDictionary *errorInfoDic = @{
+                                   key_errorName        : errorName,
+                                   key_errorReason      : errorReason,
+                                   key_errorPlace       : errorPlace,
+                                   key_defaultToDo      : defaultToDo,
+                                   key_exception        : exception,
+                                   key_callStackSymbols : callStackSymbolsArr
+                                   };
+    
+    //将错误信息放在字典里,用通知的形式发送出去
+    dispatch_async(dispatch_get_main_queue(), ^{
+        [[NSNotificationCenter defaultCenter] postNotificationName:AvoidCrashNotification object:nil userInfo:errorInfoDic];
+    });
+}
+
+
+
+@end

+ 17 - 0
SDK/ThirdClass/AvoidCrash/AvoidCrashProtocol.h

@@ -0,0 +1,17 @@
+//
+//  AvoidCrashProtocol.h
+//  https://github.com/chenfanfang/AvoidCrash
+//
+//  Created by chenfanfang on 2017/7/22.
+//  Copyright © 2017年 chenfanfang. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+
+@protocol AvoidCrashProtocol <NSObject>
+
+@required
++ (void)avoidCrashExchangeMethod;
+
+@end

+ 37 - 0
SDK/ThirdClass/AvoidCrash/AvoidCrashStubProxy.h

@@ -0,0 +1,37 @@
+//
+//  AvoidCrashStubProxy.h
+//  https://github.com/chenfanfang/AvoidCrash
+//
+//  Created by chenfanfang on 2017/7/25.
+//  Copyright © 2017年 chenfanfang. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+
+#define AvoidCrashNotification @"AvoidCrashNotification"
+#define AvoidCrashIsiOS(version) ([[UIDevice currentDevice].systemVersion floatValue] >= version)
+
+
+//user can ignore below define
+#define AvoidCrashDefaultReturnNil  @"AvoidCrash default is to return nil to avoid crash."
+#define AvoidCrashDefaultIgnore     @"AvoidCrash default is to ignore this operation to avoid crash."
+
+#define AvoidCrashSeparator         @"================================================================"
+#define AvoidCrashSeparatorWithFlag @"========================AvoidCrash Log=========================="
+
+
+#ifdef DEBUG
+
+#define  AvoidCrashLog(...) NSLog(@"%@",[NSString stringWithFormat:__VA_ARGS__])
+
+#else
+
+#define AvoidCrashLog(...)
+#endif
+
+@interface AvoidCrashStubProxy : NSObject
+
+- (void)proxyMethod;
+
+@end

+ 18 - 0
SDK/ThirdClass/AvoidCrash/AvoidCrashStubProxy.m

@@ -0,0 +1,18 @@
+//
+//  AvoidCrashStubProxy.m
+//  https://github.com/chenfanfang/AvoidCrash
+//
+//  Created by chenfanfang on 2017/7/25.
+//  Copyright © 2017年 chenfanfang. All rights reserved.
+//
+
+#import "AvoidCrashStubProxy.h"
+
+
+@implementation AvoidCrashStubProxy
+
+- (void)proxyMethod {
+    
+}
+
+@end

+ 25 - 0
SDK/ThirdClass/AvoidCrash/NSArray+AvoidCrash.h

@@ -0,0 +1,25 @@
+//
+//  NSArray+AvoidCrash.h
+//  https://github.com/chenfanfang/AvoidCrash
+//
+//  Created by mac on 16/9/21.
+//  Copyright © 2016年 chenfanfang. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "AvoidCrashProtocol.h"
+
+@interface NSArray (AvoidCrash)<AvoidCrashProtocol>
+
+
+@end
+
+
+/**
+ *  Can avoid crash method
+ *
+ *  1. NSArray的快速创建方式 NSArray *array = @[@"chenfanfang", @"AvoidCrash"];  //这种创建方式其实调用的是2中的方法
+ *  2. +(instancetype)arrayWithObjects:(const id  _Nonnull __unsafe_unretained *)objects count:(NSUInteger)cnt
+ *  3. - (id)objectAtIndex:(NSUInteger)index
+ *  4. - (void)getObjects:(__unsafe_unretained id  _Nonnull *)objects range:(NSRange)range
+ */    

+ 257 - 0
SDK/ThirdClass/AvoidCrash/NSArray+AvoidCrash.m

@@ -0,0 +1,257 @@
+//
+//  NSArray+AvoidCrash.m
+//  https://github.com/chenfanfang/AvoidCrash
+//
+//  Created by mac on 16/9/21.
+//  Copyright © 2016年 chenfanfang. All rights reserved.
+//
+
+#import "NSArray+AvoidCrash.h"
+
+#import "AvoidCrash.h"
+
+@implementation NSArray (AvoidCrash)
+
+
++ (void)avoidCrashExchangeMethod {
+    
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        //=================
+        //   class method
+        //=================
+        
+        //instance array method exchange
+        [AvoidCrash exchangeClassMethod:[self class] method1Sel:@selector(arrayWithObjects:count:) method2Sel:@selector(AvoidCrashArrayWithObjects:count:)];
+        
+        
+        
+        //====================
+        //   instance method
+        //====================
+        
+        Class __NSArray = NSClassFromString(@"NSArray");
+        Class __NSArrayI = NSClassFromString(@"__NSArrayI");
+        Class __NSSingleObjectArrayI = NSClassFromString(@"__NSSingleObjectArrayI");
+        Class __NSArray0 = NSClassFromString(@"__NSArray0");
+        
+        
+        //objectsAtIndexes:
+        [AvoidCrash exchangeInstanceMethod:__NSArray method1Sel:@selector(objectsAtIndexes:) method2Sel:@selector(avoidCrashObjectsAtIndexes:)];
+        
+        
+        //objectAtIndex:
+        
+        [AvoidCrash exchangeInstanceMethod:__NSArrayI method1Sel:@selector(objectAtIndex:) method2Sel:@selector(__NSArrayIAvoidCrashObjectAtIndex:)];
+        
+        [AvoidCrash exchangeInstanceMethod:__NSSingleObjectArrayI method1Sel:@selector(objectAtIndex:) method2Sel:@selector(__NSSingleObjectArrayIAvoidCrashObjectAtIndex:)];
+        
+        [AvoidCrash exchangeInstanceMethod:__NSArray0 method1Sel:@selector(objectAtIndex:) method2Sel:@selector(__NSArray0AvoidCrashObjectAtIndex:)];
+        
+        //objectAtIndexedSubscript:
+        if (AvoidCrashIsiOS(11.0)) {
+            [AvoidCrash exchangeInstanceMethod:__NSArrayI method1Sel:@selector(objectAtIndexedSubscript:) method2Sel:@selector(__NSArrayIAvoidCrashObjectAtIndexedSubscript:)];
+        }
+        
+        
+        //getObjects:range:
+        [AvoidCrash exchangeInstanceMethod:__NSArray method1Sel:@selector(getObjects:range:) method2Sel:@selector(NSArrayAvoidCrashGetObjects:range:)];
+        
+        [AvoidCrash exchangeInstanceMethod:__NSSingleObjectArrayI method1Sel:@selector(getObjects:range:) method2Sel:@selector(__NSSingleObjectArrayIAvoidCrashGetObjects:range:)];
+        
+        [AvoidCrash exchangeInstanceMethod:__NSArrayI method1Sel:@selector(getObjects:range:) method2Sel:@selector(__NSArrayIAvoidCrashGetObjects:range:)];
+    });
+    
+    
+}
+
+
+//=================================================================
+//                        instance array
+//=================================================================
+#pragma mark - instance array
+
+
++ (instancetype)AvoidCrashArrayWithObjects:(const id  _Nonnull __unsafe_unretained *)objects count:(NSUInteger)cnt {
+    
+    id instance = nil;
+    
+    @try {
+        instance = [self AvoidCrashArrayWithObjects:objects count:cnt];
+    }
+    @catch (NSException *exception) {
+        
+        NSString *defaultToDo = @"AvoidCrash default is to remove nil object and instance a array.";
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+        
+        //以下是对错误数据的处理,把为nil的数据去掉,然后初始化数组
+        NSInteger newObjsIndex = 0;
+        id  _Nonnull __unsafe_unretained newObjects[cnt];
+        
+        for (int i = 0; i < cnt; i++) {
+            if (objects[i] != nil) {
+                newObjects[newObjsIndex] = objects[i];
+                newObjsIndex++;
+            }
+        }
+        instance = [self AvoidCrashArrayWithObjects:newObjects count:newObjsIndex];
+    }
+    @finally {
+        return instance;
+    }
+}
+
+
+
+//=================================================================
+//                     objectAtIndexedSubscript:
+//=================================================================
+#pragma mark - objectAtIndexedSubscript:
+- (id)__NSArrayIAvoidCrashObjectAtIndexedSubscript:(NSUInteger)idx {
+    
+    id object = nil;
+    
+    @try {
+        object = [self __NSArrayIAvoidCrashObjectAtIndexedSubscript:idx];
+    }
+    @catch (NSException *exception) {
+        NSString *defaultToDo = AvoidCrashDefaultReturnNil;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+    }
+    @finally {
+        return object;
+    }
+
+}
+
+
+//=================================================================
+//                       objectsAtIndexes:
+//=================================================================
+#pragma mark - objectsAtIndexes:
+
+- (NSArray *)avoidCrashObjectsAtIndexes:(NSIndexSet *)indexes {
+    
+    NSArray *returnArray = nil;
+    @try {
+        returnArray = [self avoidCrashObjectsAtIndexes:indexes];
+    } @catch (NSException *exception) {
+        NSString *defaultToDo = AvoidCrashDefaultReturnNil;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+        
+    } @finally {
+        return returnArray;
+    }
+}
+
+
+//=================================================================
+//                         objectAtIndex:
+//=================================================================
+#pragma mark - objectAtIndex:
+
+//__NSArrayI  objectAtIndex:
+- (id)__NSArrayIAvoidCrashObjectAtIndex:(NSUInteger)index {
+    id object = nil;
+    
+    @try {
+        object = [self __NSArrayIAvoidCrashObjectAtIndex:index];
+    }
+    @catch (NSException *exception) {
+        NSString *defaultToDo = AvoidCrashDefaultReturnNil;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+    }
+    @finally {
+        return object;
+    }
+}
+
+
+
+//__NSSingleObjectArrayI objectAtIndex:
+- (id)__NSSingleObjectArrayIAvoidCrashObjectAtIndex:(NSUInteger)index {
+    id object = nil;
+    
+    @try {
+        object = [self __NSSingleObjectArrayIAvoidCrashObjectAtIndex:index];
+    }
+    @catch (NSException *exception) {
+        NSString *defaultToDo = AvoidCrashDefaultReturnNil;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+    }
+    @finally {
+        return object;
+    }
+}
+
+//__NSArray0 objectAtIndex:
+- (id)__NSArray0AvoidCrashObjectAtIndex:(NSUInteger)index {
+    id object = nil;
+    
+    @try {
+        object = [self __NSArray0AvoidCrashObjectAtIndex:index];
+    }
+    @catch (NSException *exception) {
+        NSString *defaultToDo = AvoidCrashDefaultReturnNil;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+    }
+    @finally {
+        return object;
+    }
+}
+
+
+//=================================================================
+//                           getObjects:range:
+//=================================================================
+#pragma mark - getObjects:range:
+
+//NSArray getObjects:range:
+- (void)NSArrayAvoidCrashGetObjects:(__unsafe_unretained id  _Nonnull *)objects range:(NSRange)range {
+    
+    @try {
+        [self NSArrayAvoidCrashGetObjects:objects range:range];
+    } @catch (NSException *exception) {
+        
+        NSString *defaultToDo = AvoidCrashDefaultIgnore;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+        
+    } @finally {
+        
+    }
+}
+
+
+//__NSSingleObjectArrayI  getObjects:range:
+- (void)__NSSingleObjectArrayIAvoidCrashGetObjects:(__unsafe_unretained id  _Nonnull *)objects range:(NSRange)range {
+    
+    @try {
+        [self __NSSingleObjectArrayIAvoidCrashGetObjects:objects range:range];
+    } @catch (NSException *exception) {
+        
+        NSString *defaultToDo = AvoidCrashDefaultIgnore;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+        
+    } @finally {
+        //x * 0.17 = 3000
+    }
+    
+}
+
+//__NSArrayI  getObjects:range:
+- (void)__NSArrayIAvoidCrashGetObjects:(__unsafe_unretained id  _Nonnull *)objects range:(NSRange)range {
+    
+    @try {
+        [self __NSArrayIAvoidCrashGetObjects:objects range:range];
+    } @catch (NSException *exception) {
+        
+        NSString *defaultToDo = AvoidCrashDefaultIgnore;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+        
+    } @finally {
+        
+    }
+    
+}
+
+@end

+ 25 - 0
SDK/ThirdClass/AvoidCrash/NSAttributedString+AvoidCrash.h

@@ -0,0 +1,25 @@
+//
+//  NSAttributedString+AvoidCrash.h
+//  https://github.com/chenfanfang/AvoidCrash
+//
+//  Created by mac on 16/10/15.
+//  Copyright © 2016年 chenfanfang. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "AvoidCrashProtocol.h"
+
+@interface NSAttributedString (AvoidCrash)<AvoidCrashProtocol>
+
+
+@end
+
+/**
+ *  Can avoid crash method
+ *
+ *  1.- (instancetype)initWithString:(NSString *)str
+ *  2.- (instancetype)initWithAttributedString:(NSAttributedString *)attrStr
+ *  3.- (instancetype)initWithString:(NSString *)str attributes:(NSDictionary<NSString *,id> *)attrs
+ *
+ *
+ */

+ 96 - 0
SDK/ThirdClass/AvoidCrash/NSAttributedString+AvoidCrash.m

@@ -0,0 +1,96 @@
+//
+//  NSAttributedString+AvoidCrash.m
+//  https://github.com/chenfanfang/AvoidCrash
+//
+//  Created by mac on 16/10/15.
+//  Copyright © 2016年 chenfanfang. All rights reserved.
+//
+
+#import "NSAttributedString+AvoidCrash.h"
+
+#import "AvoidCrash.h"
+
+@implementation NSAttributedString (AvoidCrash)
+
++ (void)avoidCrashExchangeMethod {
+    
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        
+        Class NSConcreteAttributedString = NSClassFromString(@"NSConcreteAttributedString");
+        
+        //initWithString:
+        [AvoidCrash exchangeInstanceMethod:NSConcreteAttributedString method1Sel:@selector(initWithString:) method2Sel:@selector(avoidCrashInitWithString:)];
+        
+        //initWithAttributedString
+        [AvoidCrash exchangeInstanceMethod:NSConcreteAttributedString method1Sel:@selector(initWithAttributedString:) method2Sel:@selector(avoidCrashInitWithAttributedString:)];
+        
+        //initWithString:attributes:
+        [AvoidCrash exchangeInstanceMethod:NSConcreteAttributedString method1Sel:@selector(initWithString:attributes:) method2Sel:@selector(avoidCrashInitWithString:attributes:)];
+    });
+
+}
+
+//=================================================================
+//                           initWithString:
+//=================================================================
+#pragma mark - initWithString:
+
+- (instancetype)avoidCrashInitWithString:(NSString *)str {
+    id object = nil;
+    
+    @try {
+        object = [self avoidCrashInitWithString:str];
+    }
+    @catch (NSException *exception) {
+        NSString *defaultToDo = AvoidCrashDefaultReturnNil;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+    }
+    @finally {
+        return object;
+    }
+}
+
+
+//=================================================================
+//                          initWithAttributedString
+//=================================================================
+#pragma mark - initWithAttributedString
+
+- (instancetype)avoidCrashInitWithAttributedString:(NSAttributedString *)attrStr {
+    id object = nil;
+    
+    @try {
+        object = [self avoidCrashInitWithAttributedString:attrStr];
+    }
+    @catch (NSException *exception) {
+        NSString *defaultToDo = AvoidCrashDefaultReturnNil;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+    }
+    @finally {
+        return object;
+    }
+}
+
+
+//=================================================================
+//                      initWithString:attributes:
+//=================================================================
+#pragma mark - initWithString:attributes:
+
+- (instancetype)avoidCrashInitWithString:(NSString *)str attributes:(NSDictionary<NSString *,id> *)attrs {
+    id object = nil;
+    
+    @try {
+        object = [self avoidCrashInitWithString:str attributes:attrs];
+    }
+    @catch (NSException *exception) {
+        NSString *defaultToDo = AvoidCrashDefaultReturnNil;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+    }
+    @finally {
+        return object;
+    }
+}
+
+@end

+ 24 - 0
SDK/ThirdClass/AvoidCrash/NSDictionary+AvoidCrash.h

@@ -0,0 +1,24 @@
+//
+//  NSDictionary+AvoidCrash.h
+//  https://github.com/chenfanfang/AvoidCrash
+//
+//  Created by mac on 16/9/21.
+//  Copyright © 2016年 chenfanfang. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "AvoidCrashProtocol.h"
+
+@interface NSDictionary (AvoidCrash)<AvoidCrashProtocol>
+
+
+@end
+
+
+/**
+ *  Can avoid crash method
+ *
+ *  1. NSDictionary的快速创建方式 NSDictionary *dict = @{@"frameWork" : @"AvoidCrash"}; //这种创建方式其实调用的是2中的方法
+ *  2. +(instancetype)dictionaryWithObjects:(const id  _Nonnull __unsafe_unretained *)objects forKeys:(const id<NSCopying>  _Nonnull __unsafe_unretained *)keys count:(NSUInteger)cnt
+ *
+ */

+ 56 - 0
SDK/ThirdClass/AvoidCrash/NSDictionary+AvoidCrash.m

@@ -0,0 +1,56 @@
+//
+//  NSDictionary+AvoidCrash.m
+//  https://github.com/chenfanfang/AvoidCrash
+//
+//  Created by mac on 16/9/21.
+//  Copyright © 2016年 chenfanfang. All rights reserved.
+//
+
+#import "NSDictionary+AvoidCrash.h"
+
+#import "AvoidCrash.h"
+
+@implementation NSDictionary (AvoidCrash)
+
++ (void)avoidCrashExchangeMethod {
+    
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        
+        [AvoidCrash exchangeClassMethod:self method1Sel:@selector(dictionaryWithObjects:forKeys:count:) method2Sel:@selector(avoidCrashDictionaryWithObjects:forKeys:count:)];
+    });
+}
+
+
++ (instancetype)avoidCrashDictionaryWithObjects:(const id  _Nonnull __unsafe_unretained *)objects forKeys:(const id<NSCopying>  _Nonnull __unsafe_unretained *)keys count:(NSUInteger)cnt {
+    
+    id instance = nil;
+    
+    @try {
+        instance = [self avoidCrashDictionaryWithObjects:objects forKeys:keys count:cnt];
+    }
+    @catch (NSException *exception) {
+        
+        NSString *defaultToDo = @"AvoidCrash default is to remove nil key-values and instance a dictionary.";
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+        
+        //处理错误的数据,然后重新初始化一个字典
+        NSUInteger index = 0;
+        id  _Nonnull __unsafe_unretained newObjects[cnt];
+        id  _Nonnull __unsafe_unretained newkeys[cnt];
+        
+        for (int i = 0; i < cnt; i++) {
+            if (objects[i] && keys[i]) {
+                newObjects[index] = objects[i];
+                newkeys[index] = keys[i];
+                index++;
+            }
+        }
+        instance = [self avoidCrashDictionaryWithObjects:newObjects forKeys:newkeys count:index];
+    }
+    @finally {
+        return instance;
+    }
+}
+
+@end

+ 26 - 0
SDK/ThirdClass/AvoidCrash/NSMutableArray+AvoidCrash.h

@@ -0,0 +1,26 @@
+//
+//  NSMutableArray+AvoidCrash.h
+//  https://github.com/chenfanfang/AvoidCrash
+//
+//  Created by mac on 16/9/21.
+//  Copyright © 2016年 chenfanfang. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "AvoidCrashProtocol.h"
+
+@interface NSMutableArray (AvoidCrash)<AvoidCrashProtocol>
+
+
+@end
+
+
+/**
+ *  Can avoid crash method
+ *
+ *  1. - (id)objectAtIndex:(NSUInteger)index
+ *  2. - (void)setObject:(id)obj atIndexedSubscript:(NSUInteger)idx
+ *  3. - (void)removeObjectAtIndex:(NSUInteger)index
+ *  4. - (void)insertObject:(id)anObject atIndex:(NSUInteger)index
+ *  5. - (void)getObjects:(__unsafe_unretained id  _Nonnull *)objects range:(NSRange)range
+ */

+ 169 - 0
SDK/ThirdClass/AvoidCrash/NSMutableArray+AvoidCrash.m

@@ -0,0 +1,169 @@
+//
+//  NSMutableArray+AvoidCrash.m
+//  https://github.com/chenfanfang/AvoidCrash
+//
+//  Created by mac on 16/9/21.
+//  Copyright © 2016年 chenfanfang. All rights reserved.
+//
+
+#import "NSMutableArray+AvoidCrash.h"
+
+#import "AvoidCrash.h"
+
+@implementation NSMutableArray (AvoidCrash)
+
++ (void)avoidCrashExchangeMethod {
+    
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        
+        Class arrayMClass = NSClassFromString(@"__NSArrayM");
+        
+        
+        //objectAtIndex:
+        [AvoidCrash exchangeInstanceMethod:arrayMClass method1Sel:@selector(objectAtIndex:) method2Sel:@selector(avoidCrashObjectAtIndex:)];
+        
+        //objectAtIndexedSubscript
+        if (AvoidCrashIsiOS(11.0)) {
+            [AvoidCrash exchangeInstanceMethod:arrayMClass method1Sel:@selector(objectAtIndexedSubscript:) method2Sel:@selector(avoidCrashObjectAtIndexedSubscript:)];
+        }
+        
+        
+        //setObject:atIndexedSubscript:
+        [AvoidCrash exchangeInstanceMethod:arrayMClass method1Sel:@selector(setObject:atIndexedSubscript:) method2Sel:@selector(avoidCrashSetObject:atIndexedSubscript:)];
+        
+        
+        //removeObjectAtIndex:
+        [AvoidCrash exchangeInstanceMethod:arrayMClass method1Sel:@selector(removeObjectAtIndex:) method2Sel:@selector(avoidCrashRemoveObjectAtIndex:)];
+        
+        //insertObject:atIndex:
+        [AvoidCrash exchangeInstanceMethod:arrayMClass method1Sel:@selector(insertObject:atIndex:) method2Sel:@selector(avoidCrashInsertObject:atIndex:)];
+        
+        //getObjects:range:
+        [AvoidCrash exchangeInstanceMethod:arrayMClass method1Sel:@selector(getObjects:range:) method2Sel:@selector(avoidCrashGetObjects:range:)];
+    });
+    
+    
+    
+}
+
+
+//=================================================================
+//                    array set object at index
+//=================================================================
+#pragma mark - get object from array
+
+
+- (void)avoidCrashSetObject:(id)obj atIndexedSubscript:(NSUInteger)idx {
+    
+    @try {
+        [self avoidCrashSetObject:obj atIndexedSubscript:idx];
+    }
+    @catch (NSException *exception) {
+        [AvoidCrash noteErrorWithException:exception defaultToDo:AvoidCrashDefaultIgnore];
+    }
+    @finally {
+        
+    }
+}
+
+
+//=================================================================
+//                    removeObjectAtIndex:
+//=================================================================
+#pragma mark - removeObjectAtIndex:
+
+- (void)avoidCrashRemoveObjectAtIndex:(NSUInteger)index {
+    @try {
+        [self avoidCrashRemoveObjectAtIndex:index];
+    }
+    @catch (NSException *exception) {
+        [AvoidCrash noteErrorWithException:exception defaultToDo:AvoidCrashDefaultIgnore];
+    }
+    @finally {
+        
+    }
+}
+
+
+//=================================================================
+//                    insertObject:atIndex:
+//=================================================================
+#pragma mark - set方法
+- (void)avoidCrashInsertObject:(id)anObject atIndex:(NSUInteger)index {
+    @try {
+        [self avoidCrashInsertObject:anObject atIndex:index];
+    }
+    @catch (NSException *exception) {
+        [AvoidCrash noteErrorWithException:exception defaultToDo:AvoidCrashDefaultIgnore];
+    }
+    @finally {
+        
+    }
+}
+
+
+//=================================================================
+//                           objectAtIndex:
+//=================================================================
+#pragma mark - objectAtIndex:
+
+- (id)avoidCrashObjectAtIndex:(NSUInteger)index {
+    id object = nil;
+    
+    @try {
+        object = [self avoidCrashObjectAtIndex:index];
+    }
+    @catch (NSException *exception) {
+        NSString *defaultToDo = AvoidCrashDefaultReturnNil;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+    }
+    @finally {
+        return object;
+    }
+}
+
+//=================================================================
+//                     objectAtIndexedSubscript:
+//=================================================================
+#pragma mark - objectAtIndexedSubscript:
+- (id)avoidCrashObjectAtIndexedSubscript:(NSUInteger)idx {
+    id object = nil;
+    
+    @try {
+        object = [self avoidCrashObjectAtIndexedSubscript:idx];
+    }
+    @catch (NSException *exception) {
+        NSString *defaultToDo = AvoidCrashDefaultReturnNil;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+    }
+    @finally {
+        return object;
+    }
+    
+}
+
+
+//=================================================================
+//                         getObjects:range:
+//=================================================================
+#pragma mark - getObjects:range:
+
+- (void)avoidCrashGetObjects:(__unsafe_unretained id  _Nonnull *)objects range:(NSRange)range {
+    
+    @try {
+        [self avoidCrashGetObjects:objects range:range];
+    } @catch (NSException *exception) {
+        
+        NSString *defaultToDo = AvoidCrashDefaultIgnore;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+        
+    } @finally {
+        
+    }
+}
+
+
+
+
+@end

+ 23 - 0
SDK/ThirdClass/AvoidCrash/NSMutableAttributedString+AvoidCrash.h

@@ -0,0 +1,23 @@
+//
+//  NSMutableAttributedString+AvoidCrash.h
+//  https://github.com/chenfanfang/AvoidCrash
+//
+//  Created by mac on 16/10/15.
+//  Copyright © 2016年 chenfanfang. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "AvoidCrashProtocol.h"
+
+@interface NSMutableAttributedString (AvoidCrash)<AvoidCrashProtocol>
+
+
+@end
+
+
+/**
+ *  Can avoid crash method
+ *
+ *  1.- (instancetype)initWithString:(NSString *)str
+ *  2.- (instancetype)initWithString:(NSString *)str attributes:(NSDictionary<NSString *,id> *)attrs
+ */

+ 74 - 0
SDK/ThirdClass/AvoidCrash/NSMutableAttributedString+AvoidCrash.m

@@ -0,0 +1,74 @@
+//
+//  NSMutableAttributedString+AvoidCrash.m
+//  https://github.com/chenfanfang/AvoidCrash
+//
+//  Created by mac on 16/10/15.
+//  Copyright © 2016年 chenfanfang. All rights reserved.
+//
+
+#import "NSMutableAttributedString+AvoidCrash.h"
+
+#import "AvoidCrash.h"
+
+@implementation NSMutableAttributedString (AvoidCrash)
+
++ (void)avoidCrashExchangeMethod {
+    
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        
+        Class NSConcreteMutableAttributedString = NSClassFromString(@"NSConcreteMutableAttributedString");
+        
+        //initWithString:
+        [AvoidCrash exchangeInstanceMethod:NSConcreteMutableAttributedString method1Sel:@selector(initWithString:) method2Sel:@selector(avoidCrashInitWithString:)];
+        
+        //initWithString:attributes:
+        [AvoidCrash exchangeInstanceMethod:NSConcreteMutableAttributedString method1Sel:@selector(initWithString:attributes:) method2Sel:@selector(avoidCrashInitWithString:attributes:)];
+    });
+}
+
+//=================================================================
+//                          initWithString:
+//=================================================================
+#pragma mark - initWithString:
+
+
+- (instancetype)avoidCrashInitWithString:(NSString *)str {
+    id object = nil;
+    
+    @try {
+        object = [self avoidCrashInitWithString:str];
+    }
+    @catch (NSException *exception) {
+        NSString *defaultToDo = AvoidCrashDefaultReturnNil;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+    }
+    @finally {
+        return object;
+    }
+}
+
+
+//=================================================================
+//                     initWithString:attributes:
+//=================================================================
+#pragma mark - initWithString:attributes:
+
+
+- (instancetype)avoidCrashInitWithString:(NSString *)str attributes:(NSDictionary<NSString *,id> *)attrs {
+    id object = nil;
+    
+    @try {
+        object = [self avoidCrashInitWithString:str attributes:attrs];
+    }
+    @catch (NSException *exception) {
+        NSString *defaultToDo = AvoidCrashDefaultReturnNil;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+    }
+    @finally {
+        return object;
+    }
+}
+
+
+@end

+ 24 - 0
SDK/ThirdClass/AvoidCrash/NSMutableDictionary+AvoidCrash.h

@@ -0,0 +1,24 @@
+//
+//  NSMutableDictionary+AvoidCrash.h
+//  https://github.com/chenfanfang/AvoidCrash
+//
+//  Created by mac on 16/9/22.
+//  Copyright © 2016年 chenfanfang. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "AvoidCrashProtocol.h"
+
+@interface NSMutableDictionary (AvoidCrash)<AvoidCrashProtocol>
+
+
+@end
+
+
+/**
+ *  Can avoid crash method
+ *
+ *  1. - (void)setObject:(id)anObject forKey:(id<NSCopying>)aKey
+ *  2. - (void)removeObjectForKey:(id)aKey
+ *
+ */

+ 95 - 0
SDK/ThirdClass/AvoidCrash/NSMutableDictionary+AvoidCrash.m

@@ -0,0 +1,95 @@
+//
+//  NSMutableDictionary+AvoidCrash.m
+//  https://github.com/chenfanfang/AvoidCrash
+//
+//  Created by mac on 16/9/22.
+//  Copyright © 2016年 chenfanfang. All rights reserved.
+//
+
+#import "NSMutableDictionary+AvoidCrash.h"
+
+#import "AvoidCrash.h"
+
+@implementation NSMutableDictionary (AvoidCrash)
+
++ (void)avoidCrashExchangeMethod {
+    
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        Class dictionaryM = NSClassFromString(@"__NSDictionaryM");
+        
+        //setObject:forKey:
+        [AvoidCrash exchangeInstanceMethod:dictionaryM method1Sel:@selector(setObject:forKey:) method2Sel:@selector(avoidCrashSetObject:forKey:)];
+        
+        //setObject:forKeyedSubscript:
+        if (AvoidCrashIsiOS(11.0)) {
+            [AvoidCrash exchangeInstanceMethod:dictionaryM method1Sel:@selector(setObject:forKeyedSubscript:) method2Sel:@selector(avoidCrashSetObject:forKeyedSubscript:)];
+        }
+        
+        
+        
+        //removeObjectForKey:
+        Method removeObjectForKey = class_getInstanceMethod(dictionaryM, @selector(removeObjectForKey:));
+        Method avoidCrashRemoveObjectForKey = class_getInstanceMethod(dictionaryM, @selector(avoidCrashRemoveObjectForKey:));
+        method_exchangeImplementations(removeObjectForKey, avoidCrashRemoveObjectForKey);
+    });
+}
+
+
+//=================================================================
+//                       setObject:forKey:
+//=================================================================
+#pragma mark - setObject:forKey:
+
+- (void)avoidCrashSetObject:(id)anObject forKey:(id<NSCopying>)aKey {
+    
+    @try {
+        [self avoidCrashSetObject:anObject forKey:aKey];
+    }
+    @catch (NSException *exception) {
+        [AvoidCrash noteErrorWithException:exception defaultToDo:AvoidCrashDefaultIgnore];
+    }
+    @finally {
+        
+    }
+}
+
+//=================================================================
+//                  setObject:forKeyedSubscript:
+//=================================================================
+#pragma mark - setObject:forKeyedSubscript:
+- (void)avoidCrashSetObject:(id)obj forKeyedSubscript:(id<NSCopying>)key {
+    @try {
+        [self avoidCrashSetObject:obj forKeyedSubscript:key];
+    }
+    @catch (NSException *exception) {
+        [AvoidCrash noteErrorWithException:exception defaultToDo:AvoidCrashDefaultIgnore];
+    }
+    @finally {
+        
+    }
+}
+
+
+//=================================================================
+//                       removeObjectForKey:
+//=================================================================
+#pragma mark - removeObjectForKey:
+
+- (void)avoidCrashRemoveObjectForKey:(id)aKey {
+    
+    @try {
+        [self avoidCrashRemoveObjectForKey:aKey];
+    }
+    @catch (NSException *exception) {
+        [AvoidCrash noteErrorWithException:exception defaultToDo:AvoidCrashDefaultIgnore];
+    }
+    @finally {
+        
+    }
+}
+
+
+
+
+@end

+ 29 - 0
SDK/ThirdClass/AvoidCrash/NSMutableString+AvoidCrash.h

@@ -0,0 +1,29 @@
+//
+//  NSMutableString+AvoidCrash.h
+//  https://github.com/chenfanfang/AvoidCrash
+//
+//  Created by mac on 16/10/6.
+//  Copyright © 2016年 chenfanfang. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "AvoidCrashProtocol.h"
+
+@interface NSMutableString (AvoidCrash)<AvoidCrashProtocol>
+
+
+@end
+
+
+/**
+ *  Can avoid crash method
+ *
+ *  1. 由于NSMutableString是继承于NSString,所以这里和NSString有些同样的方法就不重复写了
+ *  2. - (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)aString
+ *  3. - (void)insertString:(NSString *)aString atIndex:(NSUInteger)loc
+ *  4. - (void)deleteCharactersInRange:(NSRange)range
+ *
+ */
+
+
+

+ 97 - 0
SDK/ThirdClass/AvoidCrash/NSMutableString+AvoidCrash.m

@@ -0,0 +1,97 @@
+//
+//  NSMutableString+AvoidCrash.m
+//  https://github.com/chenfanfang/AvoidCrash
+//
+//  Created by mac on 16/10/6.
+//  Copyright © 2016年 chenfanfang. All rights reserved.
+//
+
+#import "NSMutableString+AvoidCrash.h"
+
+#import "AvoidCrash.h"
+
+@implementation NSMutableString (AvoidCrash)
+
++ (void)avoidCrashExchangeMethod {
+    
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        
+        Class stringClass = NSClassFromString(@"__NSCFString");
+        
+        //replaceCharactersInRange
+        [AvoidCrash exchangeInstanceMethod:stringClass method1Sel:@selector(replaceCharactersInRange:withString:) method2Sel:@selector(avoidCrashReplaceCharactersInRange:withString:)];
+        
+        //insertString:atIndex:
+        [AvoidCrash exchangeInstanceMethod:stringClass method1Sel:@selector(insertString:atIndex:) method2Sel:@selector(avoidCrashInsertString:atIndex:)];
+        
+        //deleteCharactersInRange
+        [AvoidCrash exchangeInstanceMethod:stringClass method1Sel:@selector(deleteCharactersInRange:) method2Sel:@selector(avoidCrashDeleteCharactersInRange:)];
+    });
+}
+
+//=================================================================
+//                     replaceCharactersInRange
+//=================================================================
+#pragma mark - replaceCharactersInRange
+
+- (void)avoidCrashReplaceCharactersInRange:(NSRange)range withString:(NSString *)aString {
+    
+    @try {
+        [self avoidCrashReplaceCharactersInRange:range withString:aString];
+    }
+    @catch (NSException *exception) {
+        NSString *defaultToDo = AvoidCrashDefaultIgnore;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+    }
+    @finally {
+        
+    }
+}
+
+//=================================================================
+//                     insertString:atIndex:
+//=================================================================
+#pragma mark - insertString:atIndex:
+
+- (void)avoidCrashInsertString:(NSString *)aString atIndex:(NSUInteger)loc {
+    
+    @try {
+        [self avoidCrashInsertString:aString atIndex:loc];
+    }
+    @catch (NSException *exception) {
+        NSString *defaultToDo = AvoidCrashDefaultIgnore;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+    }
+    @finally {
+        
+    }
+}
+
+//=================================================================
+//                   deleteCharactersInRange
+//=================================================================
+#pragma mark - deleteCharactersInRange
+
+- (void)avoidCrashDeleteCharactersInRange:(NSRange)range {
+    
+    @try {
+        [self avoidCrashDeleteCharactersInRange:range];
+    }
+    @catch (NSException *exception) {
+        NSString *defaultToDo = AvoidCrashDefaultIgnore;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+    }
+    @finally {
+        
+    }
+}
+
+
+
+
+
+
+
+
+@end

+ 34 - 0
SDK/ThirdClass/AvoidCrash/NSObject+AvoidCrash.h

@@ -0,0 +1,34 @@
+//
+//  NSObject+AvoidCrash.h
+//  https://github.com/chenfanfang/AvoidCrash
+//
+//  Created by mac on 16/10/11.
+//  Copyright © 2016年 chenfanfang. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+
+@interface NSObject (AvoidCrash)
+
+/** 
+ *  ifDealWithNoneSel : 是否开启"unrecognized selector sent to instance"异常的捕获
+ */
++ (void)avoidCrashExchangeMethodIfDealWithNoneSel:(BOOL)ifDealWithNoneSel;
+
+
++ (void)setupNoneSelClassStringsArr:(NSArray<NSString *> *)classStrings;
+
++ (void)setupNoneSelClassStringPrefixsArr:(NSArray<NSString *> *)classStringPrefixs;
+
+@end
+
+/**
+ *  Can avoid crash method
+ *
+ *  1.- (void)setValue:(id)value forKey:(NSString *)key
+ *  2.- (void)setValue:(id)value forKeyPath:(NSString *)keyPath
+ *  3.- (void)setValue:(id)value forUndefinedKey:(NSString *)key //这个方法一般用来重写,不会主动调用
+ *  4.- (void)setValuesForKeysWithDictionary:(NSDictionary<NSString *,id> *)keyedValues
+ *  5. unrecognized selector sent to instance
+ */

+ 220 - 0
SDK/ThirdClass/AvoidCrash/NSObject+AvoidCrash.m

@@ -0,0 +1,220 @@
+//
+//  NSObject+AvoidCrash.m
+//  https://github.com/chenfanfang/AvoidCrash
+//
+//  Created by mac on 16/10/11.
+//  Copyright © 2016年 chenfanfang. All rights reserved.
+//
+
+#import "NSObject+AvoidCrash.h"
+#import "AvoidCrash.h"
+#import "AvoidCrashStubProxy.h"
+
+@implementation NSObject (AvoidCrash)
+
+
++ (void)avoidCrashExchangeMethodIfDealWithNoneSel:(BOOL)ifDealWithNoneSel {
+    
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        //setValue:forKey:
+        [AvoidCrash exchangeInstanceMethod:[self class] method1Sel:@selector(setValue:forKey:) method2Sel:@selector(avoidCrashSetValue:forKey:)];
+        
+        //setValue:forKeyPath:
+        [AvoidCrash exchangeInstanceMethod:[self class] method1Sel:@selector(setValue:forKeyPath:) method2Sel:@selector(avoidCrashSetValue:forKeyPath:)];
+        
+        //setValue:forUndefinedKey:
+        [AvoidCrash exchangeInstanceMethod:[self class] method1Sel:@selector(setValue:forUndefinedKey:) method2Sel:@selector(avoidCrashSetValue:forUndefinedKey:)];
+        
+        //setValuesForKeysWithDictionary:
+        [AvoidCrash exchangeInstanceMethod:[self class] method1Sel:@selector(setValuesForKeysWithDictionary:) method2Sel:@selector(avoidCrashSetValuesForKeysWithDictionary:)];
+        
+        
+        //unrecognized selector sent to instance
+        if (ifDealWithNoneSel) {
+            [AvoidCrash exchangeInstanceMethod:[self class] method1Sel:@selector(methodSignatureForSelector:) method2Sel:@selector(avoidCrashMethodSignatureForSelector:)];
+            [AvoidCrash exchangeInstanceMethod:[self class] method1Sel:@selector(forwardInvocation:) method2Sel:@selector(avoidCrashForwardInvocation:)];
+        }
+    });
+}
+
+
+//=================================================================
+//              unrecognized selector sent to instance
+//=================================================================
+#pragma mark - unrecognized selector sent to instance
+
+
+static NSMutableArray *noneSelClassStrings;
+static NSMutableArray *noneSelClassStringPrefixs;
+
++ (void)setupNoneSelClassStringsArr:(NSArray<NSString *> *)classStrings {
+    
+    if (noneSelClassStrings){
+        NSString *warningMsg = [NSString stringWithFormat:@"\n\n%@\n\n[AvoidCrash setupNoneSelClassStringsArr:];\n调用一此即可,多次调用会自动忽略后面的调用\n\n%@\n\n",AvoidCrashSeparatorWithFlag,AvoidCrashSeparator];
+        AvoidCrashLog(@"%@",warningMsg);
+    }
+    
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        noneSelClassStrings = [NSMutableArray array];
+        for (NSString *className in classStrings) {
+            if ([className hasPrefix:@"UI"] == NO &&
+                [className isEqualToString:NSStringFromClass([NSObject class])] == NO) {
+                [noneSelClassStrings addObject:className];
+            } else {
+                NSString *warningMsg = [NSString stringWithFormat:@"\n\n%@\n\n[AvoidCrash setupNoneSelClassStringsArr:];\n会忽略UI开头的类和NSObject类(请使用NSObject的子类)\n\n%@\n\n",AvoidCrashSeparatorWithFlag,AvoidCrashSeparator];
+                AvoidCrashLog(@"%@",warningMsg);
+            }
+        }
+    });
+    
+}
+
+/**
+ *  初始化一个需要防止”unrecognized selector sent to instance”的崩溃的类名前缀的数组
+ */
++ (void)setupNoneSelClassStringPrefixsArr:(NSArray<NSString *> *)classStringPrefixs {
+    if (noneSelClassStringPrefixs) {
+        
+        NSString *warningMsg = [NSString stringWithFormat:@"\n\n%@\n\n[AvoidCrash setupNoneSelClassStringPrefixsArr:];\n调用一此即可,多次调用会自动忽略后面的调用\n\n%@\n\n",AvoidCrashSeparatorWithFlag,AvoidCrashSeparator];
+        AvoidCrashLog(@"%@",warningMsg);
+    }
+    
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        
+        noneSelClassStringPrefixs = [NSMutableArray array];
+        for (NSString *classNamePrefix in classStringPrefixs) {
+            if ([classNamePrefix hasPrefix:@"UI"] == NO &&
+                [classNamePrefix hasPrefix:@"NS"] == NO) {
+                [noneSelClassStringPrefixs addObject:classNamePrefix];
+                
+            } else {
+                NSString *warningMsg = [NSString stringWithFormat:@"\n\n%@\n\n[AvoidCrash setupNoneSelClassStringsArr:];\n会忽略UI开头的类和NS开头的类\n若需要对NS开头的类防止”unrecognized selector sent to instance”(比如NSArray),请使用setupNoneSelClassStringsArr:\n\n%@\n\n",AvoidCrashSeparatorWithFlag,AvoidCrashSeparator];
+                AvoidCrashLog(@"%@",warningMsg);
+            }
+        }
+    });
+}
+
+- (NSMethodSignature *)avoidCrashMethodSignatureForSelector:(SEL)aSelector {
+    
+    NSMethodSignature *ms = [self avoidCrashMethodSignatureForSelector:aSelector];
+    
+    BOOL flag = NO;
+    if (ms == nil) {
+        for (NSString *classStr in noneSelClassStrings) {
+            if ([self isKindOfClass:NSClassFromString(classStr)]) {
+                ms = [AvoidCrashStubProxy instanceMethodSignatureForSelector:@selector(proxyMethod)];
+                flag = YES;
+                break;
+            }
+        }
+    }
+    if (flag == NO) {
+        NSString *selfClass = NSStringFromClass([self class]);
+        for (NSString *classStrPrefix in noneSelClassStringPrefixs) {
+            if ([selfClass hasPrefix:classStrPrefix]) {
+                ms = [AvoidCrashStubProxy instanceMethodSignatureForSelector:@selector(proxyMethod)];
+            }
+        }
+    }
+    return ms;
+}
+
+- (void)avoidCrashForwardInvocation:(NSInvocation *)anInvocation {
+    
+    @try {
+        [self avoidCrashForwardInvocation:anInvocation];
+        
+    } @catch (NSException *exception) {
+        NSString *defaultToDo = AvoidCrashDefaultIgnore;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+        
+    } @finally {
+        
+    }
+    
+}
+
+
+//=================================================================
+//                         setValue:forKey:
+//=================================================================
+#pragma mark - setValue:forKey:
+
+- (void)avoidCrashSetValue:(id)value forKey:(NSString *)key {
+    @try {
+        [self avoidCrashSetValue:value forKey:key];
+    }
+    @catch (NSException *exception) {
+        NSString *defaultToDo = AvoidCrashDefaultIgnore;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+    }
+    @finally {
+        
+    }
+}
+
+
+//=================================================================
+//                     setValue:forKeyPath:
+//=================================================================
+#pragma mark - setValue:forKeyPath:
+
+- (void)avoidCrashSetValue:(id)value forKeyPath:(NSString *)keyPath {
+    @try {
+        [self avoidCrashSetValue:value forKeyPath:keyPath];
+    }
+    @catch (NSException *exception) {
+        NSString *defaultToDo = AvoidCrashDefaultIgnore;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+    }
+    @finally {
+        
+    }
+}
+
+
+
+//=================================================================
+//                     setValue:forUndefinedKey:
+//=================================================================
+#pragma mark - setValue:forUndefinedKey:
+
+- (void)avoidCrashSetValue:(id)value forUndefinedKey:(NSString *)key {
+    @try {
+        [self avoidCrashSetValue:value forUndefinedKey:key];
+    }
+    @catch (NSException *exception) {
+        NSString *defaultToDo = AvoidCrashDefaultIgnore;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+    }
+    @finally {
+        
+    }
+}
+
+
+//=================================================================
+//                  setValuesForKeysWithDictionary:
+//=================================================================
+#pragma mark - setValuesForKeysWithDictionary:
+
+- (void)avoidCrashSetValuesForKeysWithDictionary:(NSDictionary<NSString *,id> *)keyedValues {
+    @try {
+        [self avoidCrashSetValuesForKeysWithDictionary:keyedValues];
+    }
+    @catch (NSException *exception) {
+        NSString *defaultToDo = AvoidCrashDefaultIgnore;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+    }
+    @finally {
+        
+    }
+}
+
+
+
+@end

+ 29 - 0
SDK/ThirdClass/AvoidCrash/NSString+AvoidCrash.h

@@ -0,0 +1,29 @@
+//
+//  NSString+AvoidCrash.h
+//  https://github.com/chenfanfang/AvoidCrash
+//
+//  Created by mac on 16/10/5.
+//  Copyright © 2016年 chenfanfang. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "AvoidCrashProtocol.h"
+
+@interface NSString (AvoidCrash)<AvoidCrashProtocol>
+
+
+@end
+
+
+/**
+ *  Can avoid crash method
+ *
+ *  1. - (unichar)characterAtIndex:(NSUInteger)index
+ *  2. - (NSString *)substringFromIndex:(NSUInteger)from
+ *  3. - (NSString *)substringToIndex:(NSUInteger)to {
+ *  4. - (NSString *)substringWithRange:(NSRange)range {
+ *  5. - (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement
+ *  6. - (NSString *)stringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement options:(NSStringCompareOptions)options range:(NSRange)searchRange
+ *  7. - (NSString *)stringByReplacingCharactersInRange:(NSRange)range withString:(NSString *)replacement
+ *
+ */

+ 204 - 0
SDK/ThirdClass/AvoidCrash/NSString+AvoidCrash.m

@@ -0,0 +1,204 @@
+//
+//  NSString+AvoidCrash.m
+//  https://github.com/chenfanfang/AvoidCrash
+//
+//  Created by mac on 16/10/5.
+//  Copyright © 2016年 chenfanfang. All rights reserved.
+//
+
+#import "NSString+AvoidCrash.h"
+
+#import "AvoidCrash.h"
+
+@implementation NSString (AvoidCrash)
+
++ (void)avoidCrashExchangeMethod {
+    
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        Class stringClass = NSClassFromString(@"__NSCFConstantString");
+        
+        //characterAtIndex
+        [AvoidCrash exchangeInstanceMethod:stringClass method1Sel:@selector(characterAtIndex:) method2Sel:@selector(avoidCrashCharacterAtIndex:)];
+        
+        //substringFromIndex
+        [AvoidCrash exchangeInstanceMethod:stringClass method1Sel:@selector(substringFromIndex:) method2Sel:@selector(avoidCrashSubstringFromIndex:)];
+        
+        //substringToIndex
+        [AvoidCrash exchangeInstanceMethod:stringClass method1Sel:@selector(substringToIndex:) method2Sel:@selector(avoidCrashSubstringToIndex:)];
+        
+        //substringWithRange:
+        [AvoidCrash exchangeInstanceMethod:stringClass method1Sel:@selector(substringWithRange:) method2Sel:@selector(avoidCrashSubstringWithRange:)];
+        
+        //stringByReplacingOccurrencesOfString:
+        [AvoidCrash exchangeInstanceMethod:stringClass method1Sel:@selector(stringByReplacingOccurrencesOfString:withString:) method2Sel:@selector(avoidCrashStringByReplacingOccurrencesOfString:withString:)];
+        
+        //stringByReplacingOccurrencesOfString:withString:options:range:
+        [AvoidCrash exchangeInstanceMethod:stringClass method1Sel:@selector(stringByReplacingOccurrencesOfString:withString:options:range:) method2Sel:@selector(avoidCrashStringByReplacingOccurrencesOfString:withString:options:range:)];
+        
+        //stringByReplacingCharactersInRange:withString:
+        [AvoidCrash exchangeInstanceMethod:stringClass method1Sel:@selector(stringByReplacingCharactersInRange:withString:) method2Sel:@selector(avoidCrashStringByReplacingCharactersInRange:withString:)];
+    });
+    
+}
+
+
+//=================================================================
+//                           characterAtIndex:
+//=================================================================
+#pragma mark - characterAtIndex:
+
+- (unichar)avoidCrashCharacterAtIndex:(NSUInteger)index {
+    
+    unichar characteristic;
+    @try {
+        characteristic = [self avoidCrashCharacterAtIndex:index];
+    }
+    @catch (NSException *exception) {
+        
+        NSString *defaultToDo = @"AvoidCrash default is to return a without assign unichar.";
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+    }
+    @finally {
+        return characteristic;
+    }
+}
+
+//=================================================================
+//                           substringFromIndex:
+//=================================================================
+#pragma mark - substringFromIndex:
+
+- (NSString *)avoidCrashSubstringFromIndex:(NSUInteger)from {
+    
+    NSString *subString = nil;
+    
+    @try {
+        subString = [self avoidCrashSubstringFromIndex:from];
+    }
+    @catch (NSException *exception) {
+        
+        NSString *defaultToDo = AvoidCrashDefaultReturnNil;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+        subString = nil;
+    }
+    @finally {
+        return subString;
+    }
+}
+
+//=================================================================
+//                           substringToIndex
+//=================================================================
+#pragma mark - substringToIndex
+
+- (NSString *)avoidCrashSubstringToIndex:(NSUInteger)to {
+    
+    NSString *subString = nil;
+    
+    @try {
+        subString = [self avoidCrashSubstringToIndex:to];
+    }
+    @catch (NSException *exception) {
+        NSString *defaultToDo = AvoidCrashDefaultReturnNil;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+        subString = nil;
+    }
+    @finally {
+        return subString;
+    }
+}
+
+
+//=================================================================
+//                           substringWithRange:
+//=================================================================
+#pragma mark - substringWithRange:
+
+- (NSString *)avoidCrashSubstringWithRange:(NSRange)range {
+    
+    NSString *subString = nil;
+    
+    @try {
+        subString = [self avoidCrashSubstringWithRange:range];
+    }
+    @catch (NSException *exception) {
+        NSString *defaultToDo = AvoidCrashDefaultReturnNil;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+        subString = nil;
+    }
+    @finally {
+        return subString;
+    }
+}
+
+//=================================================================
+//                stringByReplacingOccurrencesOfString:
+//=================================================================
+#pragma mark - stringByReplacingOccurrencesOfString:
+
+- (NSString *)avoidCrashStringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement {
+    
+    NSString *newStr = nil;
+    
+    @try {
+        newStr = [self avoidCrashStringByReplacingOccurrencesOfString:target withString:replacement];
+    }
+    @catch (NSException *exception) {
+        NSString *defaultToDo = AvoidCrashDefaultReturnNil;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+        newStr = nil;
+    }
+    @finally {
+        return newStr;
+    }
+}
+
+//=================================================================
+//  stringByReplacingOccurrencesOfString:withString:options:range:
+//=================================================================
+#pragma mark - stringByReplacingOccurrencesOfString:withString:options:range:
+
+- (NSString *)avoidCrashStringByReplacingOccurrencesOfString:(NSString *)target withString:(NSString *)replacement options:(NSStringCompareOptions)options range:(NSRange)searchRange {
+    
+    NSString *newStr = nil;
+    
+    @try {
+        newStr = [self avoidCrashStringByReplacingOccurrencesOfString:target withString:replacement options:options range:searchRange];
+    }
+    @catch (NSException *exception) {
+        NSString *defaultToDo = AvoidCrashDefaultReturnNil;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+        newStr = nil;
+    }
+    @finally {
+        return newStr;
+    }
+}
+
+
+//=================================================================
+//       stringByReplacingCharactersInRange:withString:
+//=================================================================
+#pragma mark - stringByReplacingCharactersInRange:withString:
+
+- (NSString *)avoidCrashStringByReplacingCharactersInRange:(NSRange)range withString:(NSString *)replacement {
+
+    
+    NSString *newStr = nil;
+    
+    @try {
+        newStr = [self avoidCrashStringByReplacingCharactersInRange:range withString:replacement];
+    }
+    @catch (NSException *exception) {
+        NSString *defaultToDo = AvoidCrashDefaultReturnNil;
+        [AvoidCrash noteErrorWithException:exception defaultToDo:defaultToDo];
+        newStr = nil;
+    }
+    @finally {
+        return newStr;
+    }
+}
+
+
+@end

BIN
SDK/ThirdClass/Bugly-2.5.9/Bugly.framework/Bugly


+ 163 - 0
SDK/ThirdClass/Bugly-2.5.9/Bugly.framework/Headers/Bugly.h

@@ -0,0 +1,163 @@
+//
+//  Bugly.h
+//
+//  Version: 2.5(9)
+//
+//  Copyright (c) 2017年 Tencent. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+#import "BuglyConfig.h"
+#import "BuglyLog.h"
+
+BLY_START_NONNULL
+
+@interface Bugly : NSObject
+
+/**
+ *  初始化Bugly,使用默认BuglyConfigs
+ *
+ *  @param appId 注册Bugly分配的应用唯一标识
+ */
++ (void)startWithAppId:(NSString * BLY_NULLABLE)appId;
+
+/**
+ *  使用指定配置初始化Bugly
+ *
+ *  @param appId 注册Bugly分配的应用唯一标识
+ *  @param config 传入配置的 BuglyConfig
+ */
++ (void)startWithAppId:(NSString * BLY_NULLABLE)appId
+                config:(BuglyConfig * BLY_NULLABLE)config;
+
+/**
+ *  使用指定配置初始化Bugly
+ *
+ *  @param appId 注册Bugly分配的应用唯一标识
+ *  @param development 是否开发设备
+ *  @param config 传入配置的 BuglyConfig
+ */
++ (void)startWithAppId:(NSString * BLY_NULLABLE)appId
+     developmentDevice:(BOOL)development
+                config:(BuglyConfig * BLY_NULLABLE)config;
+
+/**
+ *  设置用户标识
+ *
+ *  @param userId 用户标识
+ */
++ (void)setUserIdentifier:(NSString *)userId;
+
+/**
+ *  更新版本信息
+ *
+ *  @param version 应用版本信息
+ */
++ (void)updateAppVersion:(NSString *)version;
+
+/**
+ *  设置关键数据,随崩溃信息上报
+ *
+ *  @param value KEY
+ *  @param key VALUE
+ */
++ (void)setUserValue:(NSString *)value
+              forKey:(NSString *)key;
+
+/**
+ *  获取USER ID
+ *
+ *  @return USER ID
+ */
++ (NSString *)buglyUserIdentifier;
+
+/**
+ *  获取关键数据
+ *
+ *  @return 关键数据
+ */
++ (NSDictionary * BLY_NULLABLE)allUserValues;
+
+/**
+ *  设置标签
+ *
+ *  @param tag 标签ID,可在网站生成
+ */
++ (void)setTag:(NSUInteger)tag;
+
+/**
+ *  获取当前设置标签
+ *
+ *  @return 当前标签ID
+ */
++ (NSUInteger)currentTag;
+
+/**
+ *  获取设备ID
+ *
+ *  @return 设备ID
+ */
++ (NSString *)buglyDeviceId;
+
+/**
+ *  上报自定义Objective-C异常
+ *
+ *  @param exception 异常信息
+ */
++ (void)reportException:(NSException *)exception;
+
+/**
+ *  上报错误
+ *
+ *  @param error 错误信息
+ */
++ (void)reportError:(NSError *)error;
+
+/**
+ *    @brief 上报自定义错误
+ *
+ *    @param category    类型(Cocoa=3,CSharp=4,JS=5,Lua=6)
+ *    @param aName       名称
+ *    @param aReason     错误原因
+ *    @param aStackArray 堆栈
+ *    @param info        附加数据
+ *    @param terminate   上报后是否退出应用进程
+ */
++ (void)reportExceptionWithCategory:(NSUInteger)category
+                               name:(NSString *)aName
+                             reason:(NSString *)aReason
+                          callStack:(NSArray *)aStackArray
+                          extraInfo:(NSDictionary *)info
+                       terminateApp:(BOOL)terminate;
+
+/**
+ *  SDK 版本信息
+ *
+ *  @return SDK版本号
+ */
++ (NSString *)sdkVersion;
+
+/**
+ *  APP 版本信息
+ *
+ *  @return SDK版本号
+ */
++ (NSString *)appVersion;
+
+/**
+ *  App 是否发生了连续闪退
+ *  如果 启动SDK 且 5秒内 闪退,且次数达到 3次 则判定为连续闪退
+ *
+ *  @return 是否连续闪退
+ */
++ (BOOL)isAppCrashedOnStartUpExceedTheLimit;
+
+/**
+ *  关闭bugly监控
+ */
++ (void)closeCrashReport;
+
+BLY_END_NONNULL
+
+@end

+ 141 - 0
SDK/ThirdClass/Bugly-2.5.9/Bugly.framework/Headers/BuglyConfig.h

@@ -0,0 +1,141 @@
+//
+//  BuglyConfig.h
+//  Bugly
+//
+//  Copyright (c) 2016年 Tencent. All rights reserved.
+//
+
+#pragma once
+
+#define BLY_UNAVAILABLE(x) __attribute__((unavailable(x)))
+
+#if __has_feature(nullability)
+#define BLY_NONNULL __nonnull
+#define BLY_NULLABLE __nullable
+#define BLY_START_NONNULL _Pragma("clang assume_nonnull begin")
+#define BLY_END_NONNULL _Pragma("clang assume_nonnull end")
+#else
+#define BLY_NONNULL
+#define BLY_NULLABLE
+#define BLY_START_NONNULL
+#define BLY_END_NONNULL
+#endif
+
+#import <Foundation/Foundation.h>
+
+#import "BuglyLog.h"
+
+BLY_START_NONNULL
+
+@protocol BuglyDelegate <NSObject>
+
+@optional
+/**
+ *  发生异常时回调
+ *
+ *  @param exception 异常信息
+ *
+ *  @return 返回需上报记录,随异常上报一起上报
+ */
+- (NSString * BLY_NULLABLE)attachmentForException:(NSException * BLY_NULLABLE)exception;
+
+
+/**
+ *  策略激活时回调
+ *
+ *  @param tacticInfo
+ *
+ *  @return app是否弹框展示
+ */
+- (BOOL) h5AlertForTactic:(NSDictionary *)tacticInfo;
+
+@end
+
+@interface BuglyConfig : NSObject
+
+/**
+ *  SDK Debug信息开关, 默认关闭
+ */
+@property (nonatomic, assign) BOOL debugMode;
+
+/**
+ *  设置自定义渠道标识
+ */
+@property (nonatomic, copy) NSString *channel;
+
+/**
+ *  设置自定义版本号
+ */
+@property (nonatomic, copy) NSString *version;
+
+/**
+ *  设置自定义设备唯一标识
+ */
+@property (nonatomic, copy) NSString *deviceIdentifier;
+
+/**
+ *  卡顿监控开关,默认关闭
+ */
+@property (nonatomic) BOOL blockMonitorEnable;
+
+/**
+ *  卡顿监控判断间隔,单位为秒
+ */
+@property (nonatomic) NSTimeInterval blockMonitorTimeout;
+
+/**
+ *  设置 App Groups Id (如有使用 Bugly iOS Extension SDK,请设置该值)
+ */
+@property (nonatomic, copy) NSString *applicationGroupIdentifier;
+
+/**
+ *  进程内还原开关,默认开启
+ */
+@property (nonatomic) BOOL symbolicateInProcessEnable;
+
+/**
+ *  非正常退出事件记录开关,默认关闭
+ */
+@property (nonatomic) BOOL unexpectedTerminatingDetectionEnable;
+
+/**
+ *  页面信息记录开关,默认开启
+ */
+@property (nonatomic) BOOL viewControllerTrackingEnable;
+
+/**
+ *  Bugly Delegate
+ */
+@property (nonatomic, assign) id<BuglyDelegate> delegate;
+
+/**
+ * 控制自定义日志上报,默认值为BuglyLogLevelSilent,即关闭日志记录功能。
+ * 如果设置为BuglyLogLevelWarn,则在崩溃时会上报Warn、Error接口打印的日志
+ */
+@property (nonatomic, assign) BuglyLogLevel reportLogLevel;
+
+/**
+ *  崩溃数据过滤器,如果崩溃堆栈的模块名包含过滤器中设置的关键字,则崩溃数据不会进行上报
+ *  例如,过滤崩溃堆栈中包含搜狗输入法的数据,可以添加过滤器关键字SogouInputIPhone.dylib等
+ */
+@property (nonatomic, copy) NSArray *excludeModuleFilter;
+
+/**
+ * 控制台日志上报开关,默认开启
+ */
+@property (nonatomic, assign) BOOL consolelogEnable;
+
+/**
+ * 崩溃退出超时,如果监听到崩溃后,App一直没有退出,则到达超时时间后会自动abort进程退出
+ * 默认值 5s, 单位 秒
+ * 当赋值为0时,则不会自动abort进程退出
+ */
+@property (nonatomic, assign) NSUInteger crashAbortTimeout;
+
+/**
+ *  设置自定义联网、crash上报域名
+ */
+@property (nonatomic, copy) NSString *crashServerUrl;
+
+@end
+BLY_END_NONNULL

+ 78 - 0
SDK/ThirdClass/Bugly-2.5.9/Bugly.framework/Headers/BuglyLog.h

@@ -0,0 +1,78 @@
+//
+//  BuglyLog.h
+//  Bugly
+//
+//  Copyright (c) 2017年 Tencent. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+// Log level for Bugly Log
+typedef NS_ENUM(NSUInteger, BuglyLogLevel) {
+    BuglyLogLevelSilent  = 0,
+    BuglyLogLevelError   = 1,
+    BuglyLogLevelWarn    = 2,
+    BuglyLogLevelInfo    = 3,
+    BuglyLogLevelDebug   = 4,
+    BuglyLogLevelVerbose = 5,
+};
+#pragma mark -
+
+OBJC_EXTERN void BLYLog(BuglyLogLevel level, NSString *format, ...) NS_FORMAT_FUNCTION(2, 3);
+
+OBJC_EXTERN void BLYLogv(BuglyLogLevel level, NSString *format, va_list args) NS_FORMAT_FUNCTION(2, 0);
+
+#pragma mark -
+#define BUGLY_LOG_MACRO(_level, fmt, ...) [BuglyLog level:_level tag:nil log:fmt, ##__VA_ARGS__]
+
+#define BLYLogError(fmt, ...)   BUGLY_LOG_MACRO(BuglyLogLevelError, fmt, ##__VA_ARGS__)
+#define BLYLogWarn(fmt, ...)    BUGLY_LOG_MACRO(BuglyLogLevelWarn,  fmt, ##__VA_ARGS__)
+#define BLYLogInfo(fmt, ...)    BUGLY_LOG_MACRO(BuglyLogLevelInfo, fmt, ##__VA_ARGS__)
+#define BLYLogDebug(fmt, ...)   BUGLY_LOG_MACRO(BuglyLogLevelDebug, fmt, ##__VA_ARGS__)
+#define BLYLogVerbose(fmt, ...) BUGLY_LOG_MACRO(BuglyLogLevelVerbose, fmt, ##__VA_ARGS__)
+
+#pragma mark - Interface
+@interface BuglyLog : NSObject
+
+/**
+ *    @brief  初始化日志模块
+ *
+ *    @param level 设置默认日志级别,默认BLYLogLevelSilent
+ *
+ *    @param printConsole 是否打印到控制台,默认NO
+ */
++ (void)initLogger:(BuglyLogLevel) level consolePrint:(BOOL)printConsole;
+
+/**
+ *    @brief 打印BLYLogLevelInfo日志
+ *
+ *    @param format   日志内容 总日志大小限制为:字符串长度30k,条数200
+ */
++ (void)log:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2);
+
+/**
+ *    @brief  打印日志
+ *
+ *    @param level 日志级别
+ *    @param message   日志内容 总日志大小限制为:字符串长度30k,条数200
+ */
++ (void)level:(BuglyLogLevel) level logs:(NSString *)message;
+
+/**
+ *    @brief  打印日志
+ *
+ *    @param level 日志级别
+ *    @param format   日志内容 总日志大小限制为:字符串长度30k,条数200
+ */
++ (void)level:(BuglyLogLevel) level log:(NSString *)format, ... NS_FORMAT_FUNCTION(2, 3);
+
+/**
+ *    @brief  打印日志
+ *
+ *    @param level  日志级别
+ *    @param tag    日志模块分类
+ *    @param format   日志内容 总日志大小限制为:字符串长度30k,条数200
+ */
++ (void)level:(BuglyLogLevel) level tag:(NSString *) tag log:(NSString *)format, ... NS_FORMAT_FUNCTION(3, 4);
+
+@end

+ 12 - 0
SDK/ThirdClass/Bugly-2.5.9/Bugly.framework/Modules/module.modulemap

@@ -0,0 +1,12 @@
+framework module Bugly {
+	umbrella header "Bugly.h"
+	
+	export *
+	module * { export * }
+	
+	link framework "Foundation"
+	link framework "Security"
+	link framework "SystemConfiguration"
+	link "c++"
+	link "z"
+}

+ 154 - 0
SDK/ThirdClass/socket/SRWebSocket.h

@@ -0,0 +1,154 @@
+//
+//   Copyright 2012 Square Inc.
+//
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+//
+
+#import <Foundation/Foundation.h>
+#import <Security/SecCertificate.h>
+
+typedef NS_ENUM(NSInteger, SRReadyState) {
+    SR_CONNECTING   = 0,
+    SR_OPEN         = 1,
+    SR_CLOSING      = 2,
+    SR_CLOSED       = 3,
+};
+
+typedef enum SRStatusCode : NSInteger {
+    // 0–999: Reserved and not used.
+    SRStatusCodeNormal = 1000,
+    SRStatusCodeGoingAway = 1001,
+    SRStatusCodeProtocolError = 1002,
+    SRStatusCodeUnhandledType = 1003,
+    // 1004 reserved.
+    SRStatusNoStatusReceived = 1005,
+    SRStatusCodeAbnormal = 1006,
+    SRStatusCodeInvalidUTF8 = 1007,
+    SRStatusCodePolicyViolated = 1008,
+    SRStatusCodeMessageTooBig = 1009,
+    SRStatusCodeMissingExtension = 1010,
+    SRStatusCodeInternalError = 1011,
+    SRStatusCodeServiceRestart = 1012,
+    SRStatusCodeTryAgainLater = 1013,
+    // 1014: Reserved for future use by the WebSocket standard.
+    SRStatusCodeTLSHandshake = 1015,
+    // 1016–1999: Reserved for future use by the WebSocket standard.
+    // 2000–2999: Reserved for use by WebSocket extensions.
+    // 3000–3999: Available for use by libraries and frameworks. May not be used by applications. Available for registration at the IANA via first-come, first-serve.
+    // 4000–4999: Available for use by applications.
+} SRStatusCode;
+
+@class SRWebSocket;
+
+extern NSString *const SRWebSocketErrorDomain;
+extern NSString *const SRHTTPResponseErrorKey;
+
+#pragma mark - SRWebSocketDelegate
+
+@protocol SRWebSocketDelegate;
+
+#pragma mark - SRWebSocket
+
+@interface SRWebSocket : NSObject <NSStreamDelegate>
+
+@property (nonatomic, weak) id <SRWebSocketDelegate> delegate;
+
+@property (nonatomic, readonly) SRReadyState readyState;
+@property (nonatomic, readonly, retain) NSURL *url;
+
+
+@property (nonatomic, readonly) CFHTTPMessageRef receivedHTTPHeaders;
+
+// Optional array of cookies (NSHTTPCookie objects) to apply to the connections
+@property (nonatomic, readwrite) NSArray * requestCookies;
+
+// This returns the negotiated protocol.
+// It will be nil until after the handshake completes.
+@property (nonatomic, readonly, copy) NSString *protocol;
+
+// Protocols should be an array of strings that turn into Sec-WebSocket-Protocol.
+- (id)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray *)protocols allowsUntrustedSSLCertificates:(BOOL)allowsUntrustedSSLCertificates;
+- (id)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray *)protocols;
+- (id)initWithURLRequest:(NSURLRequest *)request;
+
+// Some helper constructors.
+- (id)initWithURL:(NSURL *)url protocols:(NSArray *)protocols allowsUntrustedSSLCertificates:(BOOL)allowsUntrustedSSLCertificates;
+- (id)initWithURL:(NSURL *)url protocols:(NSArray *)protocols;
+- (id)initWithURL:(NSURL *)url;
+
+// Delegate queue will be dispatch_main_queue by default.
+// You cannot set both OperationQueue and dispatch_queue.
+- (void)setDelegateOperationQueue:(NSOperationQueue*) queue;
+- (void)setDelegateDispatchQueue:(dispatch_queue_t) queue;
+
+// By default, it will schedule itself on +[NSRunLoop SR_networkRunLoop] using defaultModes.
+- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode;
+- (void)unscheduleFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode;
+
+// SRWebSockets are intended for one-time-use only.  Open should be called once and only once.
+- (void)open;
+
+- (void)close;
+- (void)closeWithCode:(NSInteger)code reason:(NSString *)reason;
+
+// Send a UTF8 String or Data.
+- (void)send:(id)data;
+
+// Send Data (can be nil) in a ping message.
+- (void)sendPing:(NSData *)data;
+
+@end
+
+#pragma mark - SRWebSocketDelegate
+
+@protocol SRWebSocketDelegate <NSObject>
+
+// message will either be an NSString if the server is using text
+// or NSData if the server is using binary.
+- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message;
+
+@optional
+
+- (void)webSocketDidOpen:(SRWebSocket *)webSocket;
+- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error;
+- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean;
+- (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload;
+
+// Return YES to convert messages sent as Text to an NSString. Return NO to skip NSData -> NSString conversion for Text messages. Defaults to YES.
+- (BOOL)webSocketShouldConvertTextFrameToString:(SRWebSocket *)webSocket;
+
+@end
+
+#pragma mark - NSURLRequest (SRCertificateAdditions)
+
+@interface NSURLRequest (SRCertificateAdditions)
+
+@property (nonatomic, retain, readonly) NSArray *SR_SSLPinnedCertificates;
+
+@end
+
+#pragma mark - NSMutableURLRequest (SRCertificateAdditions)
+
+@interface NSMutableURLRequest (SRCertificateAdditions)
+
+@property (nonatomic, retain) NSArray *SR_SSLPinnedCertificates;
+
+@end
+
+#pragma mark - NSRunLoop (SRWebSocket)
+
+@interface NSRunLoop (SRWebSocket)
+
++ (NSRunLoop *)SR_networkRunLoop;
+
+@end

+ 1916 - 0
SDK/ThirdClass/socket/SRWebSocket.m

@@ -0,0 +1,1916 @@
+//
+//   Copyright 2012 Square Inc.
+//
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+//
+
+
+#import "SRWebSocket.h"
+
+#if TARGET_OS_IPHONE
+#define HAS_ICU
+#endif
+
+#ifdef HAS_ICU
+#import <unicode/utf8.h>
+#endif
+
+#if TARGET_OS_IPHONE
+#import <Endian.h>
+#else
+#import <CoreServices/CoreServices.h>
+#endif
+
+#import <CommonCrypto/CommonDigest.h>
+#import <Security/SecRandom.h>
+
+#if OS_OBJECT_USE_OBJC_RETAIN_RELEASE
+#define sr_dispatch_retain(x)
+#define sr_dispatch_release(x)
+#define maybe_bridge(x) ((__bridge void *) x)
+#else
+#define sr_dispatch_retain(x) dispatch_retain(x)
+#define sr_dispatch_release(x) dispatch_release(x)
+#define maybe_bridge(x) (x)
+#endif
+
+#if !__has_feature(objc_arc) 
+#error SocketRocket must be compiled with ARC enabled
+#endif
+
+
+typedef enum  {
+    SROpCodeTextFrame = 0x1,
+    SROpCodeBinaryFrame = 0x2,
+    // 3-7 reserved.
+    SROpCodeConnectionClose = 0x8,
+    SROpCodePing = 0x9,
+    SROpCodePong = 0xA,
+    // B-F reserved.
+} SROpCode;
+
+typedef struct {
+    BOOL fin;
+//  BOOL rsv1;
+//  BOOL rsv2;
+//  BOOL rsv3;
+    uint8_t opcode;
+    BOOL masked;
+    uint64_t payload_length;
+} frame_header;
+
+static NSString *const SRWebSocketAppendToSecKeyString = @"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+
+static inline int32_t validate_dispatch_data_partial_string(NSData *data);
+static inline void SRFastLog(NSString *format, ...);
+
+@interface NSData (SRWebSocket)
+
+- (NSString *)stringBySHA1ThenBase64Encoding;
+
+@end
+
+
+@interface NSString (SRWebSocket)
+
+- (NSString *)stringBySHA1ThenBase64Encoding;
+
+@end
+
+
+@interface NSURL (SRWebSocket)
+
+// The origin isn't really applicable for a native application.
+// So instead, just map ws -> http and wss -> https.
+- (NSString *)SR_origin;
+
+@end
+
+
+@interface _SRRunLoopThread : NSThread
+
+@property (nonatomic, readonly) NSRunLoop *runLoop;
+
+@end
+
+
+static NSString *newSHA1String(const char *bytes, size_t length) {
+    uint8_t md[CC_SHA1_DIGEST_LENGTH];
+
+    assert(length >= 0);
+    assert(length <= UINT32_MAX);
+    CC_SHA1(bytes, (CC_LONG)length, md);
+    
+    NSData *data = [NSData dataWithBytes:md length:CC_SHA1_DIGEST_LENGTH];
+    
+    if ([data respondsToSelector:@selector(base64EncodedStringWithOptions:)]) {
+        return [data base64EncodedStringWithOptions:0];
+    }
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+    return [data base64Encoding];
+#pragma clang diagnostic pop
+}
+
+@implementation NSData (SRWebSocket)
+
+- (NSString *)stringBySHA1ThenBase64Encoding;
+{
+    return newSHA1String(self.bytes, self.length);
+}
+
+@end
+
+
+@implementation NSString (SRWebSocket)
+
+- (NSString *)stringBySHA1ThenBase64Encoding;
+{
+    return newSHA1String(self.UTF8String, self.length);
+}
+
+@end
+
+NSString *const SRWebSocketErrorDomain = @"SRWebSocketErrorDomain";
+NSString *const SRHTTPResponseErrorKey = @"HTTPResponseStatusCode";
+
+// Returns number of bytes consumed. Returning 0 means you didn't match.
+// Sends bytes to callback handler;
+typedef size_t (^stream_scanner)(NSData *collected_data);
+
+typedef void (^data_callback)(SRWebSocket *webSocket,  NSData *data);
+
+@interface SRIOConsumer : NSObject {
+    stream_scanner _scanner;
+    data_callback _handler;
+    size_t _bytesNeeded;
+    BOOL _readToCurrentFrame;
+    BOOL _unmaskBytes;
+}
+@property (nonatomic, copy, readonly) stream_scanner consumer;
+@property (nonatomic, copy, readonly) data_callback handler;
+@property (nonatomic, assign) size_t bytesNeeded;
+@property (nonatomic, assign, readonly) BOOL readToCurrentFrame;
+@property (nonatomic, assign, readonly) BOOL unmaskBytes;
+
+@end
+
+// This class is not thread-safe, and is expected to always be run on the same queue.
+@interface SRIOConsumerPool : NSObject
+
+- (id)initWithBufferCapacity:(NSUInteger)poolSize;
+
+- (SRIOConsumer *)consumerWithScanner:(stream_scanner)scanner handler:(data_callback)handler bytesNeeded:(size_t)bytesNeeded readToCurrentFrame:(BOOL)readToCurrentFrame unmaskBytes:(BOOL)unmaskBytes;
+- (void)returnConsumer:(SRIOConsumer *)consumer;
+
+@end
+
+@interface SRWebSocket ()  <NSStreamDelegate>
+
+@property (nonatomic) SRReadyState readyState;
+
+@property (nonatomic) NSOperationQueue *delegateOperationQueue;
+@property (nonatomic) dispatch_queue_t delegateDispatchQueue;
+
+// Specifies whether SSL trust chain should NOT be evaluated.
+// By default this flag is set to NO, meaning only secure SSL connections are allowed.
+// For DEBUG builds this flag is ignored, and SSL connections are allowed regardless
+// of the certificate trust configuration
+@property (nonatomic, readwrite) BOOL allowsUntrustedSSLCertificates;
+
+@end
+
+
+@implementation SRWebSocket {
+    NSInteger _webSocketVersion;
+    
+    NSOperationQueue *_delegateOperationQueue;
+    dispatch_queue_t _delegateDispatchQueue;
+    
+    dispatch_queue_t _workQueue;
+    NSMutableArray *_consumers;
+
+    NSInputStream *_inputStream;
+    NSOutputStream *_outputStream;
+   
+    NSMutableData *_readBuffer;
+    NSUInteger _readBufferOffset;
+ 
+    NSMutableData *_outputBuffer;
+    NSUInteger _outputBufferOffset;
+
+    uint8_t _currentFrameOpcode;
+    size_t _currentFrameCount;
+    size_t _readOpCount;
+    uint32_t _currentStringScanPosition;
+    NSMutableData *_currentFrameData;
+    
+    NSString *_closeReason;
+    
+    NSString *_secKey;
+    NSString *_basicAuthorizationString;
+    
+    BOOL _pinnedCertFound;
+    
+    uint8_t _currentReadMaskKey[4];
+    size_t _currentReadMaskOffset;
+
+    BOOL _consumerStopped;
+    
+    BOOL _closeWhenFinishedWriting;
+    BOOL _failed;
+
+    BOOL _secure;
+    NSURLRequest *_urlRequest;
+
+    BOOL _sentClose;
+    BOOL _didFail;
+    BOOL _cleanupScheduled;
+    int _closeCode;
+    
+    BOOL _isPumping;
+    
+    NSMutableSet *_scheduledRunloops;
+    
+    // We use this to retain ourselves.
+    __strong SRWebSocket *_selfRetain;
+    
+    NSArray *_requestedProtocols;
+    SRIOConsumerPool *_consumerPool;
+}
+
+@synthesize delegate = _delegate;
+@synthesize url = _url;
+@synthesize readyState = _readyState;
+@synthesize protocol = _protocol;
+
+static __strong NSData *CRLFCRLF;
+
++ (void)initialize;
+{
+    CRLFCRLF = [[NSData alloc] initWithBytes:"\r\n\r\n" length:4];
+}
+
+- (id)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray *)protocols allowsUntrustedSSLCertificates:(BOOL)allowsUntrustedSSLCertificates;
+{
+    self = [super init];
+    if (self) {
+        assert(request.URL);
+        _url = request.URL;
+        _urlRequest = request;
+        _allowsUntrustedSSLCertificates = allowsUntrustedSSLCertificates;
+        
+        _requestedProtocols = [protocols copy];
+        
+        [self _SR_commonInit];
+    }
+    
+    return self;
+}
+
+- (id)initWithURLRequest:(NSURLRequest *)request protocols:(NSArray *)protocols;
+{
+    return [self initWithURLRequest:request protocols:protocols allowsUntrustedSSLCertificates:NO];
+}
+
+- (id)initWithURLRequest:(NSURLRequest *)request;
+{
+    return [self initWithURLRequest:request protocols:nil];
+}
+
+- (id)initWithURL:(NSURL *)url;
+{
+    return [self initWithURL:url protocols:nil];
+}
+
+- (id)initWithURL:(NSURL *)url protocols:(NSArray *)protocols;
+{
+    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];    
+    return [self initWithURLRequest:request protocols:protocols];
+}
+
+- (id)initWithURL:(NSURL *)url protocols:(NSArray *)protocols allowsUntrustedSSLCertificates:(BOOL)allowsUntrustedSSLCertificates;
+{
+    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url];
+    return [self initWithURLRequest:request protocols:protocols allowsUntrustedSSLCertificates:allowsUntrustedSSLCertificates];
+}
+
+- (void)_SR_commonInit;
+{
+    NSString *scheme = _url.scheme.lowercaseString;
+    assert([scheme isEqualToString:@"ws"] || [scheme isEqualToString:@"http"] || [scheme isEqualToString:@"wss"] || [scheme isEqualToString:@"https"]);
+    
+    if ([scheme isEqualToString:@"wss"] || [scheme isEqualToString:@"https"]) {
+        _secure = YES;
+    }
+    
+    _readyState = SR_CONNECTING;
+    _consumerStopped = YES;
+    _webSocketVersion = 13;
+    
+    _workQueue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
+    
+    // Going to set a specific on the queue so we can validate we're on the work queue
+    dispatch_queue_set_specific(_workQueue, (__bridge void *)self, maybe_bridge(_workQueue), NULL);
+    
+    _delegateDispatchQueue = dispatch_get_main_queue();
+    sr_dispatch_retain(_delegateDispatchQueue);
+    
+    _readBuffer = [[NSMutableData alloc] init];
+    _outputBuffer = [[NSMutableData alloc] init];
+    
+    _currentFrameData = [[NSMutableData alloc] init];
+
+    _consumers = [[NSMutableArray alloc] init];
+    
+    _consumerPool = [[SRIOConsumerPool alloc] init];
+    
+    _scheduledRunloops = [[NSMutableSet alloc] init];
+    
+    [self _initializeStreams];
+    
+    // default handlers
+}
+
+- (void)assertOnWorkQueue;
+{
+    assert(dispatch_get_specific((__bridge void *)self) == maybe_bridge(_workQueue));
+}
+
+- (void)dealloc
+{
+    _inputStream.delegate = nil;
+    _outputStream.delegate = nil;
+
+    [_inputStream close];
+    [_outputStream close];
+    
+    if (_workQueue) {
+        sr_dispatch_release(_workQueue);
+        _workQueue = NULL;
+    }
+    
+    if (_receivedHTTPHeaders) {
+        CFRelease(_receivedHTTPHeaders);
+        _receivedHTTPHeaders = NULL;
+    }
+    
+    if (_delegateDispatchQueue) {
+        sr_dispatch_release(_delegateDispatchQueue);
+        _delegateDispatchQueue = NULL;
+    }
+}
+
+#ifndef NDEBUG
+
+- (void)setReadyState:(SRReadyState)aReadyState;
+{
+    assert(aReadyState > _readyState);
+    _readyState = aReadyState;
+}
+
+#endif
+
+- (void)open;
+{
+    assert(_url);
+    NSAssert(_readyState == SR_CONNECTING, @"Cannot call -(void)open on SRWebSocket more than once");
+
+    _selfRetain = self;
+
+    if (_urlRequest.timeoutInterval > 0)
+    {
+        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, _urlRequest.timeoutInterval * NSEC_PER_SEC);
+        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
+            if (self.readyState == SR_CONNECTING)
+                [self _failWithError:[NSError errorWithDomain:@"com.squareup.SocketRocket" code:504 userInfo:@{NSLocalizedDescriptionKey: @"Timeout Connecting to Server"}]];
+        });
+    }
+
+    [self openConnection];
+}
+
+// Calls block on delegate queue
+- (void)_performDelegateBlock:(dispatch_block_t)block;
+{
+    if (_delegateOperationQueue) {
+        [_delegateOperationQueue addOperationWithBlock:block];
+    } else {
+        assert(_delegateDispatchQueue);
+        dispatch_async(_delegateDispatchQueue, block);
+    }
+}
+
+- (void)setDelegateDispatchQueue:(dispatch_queue_t)queue;
+{
+    if (queue) {
+        sr_dispatch_retain(queue);
+    }
+    
+    if (_delegateDispatchQueue) {
+        sr_dispatch_release(_delegateDispatchQueue);
+    }
+    
+    _delegateDispatchQueue = queue;
+}
+
+- (BOOL)_checkHandshake:(CFHTTPMessageRef)httpMessage;
+{
+    NSString *acceptHeader = CFBridgingRelease(CFHTTPMessageCopyHeaderFieldValue(httpMessage, CFSTR("Sec-WebSocket-Accept")));
+
+    if (acceptHeader == nil) {
+        return NO;
+    }
+    
+    NSString *concattedString = [_secKey stringByAppendingString:SRWebSocketAppendToSecKeyString];
+    NSString *expectedAccept = [concattedString stringBySHA1ThenBase64Encoding];
+    
+    return [acceptHeader isEqualToString:expectedAccept];
+}
+
+- (void)_HTTPHeadersDidFinish;
+{
+    NSInteger responseCode = CFHTTPMessageGetResponseStatusCode(_receivedHTTPHeaders);
+    
+    if (responseCode >= 400) {
+        SRFastLog(@"Request failed with response code %d", responseCode);
+        [self _failWithError:[NSError errorWithDomain:SRWebSocketErrorDomain code:2132 userInfo:@{NSLocalizedDescriptionKey:[NSString stringWithFormat:@"received bad response code from server %ld", (long)responseCode], SRHTTPResponseErrorKey:@(responseCode)}]];
+        return;
+    }
+    
+    if(![self _checkHandshake:_receivedHTTPHeaders]) {
+        [self _failWithError:[NSError errorWithDomain:SRWebSocketErrorDomain code:2133 userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Invalid Sec-WebSocket-Accept response"] forKey:NSLocalizedDescriptionKey]]];
+        return;
+    }
+    
+    NSString *negotiatedProtocol = CFBridgingRelease(CFHTTPMessageCopyHeaderFieldValue(_receivedHTTPHeaders, CFSTR("Sec-WebSocket-Protocol")));
+    if (negotiatedProtocol) {
+        // Make sure we requested the protocol
+        if ([_requestedProtocols indexOfObject:negotiatedProtocol] == NSNotFound) {
+            [self _failWithError:[NSError errorWithDomain:SRWebSocketErrorDomain code:2133 userInfo:[NSDictionary dictionaryWithObject:[NSString stringWithFormat:@"Server specified Sec-WebSocket-Protocol that wasn't requested"] forKey:NSLocalizedDescriptionKey]]];
+            return;
+        }
+        
+        _protocol = negotiatedProtocol;
+    }
+    
+    self.readyState = SR_OPEN;
+    
+    if (!_didFail) {
+        [self _readFrameNew];
+    }
+
+    [self _performDelegateBlock:^{
+        if ([self.delegate respondsToSelector:@selector(webSocketDidOpen:)]) {
+            [self.delegate webSocketDidOpen:self];
+        };
+    }];
+}
+
+
+- (void)_readHTTPHeader;
+{
+    if (_receivedHTTPHeaders == NULL) {
+        _receivedHTTPHeaders = CFHTTPMessageCreateEmpty(NULL, NO);
+    }
+                        
+    [self _readUntilHeaderCompleteWithCallback:^(SRWebSocket *self,  NSData *data) {
+        CFHTTPMessageAppendBytes(_receivedHTTPHeaders, (const UInt8 *)data.bytes, data.length);
+        
+        if (CFHTTPMessageIsHeaderComplete(_receivedHTTPHeaders)) {
+            SRFastLog(@"Finished reading headers %@", CFBridgingRelease(CFHTTPMessageCopyAllHeaderFields(_receivedHTTPHeaders)));
+            [self _HTTPHeadersDidFinish];
+        } else {
+            [self _readHTTPHeader];
+        }
+    }];
+}
+
+- (void)didConnect;
+{
+    SRFastLog(@"Connected");
+    CFHTTPMessageRef request = CFHTTPMessageCreateRequest(NULL, CFSTR("GET"), (__bridge CFURLRef)_url, kCFHTTPVersion1_1);
+    
+    // Set host first so it defaults
+    CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Host"), (__bridge CFStringRef)(_url.port ? [NSString stringWithFormat:@"%@:%@", _url.host, _url.port] : _url.host));
+        
+    NSMutableData *keyBytes = [[NSMutableData alloc] initWithLength:16];
+    SecRandomCopyBytes(kSecRandomDefault, keyBytes.length, keyBytes.mutableBytes);
+    
+    if ([keyBytes respondsToSelector:@selector(base64EncodedStringWithOptions:)]) {
+        _secKey = [keyBytes base64EncodedStringWithOptions:0];
+    } else {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+        _secKey = [keyBytes base64Encoding];
+#pragma clang diagnostic pop
+    }
+    
+    assert([_secKey length] == 24);
+
+    // Apply cookies if any have been provided
+    NSDictionary * cookies = [NSHTTPCookie requestHeaderFieldsWithCookies:[self requestCookies]];
+    for (NSString * cookieKey in cookies) {
+        NSString * cookieValue = [cookies objectForKey:cookieKey];
+        if ([cookieKey length] && [cookieValue length]) {
+            CFHTTPMessageSetHeaderFieldValue(request, (__bridge CFStringRef)cookieKey, (__bridge CFStringRef)cookieValue);
+        }
+    }
+ 
+    // set header for http basic auth
+    if (_url.user.length && _url.password.length) {
+        NSData *userAndPassword = [[NSString stringWithFormat:@"%@:%@", _url.user, _url.password] dataUsingEncoding:NSUTF8StringEncoding];
+        NSString *userAndPasswordBase64Encoded;
+        if ([keyBytes respondsToSelector:@selector(base64EncodedStringWithOptions:)]) {
+            userAndPasswordBase64Encoded = [userAndPassword base64EncodedStringWithOptions:0];
+        } else {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+            userAndPasswordBase64Encoded = [userAndPassword base64Encoding];
+#pragma clang diagnostic pop
+        }
+        _basicAuthorizationString = [NSString stringWithFormat:@"Basic %@", userAndPasswordBase64Encoded];
+        CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Authorization"), (__bridge CFStringRef)_basicAuthorizationString);
+    }
+
+    CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Upgrade"), CFSTR("websocket"));
+    CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Connection"), CFSTR("Upgrade"));
+    CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Key"), (__bridge CFStringRef)_secKey);
+    CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Version"), (__bridge CFStringRef)[NSString stringWithFormat:@"%ld", (long)_webSocketVersion]);
+    
+    CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Origin"), (__bridge CFStringRef)_url.SR_origin);
+    
+    if (_requestedProtocols) {
+        CFHTTPMessageSetHeaderFieldValue(request, CFSTR("Sec-WebSocket-Protocol"), (__bridge CFStringRef)[_requestedProtocols componentsJoinedByString:@", "]);
+    }
+
+    [_urlRequest.allHTTPHeaderFields enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
+        CFHTTPMessageSetHeaderFieldValue(request, (__bridge CFStringRef)key, (__bridge CFStringRef)obj);
+    }];
+    
+    NSData *message = CFBridgingRelease(CFHTTPMessageCopySerializedMessage(request));
+    
+    CFRelease(request);
+
+    [self _writeData:message];
+    [self _readHTTPHeader];
+}
+
+- (void)_initializeStreams;
+{
+    assert(_url.port.unsignedIntValue <= UINT32_MAX);
+    uint32_t port = _url.port.unsignedIntValue;
+    if (port == 0) {
+        if (!_secure) {
+            port = 80;
+        } else {
+            port = 443;
+        }
+    }
+    NSString *host = _url.host;
+    
+    CFReadStreamRef readStream = NULL;
+    CFWriteStreamRef writeStream = NULL;
+    
+    CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)host, port, &readStream, &writeStream);
+    
+    _outputStream = CFBridgingRelease(writeStream);
+    _inputStream = CFBridgingRelease(readStream);
+    
+    _inputStream.delegate = self;
+    _outputStream.delegate = self;
+}
+
+- (void)_updateSecureStreamOptions;
+{
+    if (_secure) {
+        NSMutableDictionary *SSLOptions = [[NSMutableDictionary alloc] init];
+        
+        [_outputStream setProperty:(__bridge id)kCFStreamSocketSecurityLevelNegotiatedSSL forKey:(__bridge id)kCFStreamPropertySocketSecurityLevel];
+        
+        // If we're using pinned certs, don't validate the certificate chain
+        if ([_urlRequest SR_SSLPinnedCertificates].count) {
+            [SSLOptions setValue:@NO forKey:(__bridge id)kCFStreamSSLValidatesCertificateChain];
+        }
+        
+#if DEBUG
+        self.allowsUntrustedSSLCertificates = YES;
+#endif
+
+        if (self.allowsUntrustedSSLCertificates) {
+            [SSLOptions setValue:@NO forKey:(__bridge id)kCFStreamSSLValidatesCertificateChain];
+            SRFastLog(@"Allowing connection to any root cert");
+        }
+        
+        [_outputStream setProperty:SSLOptions
+                            forKey:(__bridge id)kCFStreamPropertySSLSettings];
+    }
+    
+    _inputStream.delegate = self;
+    _outputStream.delegate = self;
+    
+    [self setupNetworkServiceType:_urlRequest.networkServiceType];
+}
+
+- (void)setupNetworkServiceType:(NSURLRequestNetworkServiceType)requestNetworkServiceType
+{
+    NSString *networkServiceType;
+    switch (requestNetworkServiceType) {
+        case NSURLNetworkServiceTypeDefault:
+            break;
+        case NSURLNetworkServiceTypeVoIP: {
+            networkServiceType = NSStreamNetworkServiceTypeVoIP;
+#if TARGET_OS_IPHONE && __IPHONE_9_0
+            if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_8_3) {
+                static dispatch_once_t predicate;
+                dispatch_once(&predicate, ^{
+                    NSLog(@"SocketRocket: %@ - this service type is deprecated in favor of using PushKit for VoIP control", networkServiceType);
+                });
+            }
+#endif
+            break;
+        }
+        case NSURLNetworkServiceTypeVideo:
+            networkServiceType = NSStreamNetworkServiceTypeVideo;
+            break;
+        case NSURLNetworkServiceTypeBackground:
+            networkServiceType = NSStreamNetworkServiceTypeBackground;
+            break;
+        case NSURLNetworkServiceTypeVoice:
+            networkServiceType = NSStreamNetworkServiceTypeVoice;
+            break;
+    }
+    
+    if (networkServiceType != nil) {
+        [_inputStream setProperty:networkServiceType forKey:NSStreamNetworkServiceType];
+        [_outputStream setProperty:networkServiceType forKey:NSStreamNetworkServiceType];
+    }
+}
+
+- (void)openConnection;
+{
+    [self _updateSecureStreamOptions];
+    
+    if (!_scheduledRunloops.count) {
+        [self scheduleInRunLoop:[NSRunLoop SR_networkRunLoop] forMode:NSDefaultRunLoopMode];
+    }
+    
+    
+    [_outputStream open];
+    [_inputStream open];
+}
+
+- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode;
+{
+    [_outputStream scheduleInRunLoop:aRunLoop forMode:mode];
+    [_inputStream scheduleInRunLoop:aRunLoop forMode:mode];
+    
+    [_scheduledRunloops addObject:@[aRunLoop, mode]];
+}
+
+- (void)unscheduleFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode;
+{
+    [_outputStream removeFromRunLoop:aRunLoop forMode:mode];
+    [_inputStream removeFromRunLoop:aRunLoop forMode:mode];
+    
+    [_scheduledRunloops removeObject:@[aRunLoop, mode]];
+}
+
+- (void)close;
+{
+    [self closeWithCode:SRStatusCodeNormal reason:nil];
+}
+
+- (void)closeWithCode:(NSInteger)code reason:(NSString *)reason;
+{
+    assert(code);
+    dispatch_async(_workQueue, ^{
+        if (self.readyState == SR_CLOSING || self.readyState == SR_CLOSED) {
+            return;
+        }
+        
+        BOOL wasConnecting = self.readyState == SR_CONNECTING;
+        
+        self.readyState = SR_CLOSING;
+        
+        SRFastLog(@"Closing with code %d reason %@", code, reason);
+        
+        if (wasConnecting) {
+            [self closeConnection];
+            return;
+        }
+
+        size_t maxMsgSize = [reason maximumLengthOfBytesUsingEncoding:NSUTF8StringEncoding];
+        NSMutableData *mutablePayload = [[NSMutableData alloc] initWithLength:sizeof(uint16_t) + maxMsgSize];
+        NSData *payload = mutablePayload;
+        
+        ((uint16_t *)mutablePayload.mutableBytes)[0] = EndianU16_BtoN(code);
+        
+        if (reason) {
+            NSRange remainingRange = {0};
+            
+            NSUInteger usedLength = 0;
+            
+            BOOL success = [reason getBytes:(char *)mutablePayload.mutableBytes + sizeof(uint16_t) maxLength:payload.length - sizeof(uint16_t) usedLength:&usedLength encoding:NSUTF8StringEncoding options:NSStringEncodingConversionExternalRepresentation range:NSMakeRange(0, reason.length) remainingRange:&remainingRange];
+            #pragma unused (success)
+            
+            assert(success);
+            assert(remainingRange.length == 0);
+
+            if (usedLength != maxMsgSize) {
+                payload = [payload subdataWithRange:NSMakeRange(0, usedLength + sizeof(uint16_t))];
+            }
+        }
+        
+        
+        [self _sendFrameWithOpcode:SROpCodeConnectionClose data:payload];
+    });
+}
+
+- (void)_closeWithProtocolError:(NSString *)message;
+{
+    // Need to shunt this on the _callbackQueue first to see if they received any messages 
+    [self _performDelegateBlock:^{
+        [self closeWithCode:SRStatusCodeProtocolError reason:message];
+        dispatch_async(_workQueue, ^{
+            [self closeConnection];
+        });
+    }];
+}
+
+- (void)_failWithError:(NSError *)error;
+{
+    dispatch_async(_workQueue, ^{
+        if (self.readyState != SR_CLOSED) {
+            _failed = YES;
+            [self _performDelegateBlock:^{
+                if ([self.delegate respondsToSelector:@selector(webSocket:didFailWithError:)]) {
+                    [self.delegate webSocket:self didFailWithError:error];
+                }
+            }];
+
+            self.readyState = SR_CLOSED;
+
+            SRFastLog(@"Failing with error %@", error.localizedDescription);
+            
+            [self closeConnection];
+            [self _scheduleCleanup];
+        }
+    });
+}
+
+- (void)_writeData:(NSData *)data;
+{    
+    [self assertOnWorkQueue];
+
+    if (_closeWhenFinishedWriting) {
+            return;
+    }
+    [_outputBuffer appendData:data];
+    [self _pumpWriting];
+}
+
+- (void)send:(id)data;
+{
+    NSAssert(self.readyState != SR_CONNECTING, @"Invalid State: Cannot call send: until connection is open");
+    // TODO: maybe not copy this for performance
+    data = [data copy];
+    dispatch_async(_workQueue, ^{
+        if ([data isKindOfClass:[NSString class]]) {
+            [self _sendFrameWithOpcode:SROpCodeTextFrame data:[(NSString *)data dataUsingEncoding:NSUTF8StringEncoding]];
+        } else if ([data isKindOfClass:[NSData class]]) {
+            [self _sendFrameWithOpcode:SROpCodeBinaryFrame data:data];
+        } else if (data == nil) {
+            [self _sendFrameWithOpcode:SROpCodeTextFrame data:data];
+        } else {
+            assert(NO);
+        }
+    });
+}
+
+- (void)sendPing:(NSData *)data;
+{
+    NSAssert(self.readyState == SR_OPEN, @"Invalid State: Cannot call send: until connection is open");
+    // TODO: maybe not copy this for performance
+    data = [data copy] ?: [NSData data]; // It's okay for a ping to be empty
+    dispatch_async(_workQueue, ^{
+        [self _sendFrameWithOpcode:SROpCodePing data:data];
+    });
+}
+
+- (void)handlePing:(NSData *)pingData;
+{
+    // Need to pingpong this off _callbackQueue first to make sure messages happen in order
+    [self _performDelegateBlock:^{
+        dispatch_async(_workQueue, ^{
+            [self _sendFrameWithOpcode:SROpCodePong data:pingData];
+        });
+    }];
+}
+
+- (void)handlePong:(NSData *)pongData;
+{
+    SRFastLog(@"Received pong");
+    [self _performDelegateBlock:^{
+        if ([self.delegate respondsToSelector:@selector(webSocket:didReceivePong:)]) {
+            [self.delegate webSocket:self didReceivePong:pongData];
+        }
+    }];
+}
+
+- (void)_handleMessage:(id)message
+{
+    SRFastLog(@"Received message");
+    [self _performDelegateBlock:^{
+        [self.delegate webSocket:self didReceiveMessage:message];
+    }];
+}
+
+
+static inline BOOL closeCodeIsValid(int closeCode) {
+    if (closeCode < 1000) {
+        return NO;
+    }
+    
+    if (closeCode >= 1000 && closeCode <= 1011) {
+        if (closeCode == 1004 ||
+            closeCode == 1005 ||
+            closeCode == 1006) {
+            return NO;
+        }
+        return YES;
+    }
+    
+    if (closeCode >= 3000 && closeCode <= 3999) {
+        return YES;
+    }
+    
+    if (closeCode >= 4000 && closeCode <= 4999) {
+        return YES;
+    }
+
+    return NO;
+}
+
+//  Note from RFC:
+//
+//  If there is a body, the first two
+//  bytes of the body MUST be a 2-byte unsigned integer (in network byte
+//  order) representing a status code with value /code/ defined in
+//  Section 7.4.  Following the 2-byte integer the body MAY contain UTF-8
+//  encoded data with value /reason/, the interpretation of which is not
+//  defined by this specification.
+
+- (void)handleCloseWithData:(NSData *)data;
+{
+    size_t dataSize = data.length;
+    __block uint16_t closeCode = 0;
+    
+    SRFastLog(@"Received close frame");
+    
+    if (dataSize == 1) {
+        // TODO handle error
+        [self _closeWithProtocolError:@"Payload for close must be larger than 2 bytes"];
+        return;
+    } else if (dataSize >= 2) {
+        [data getBytes:&closeCode length:sizeof(closeCode)];
+        _closeCode = EndianU16_BtoN(closeCode);
+        if (!closeCodeIsValid(_closeCode)) {
+            [self _closeWithProtocolError:[NSString stringWithFormat:@"Cannot have close code of %d", _closeCode]];
+            return;
+        }
+        if (dataSize > 2) {
+            _closeReason = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(2, dataSize - 2)] encoding:NSUTF8StringEncoding];
+            if (!_closeReason) {
+                [self _closeWithProtocolError:@"Close reason MUST be valid UTF-8"];
+                return;
+            }
+        }
+    } else {
+        _closeCode = SRStatusNoStatusReceived;
+    }
+    
+    [self assertOnWorkQueue];
+    
+    if (self.readyState == SR_OPEN) {
+        [self closeWithCode:1000 reason:nil];
+    }
+    dispatch_async(_workQueue, ^{
+        [self closeConnection];
+    });
+}
+
+- (void)closeConnection;
+{
+    [self assertOnWorkQueue];
+    SRFastLog(@"Trying to disconnect");
+    _closeWhenFinishedWriting = YES;
+    [self _pumpWriting];
+}
+
+- (void)_handleFrameWithData:(NSData *)frameData opCode:(NSInteger)opcode;
+{                
+    // Check that the current data is valid UTF8
+    
+    BOOL isControlFrame = (opcode == SROpCodePing || opcode == SROpCodePong || opcode == SROpCodeConnectionClose);
+    if (!isControlFrame) {
+        [self _readFrameNew];
+    } else {
+        dispatch_async(_workQueue, ^{
+            [self _readFrameContinue];
+        });
+    }
+    
+    //frameData will be copied before passing to handlers
+    //otherwise there can be misbehaviours when value at the pointer is changed
+    switch (opcode) {
+        case SROpCodeTextFrame: {
+            if ([self.delegate respondsToSelector:@selector(webSocketShouldConvertTextFrameToString:)] && ![self.delegate webSocketShouldConvertTextFrameToString:self]) {
+                [self _handleMessage:[frameData copy]];
+            } else {
+                NSString *str = [[NSString alloc] initWithData:frameData encoding:NSUTF8StringEncoding];
+                if (str == nil && frameData) {
+                    [self closeWithCode:SRStatusCodeInvalidUTF8 reason:@"Text frames must be valid UTF-8"];
+                    dispatch_async(_workQueue, ^{
+                        [self closeConnection];
+                    });
+                    return;
+                }
+                [self _handleMessage:str];
+            }
+            break;
+        }
+        case SROpCodeBinaryFrame:
+            [self _handleMessage:[frameData copy]];
+            break;
+        case SROpCodeConnectionClose:
+            [self handleCloseWithData:[frameData copy]];
+            break;
+        case SROpCodePing:
+            [self handlePing:[frameData copy]];
+            break;
+        case SROpCodePong:
+            [self handlePong:[frameData copy]];
+            break;
+        default:
+            [self _closeWithProtocolError:[NSString stringWithFormat:@"Unknown opcode %ld", (long)opcode]];
+            // TODO: Handle invalid opcode
+            break;
+    }
+}
+
+- (void)_handleFrameHeader:(frame_header)frame_header curData:(NSData *)curData;
+{
+    assert(frame_header.opcode != 0);
+    
+    if (self.readyState == SR_CLOSED) {
+        return;
+    }
+    
+    
+    BOOL isControlFrame = (frame_header.opcode == SROpCodePing || frame_header.opcode == SROpCodePong || frame_header.opcode == SROpCodeConnectionClose);
+    
+    if (isControlFrame && !frame_header.fin) {
+        [self _closeWithProtocolError:@"Fragmented control frames not allowed"];
+        return;
+    }
+    
+    if (isControlFrame && frame_header.payload_length >= 126) {
+        [self _closeWithProtocolError:@"Control frames cannot have payloads larger than 126 bytes"];
+        return;
+    }
+    
+    if (!isControlFrame) {
+        _currentFrameOpcode = frame_header.opcode;
+        _currentFrameCount += 1;
+    }
+    
+    if (frame_header.payload_length == 0) {
+        if (isControlFrame) {
+            [self _handleFrameWithData:curData opCode:frame_header.opcode];
+        } else {
+            if (frame_header.fin) {
+                [self _handleFrameWithData:_currentFrameData opCode:frame_header.opcode];
+            } else {
+                // TODO add assert that opcode is not a control;
+                [self _readFrameContinue];
+            }
+        }
+    } else {
+        assert(frame_header.payload_length <= SIZE_T_MAX);
+        [self _addConsumerWithDataLength:(size_t)frame_header.payload_length callback:^(SRWebSocket *self, NSData *newData) {
+            if (isControlFrame) {
+                [self _handleFrameWithData:newData opCode:frame_header.opcode];
+            } else {
+                if (frame_header.fin) {
+                    [self _handleFrameWithData:self->_currentFrameData opCode:frame_header.opcode];
+                } else {
+                    // TODO add assert that opcode is not a control;
+                    [self _readFrameContinue];
+                }
+                
+            }
+        } readToCurrentFrame:!isControlFrame unmaskBytes:frame_header.masked];
+    }
+}
+
+/* From RFC:
+
+ 0                   1                   2                   3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-------+-+-------------+-------------------------------+
+ |F|R|R|R| opcode|M| Payload len |    Extended payload length    |
+ |I|S|S|S|  (4)  |A|     (7)     |             (16/64)           |
+ |N|V|V|V|       |S|             |   (if payload len==126/127)   |
+ | |1|2|3|       |K|             |                               |
+ +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
+ |     Extended payload length continued, if payload len == 127  |
+ + - - - - - - - - - - - - - - - +-------------------------------+
+ |                               |Masking-key, if MASK set to 1  |
+ +-------------------------------+-------------------------------+
+ | Masking-key (continued)       |          Payload Data         |
+ +-------------------------------- - - - - - - - - - - - - - - - +
+ :                     Payload Data continued ...                :
+ + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
+ |                     Payload Data continued ...                |
+ +---------------------------------------------------------------+
+ */
+
+static const uint8_t SRFinMask          = 0x80;
+static const uint8_t SROpCodeMask       = 0x0F;
+static const uint8_t SRRsvMask          = 0x70;
+static const uint8_t SRMaskMask         = 0x80;
+static const uint8_t SRPayloadLenMask   = 0x7F;
+
+
+- (void)_readFrameContinue;
+{
+    assert((_currentFrameCount == 0 && _currentFrameOpcode == 0) || (_currentFrameCount > 0 && _currentFrameOpcode > 0));
+
+    [self _addConsumerWithDataLength:2 callback:^(SRWebSocket *self, NSData *data) {
+        __block frame_header header = {0};
+        
+        const uint8_t *headerBuffer = data.bytes;
+        assert(data.length >= 2);
+        
+        if (headerBuffer[0] & SRRsvMask) {
+            [self _closeWithProtocolError:@"Server used RSV bits"];
+            return;
+        }
+        
+        uint8_t receivedOpcode = (SROpCodeMask & headerBuffer[0]);
+        
+        BOOL isControlFrame = (receivedOpcode == SROpCodePing || receivedOpcode == SROpCodePong || receivedOpcode == SROpCodeConnectionClose);
+        
+        if (!isControlFrame && receivedOpcode != 0 && self->_currentFrameCount > 0) {
+            [self _closeWithProtocolError:@"all data frames after the initial data frame must have opcode 0"];
+            return;
+        }
+        
+        if (receivedOpcode == 0 && self->_currentFrameCount == 0) {
+            [self _closeWithProtocolError:@"cannot continue a message"];
+            return;
+        }
+        
+        header.opcode = receivedOpcode == 0 ? self->_currentFrameOpcode : receivedOpcode;
+        
+        header.fin = !!(SRFinMask & headerBuffer[0]);
+        
+        
+        header.masked = !!(SRMaskMask & headerBuffer[1]);
+        header.payload_length = SRPayloadLenMask & headerBuffer[1];
+        
+        headerBuffer = NULL;
+        
+        if (header.masked) {
+            [self _closeWithProtocolError:@"Client must receive unmasked data"];
+        }
+        
+        size_t extra_bytes_needed = header.masked ? sizeof(_currentReadMaskKey) : 0;
+        
+        if (header.payload_length == 126) {
+            extra_bytes_needed += sizeof(uint16_t);
+        } else if (header.payload_length == 127) {
+            extra_bytes_needed += sizeof(uint64_t);
+        }
+        
+        if (extra_bytes_needed == 0) {
+            [self _handleFrameHeader:header curData:self->_currentFrameData];
+        } else {
+            [self _addConsumerWithDataLength:extra_bytes_needed callback:^(SRWebSocket *self, NSData *data) {
+                size_t mapped_size = data.length;
+                #pragma unused (mapped_size)
+                const void *mapped_buffer = data.bytes;
+                size_t offset = 0;
+                
+                if (header.payload_length == 126) {
+                    assert(mapped_size >= sizeof(uint16_t));
+                    uint16_t newLen = EndianU16_BtoN(*(uint16_t *)(mapped_buffer));
+                    header.payload_length = newLen;
+                    offset += sizeof(uint16_t);
+                } else if (header.payload_length == 127) {
+                    assert(mapped_size >= sizeof(uint64_t));
+                    header.payload_length = EndianU64_BtoN(*(uint64_t *)(mapped_buffer));
+                    offset += sizeof(uint64_t);
+                } else {
+                    assert(header.payload_length < 126 && header.payload_length >= 0);
+                }
+                
+                if (header.masked) {
+                    assert(mapped_size >= sizeof(_currentReadMaskOffset) + offset);
+                    memcpy(self->_currentReadMaskKey, ((uint8_t *)mapped_buffer) + offset, sizeof(self->_currentReadMaskKey));
+                }
+                
+                [self _handleFrameHeader:header curData:self->_currentFrameData];
+            } readToCurrentFrame:NO unmaskBytes:NO];
+        }
+    } readToCurrentFrame:NO unmaskBytes:NO];
+}
+
+- (void)_readFrameNew;
+{
+    dispatch_async(_workQueue, ^{
+        [_currentFrameData setLength:0];
+        
+        _currentFrameOpcode = 0;
+        _currentFrameCount = 0;
+        _readOpCount = 0;
+        _currentStringScanPosition = 0;
+        
+        [self _readFrameContinue];
+    });
+}
+
+- (void)_pumpWriting;
+{
+    [self assertOnWorkQueue];
+    
+    NSUInteger dataLength = _outputBuffer.length;
+    if (dataLength - _outputBufferOffset > 0 && _outputStream.hasSpaceAvailable) {
+        NSInteger bytesWritten = [_outputStream write:_outputBuffer.bytes + _outputBufferOffset maxLength:dataLength - _outputBufferOffset];
+        if (bytesWritten == -1) {
+            [self _failWithError:[NSError errorWithDomain:SRWebSocketErrorDomain code:2145 userInfo:[NSDictionary dictionaryWithObject:@"Error writing to stream" forKey:NSLocalizedDescriptionKey]]];
+             return;
+        }
+        
+        _outputBufferOffset += bytesWritten;
+        
+        if (_outputBufferOffset > 4096 && _outputBufferOffset > (_outputBuffer.length >> 1)) {
+            _outputBuffer = [[NSMutableData alloc] initWithBytes:(char *)_outputBuffer.bytes + _outputBufferOffset length:_outputBuffer.length - _outputBufferOffset];
+            _outputBufferOffset = 0;
+        }
+    }
+    
+    if (_closeWhenFinishedWriting && 
+        _outputBuffer.length - _outputBufferOffset == 0 && 
+        (_inputStream.streamStatus != NSStreamStatusNotOpen &&
+         _inputStream.streamStatus != NSStreamStatusClosed) &&
+        !_sentClose) {
+        _sentClose = YES;
+        
+        @synchronized(self) {
+            [_outputStream close];
+            [_inputStream close];
+            
+            
+            for (NSArray *runLoop in [_scheduledRunloops copy]) {
+                [self unscheduleFromRunLoop:[runLoop objectAtIndex:0] forMode:[runLoop objectAtIndex:1]];
+            }
+        }
+        
+        if (!_failed) {
+            [self _performDelegateBlock:^{
+                if ([self.delegate respondsToSelector:@selector(webSocket:didCloseWithCode:reason:wasClean:)]) {
+                    [self.delegate webSocket:self didCloseWithCode:_closeCode reason:_closeReason wasClean:YES];
+                }
+            }];
+        }
+        
+        [self _scheduleCleanup];
+    }
+}
+
+- (void)_addConsumerWithScanner:(stream_scanner)consumer callback:(data_callback)callback;
+{
+    [self assertOnWorkQueue];
+    [self _addConsumerWithScanner:consumer callback:callback dataLength:0];
+}
+
+- (void)_addConsumerWithDataLength:(size_t)dataLength callback:(data_callback)callback readToCurrentFrame:(BOOL)readToCurrentFrame unmaskBytes:(BOOL)unmaskBytes;
+{   
+    [self assertOnWorkQueue];
+    assert(dataLength);
+    
+    [_consumers addObject:[_consumerPool consumerWithScanner:nil handler:callback bytesNeeded:dataLength readToCurrentFrame:readToCurrentFrame unmaskBytes:unmaskBytes]];
+    [self _pumpScanner];
+}
+
+- (void)_addConsumerWithScanner:(stream_scanner)consumer callback:(data_callback)callback dataLength:(size_t)dataLength;
+{    
+    [self assertOnWorkQueue];
+    [_consumers addObject:[_consumerPool consumerWithScanner:consumer handler:callback bytesNeeded:dataLength readToCurrentFrame:NO unmaskBytes:NO]];
+    [self _pumpScanner];
+}
+
+
+- (void)_scheduleCleanup
+{
+    @synchronized(self) {
+        if (_cleanupScheduled) {
+            return;
+        }
+        
+        _cleanupScheduled = YES;
+        
+        // Cleanup NSStream delegate's in the same RunLoop used by the streams themselves:
+        // This way we'll prevent race conditions between handleEvent and SRWebsocket's dealloc
+        NSTimer *timer = [NSTimer timerWithTimeInterval:(0.0f) target:self selector:@selector(_cleanupSelfReference:) userInfo:nil repeats:NO];
+        [[NSRunLoop SR_networkRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
+    }
+}
+
+- (void)_cleanupSelfReference:(NSTimer *)timer
+{
+    @synchronized(self) {
+        // Nuke NSStream delegate's
+        _inputStream.delegate = nil;
+        _outputStream.delegate = nil;
+        
+        // Remove the streams, right now, from the networkRunLoop
+        [_inputStream close];
+        [_outputStream close];
+    }
+    
+    // Cleanup selfRetain in the same GCD queue as usual
+    dispatch_async(_workQueue, ^{
+        _selfRetain = nil;
+    });
+}
+
+
+static const char CRLFCRLFBytes[] = {'\r', '\n', '\r', '\n'};
+
+- (void)_readUntilHeaderCompleteWithCallback:(data_callback)dataHandler;
+{
+    [self _readUntilBytes:CRLFCRLFBytes length:sizeof(CRLFCRLFBytes) callback:dataHandler];
+}
+
+- (void)_readUntilBytes:(const void *)bytes length:(size_t)length callback:(data_callback)dataHandler;
+{
+    // TODO optimize so this can continue from where we last searched
+    stream_scanner consumer = ^size_t(NSData *data) {
+        __block size_t found_size = 0;
+        __block size_t match_count = 0;
+        
+        size_t size = data.length;
+        const unsigned char *buffer = data.bytes;
+        for (size_t i = 0; i < size; i++ ) {
+            if (((const unsigned char *)buffer)[i] == ((const unsigned char *)bytes)[match_count]) {
+                match_count += 1;
+                if (match_count == length) {
+                    found_size = i + 1;
+                    break;
+                }
+            } else {
+                match_count = 0;
+            }
+        }
+        return found_size;
+    };
+    [self _addConsumerWithScanner:consumer callback:dataHandler];
+}
+
+
+// Returns true if did work
+- (BOOL)_innerPumpScanner {
+    
+    BOOL didWork = NO;
+    
+    if (self.readyState >= SR_CLOSED) {
+        return didWork;
+    }
+    
+    if (!_consumers.count) {
+        return didWork;
+    }
+    
+    size_t curSize = _readBuffer.length - _readBufferOffset;
+    if (!curSize) {
+        return didWork;
+    }
+    
+    SRIOConsumer *consumer = [_consumers objectAtIndex:0];
+    
+    size_t bytesNeeded = consumer.bytesNeeded;
+    
+    size_t foundSize = 0;
+    if (consumer.consumer) {
+        NSData *tempView = [NSData dataWithBytesNoCopy:(char *)_readBuffer.bytes + _readBufferOffset length:_readBuffer.length - _readBufferOffset freeWhenDone:NO];  
+        foundSize = consumer.consumer(tempView);
+    } else {
+        assert(consumer.bytesNeeded);
+        if (curSize >= bytesNeeded) {
+            foundSize = bytesNeeded;
+        } else if (consumer.readToCurrentFrame) {
+            foundSize = curSize;
+        }
+    }
+    
+    NSData *slice = nil;
+    if (consumer.readToCurrentFrame || foundSize) {
+        NSRange sliceRange = NSMakeRange(_readBufferOffset, foundSize);
+        slice = [_readBuffer subdataWithRange:sliceRange];
+        
+        _readBufferOffset += foundSize;
+        
+        if (_readBufferOffset > 4096 && _readBufferOffset > (_readBuffer.length >> 1)) {
+            _readBuffer = [[NSMutableData alloc] initWithBytes:(char *)_readBuffer.bytes + _readBufferOffset length:_readBuffer.length - _readBufferOffset];            _readBufferOffset = 0;
+        }
+        
+        if (consumer.unmaskBytes) {
+            NSMutableData *mutableSlice = [slice mutableCopy];
+            
+            NSUInteger len = mutableSlice.length;
+            uint8_t *bytes = mutableSlice.mutableBytes;
+            
+            for (NSUInteger i = 0; i < len; i++) {
+                bytes[i] = bytes[i] ^ _currentReadMaskKey[_currentReadMaskOffset % sizeof(_currentReadMaskKey)];
+                _currentReadMaskOffset += 1;
+            }
+            
+            slice = mutableSlice;
+        }
+        
+        if (consumer.readToCurrentFrame) {
+            [_currentFrameData appendData:slice];
+            
+            _readOpCount += 1;
+            
+            if (_currentFrameOpcode == SROpCodeTextFrame) {
+                // Validate UTF8 stuff.
+                size_t currentDataSize = _currentFrameData.length;
+                if (_currentFrameOpcode == SROpCodeTextFrame && currentDataSize > 0) {
+                    // TODO: Optimize the crap out of this.  Don't really have to copy all the data each time
+                    
+                    size_t scanSize = currentDataSize - _currentStringScanPosition;
+                    
+                    NSData *scan_data = [_currentFrameData subdataWithRange:NSMakeRange(_currentStringScanPosition, scanSize)];
+                    int32_t valid_utf8_size = validate_dispatch_data_partial_string(scan_data);
+                    
+                    if (valid_utf8_size == -1) {
+                        [self closeWithCode:SRStatusCodeInvalidUTF8 reason:@"Text frames must be valid UTF-8"];
+                        dispatch_async(_workQueue, ^{
+                            [self closeConnection];
+                        });
+                        return didWork;
+                    } else {
+                        _currentStringScanPosition += valid_utf8_size;
+                    }
+                } 
+                
+            }
+            
+            consumer.bytesNeeded -= foundSize;
+            
+            if (consumer.bytesNeeded == 0) {
+                [_consumers removeObjectAtIndex:0];
+                consumer.handler(self, nil);
+                [_consumerPool returnConsumer:consumer];
+                didWork = YES;
+            }
+        } else if (foundSize) {
+            [_consumers removeObjectAtIndex:0];
+            consumer.handler(self, slice);
+            [_consumerPool returnConsumer:consumer];
+            didWork = YES;
+        }
+    }
+    return didWork;
+}
+
+-(void)_pumpScanner;
+{
+    [self assertOnWorkQueue];
+    
+    if (!_isPumping) {
+        _isPumping = YES;
+    } else {
+        return;
+    }
+    
+    while ([self _innerPumpScanner]) {
+        
+    }
+    
+    _isPumping = NO;
+}
+
+//#define NOMASK
+
+static const size_t SRFrameHeaderOverhead = 32;
+
+- (void)_sendFrameWithOpcode:(SROpCode)opcode data:(id)data;
+{
+    [self assertOnWorkQueue];
+    
+    if (nil == data) {
+        return;
+    }
+    
+    NSAssert([data isKindOfClass:[NSData class]] || [data isKindOfClass:[NSString class]], @"NSString or NSData");
+    
+    size_t payloadLength = [data isKindOfClass:[NSString class]] ? [(NSString *)data lengthOfBytesUsingEncoding:NSUTF8StringEncoding] : [data length];
+        
+    NSMutableData *frame = [[NSMutableData alloc] initWithLength:payloadLength + SRFrameHeaderOverhead];
+    if (!frame) {
+        [self closeWithCode:SRStatusCodeMessageTooBig reason:@"Message too big"];
+        return;
+    }
+    uint8_t *frame_buffer = (uint8_t *)[frame mutableBytes];
+    
+    // set fin
+    frame_buffer[0] = SRFinMask | opcode;
+    
+    BOOL useMask = YES;
+#ifdef NOMASK
+    useMask = NO;
+#endif
+    
+    if (useMask) {
+    // set the mask and header
+        frame_buffer[1] |= SRMaskMask;
+    }
+    
+    size_t frame_buffer_size = 2;
+    
+    const uint8_t *unmasked_payload = NULL;
+    if ([data isKindOfClass:[NSData class]]) {
+        unmasked_payload = (uint8_t *)[data bytes];
+    } else if ([data isKindOfClass:[NSString class]]) {
+        unmasked_payload =  (const uint8_t *)[data UTF8String];
+    } else {
+        return;
+    }
+    
+    if (payloadLength < 126) {
+        frame_buffer[1] |= payloadLength;
+    } else if (payloadLength <= UINT16_MAX) {
+        frame_buffer[1] |= 126;
+        *((uint16_t *)(frame_buffer + frame_buffer_size)) = EndianU16_BtoN((uint16_t)payloadLength);
+        frame_buffer_size += sizeof(uint16_t);
+    } else {
+        frame_buffer[1] |= 127;
+        *((uint64_t *)(frame_buffer + frame_buffer_size)) = EndianU64_BtoN((uint64_t)payloadLength);
+        frame_buffer_size += sizeof(uint64_t);
+    }
+        
+    if (!useMask) {
+        for (size_t i = 0; i < payloadLength; i++) {
+            frame_buffer[frame_buffer_size] = unmasked_payload[i];
+            frame_buffer_size += 1;
+        }
+    } else {
+        uint8_t *mask_key = frame_buffer + frame_buffer_size;
+        SecRandomCopyBytes(kSecRandomDefault, sizeof(uint32_t), (uint8_t *)mask_key);
+        frame_buffer_size += sizeof(uint32_t);
+        
+        // TODO: could probably optimize this with SIMD
+        for (size_t i = 0; i < payloadLength; i++) {
+            frame_buffer[frame_buffer_size] = unmasked_payload[i] ^ mask_key[i % sizeof(uint32_t)];
+            frame_buffer_size += 1;
+        }
+    }
+
+    assert(frame_buffer_size <= [frame length]);
+    frame.length = frame_buffer_size;
+    
+    [self _writeData:frame];
+}
+
+- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode;
+{
+    __weak typeof(self) weakSelf = self;
+    
+    if (_secure && !_pinnedCertFound && (eventCode == NSStreamEventHasBytesAvailable || eventCode == NSStreamEventHasSpaceAvailable)) {
+        
+        NSArray *sslCerts = [_urlRequest SR_SSLPinnedCertificates];
+        if (sslCerts) {
+            SecTrustRef secTrust = (__bridge SecTrustRef)[aStream propertyForKey:(__bridge id)kCFStreamPropertySSLPeerTrust];
+            if (secTrust) {
+                NSInteger numCerts = SecTrustGetCertificateCount(secTrust);
+                for (NSInteger i = 0; i < numCerts && !_pinnedCertFound; i++) {
+                    SecCertificateRef cert = SecTrustGetCertificateAtIndex(secTrust, i);
+                    NSData *certData = CFBridgingRelease(SecCertificateCopyData(cert));
+                    
+                    for (id ref in sslCerts) {
+                        SecCertificateRef trustedCert = (__bridge SecCertificateRef)ref;
+                        NSData *trustedCertData = CFBridgingRelease(SecCertificateCopyData(trustedCert));
+                        
+                        if ([trustedCertData isEqualToData:certData]) {
+                            _pinnedCertFound = YES;
+                            break;
+                        }
+                    }
+                }
+            }
+            
+            if (!_pinnedCertFound) {
+                dispatch_async(_workQueue, ^{
+                    NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : @"Invalid server cert" };
+                    [weakSelf _failWithError:[NSError errorWithDomain:@"org.lolrus.SocketRocket" code:23556 userInfo:userInfo]];
+                });
+                return;
+            } else if (aStream == _outputStream) {
+                dispatch_async(_workQueue, ^{
+                    [self didConnect];
+                });
+            }
+        }
+    }
+
+    dispatch_async(_workQueue, ^{
+        [weakSelf safeHandleEvent:eventCode stream:aStream];
+    });
+}
+
+- (void)safeHandleEvent:(NSStreamEvent)eventCode stream:(NSStream *)aStream
+{
+        switch (eventCode) {
+            case NSStreamEventOpenCompleted: {
+                SRFastLog(@"NSStreamEventOpenCompleted %@", aStream);
+                if (self.readyState >= SR_CLOSING) {
+                    return;
+                }
+                assert(_readBuffer);
+                
+                // didConnect fires after certificate verification if we're using pinned certificates.
+                BOOL usingPinnedCerts = [[_urlRequest SR_SSLPinnedCertificates] count] > 0;
+                if ((!_secure || !usingPinnedCerts) && self.readyState == SR_CONNECTING && aStream == _inputStream) {
+                    [self didConnect];
+                }
+                [self _pumpWriting];
+                [self _pumpScanner];
+                break;
+            }
+                
+            case NSStreamEventErrorOccurred: {
+                SRFastLog(@"NSStreamEventErrorOccurred %@ %@", aStream, [[aStream streamError] copy]);
+                /// TODO specify error better!
+                [self _failWithError:aStream.streamError];
+                _readBufferOffset = 0;
+                [_readBuffer setLength:0];
+                break;
+                
+            }
+                
+            case NSStreamEventEndEncountered: {
+                [self _pumpScanner];
+                SRFastLog(@"NSStreamEventEndEncountered %@", aStream);
+                if (aStream.streamError) {
+                    [self _failWithError:aStream.streamError];
+                } else {
+                    dispatch_async(_workQueue, ^{
+                        if (self.readyState != SR_CLOSED) {
+                            self.readyState = SR_CLOSED;
+                            [self _scheduleCleanup];
+                        }
+                        
+                        if (!_sentClose && !_failed) {
+                            _sentClose = YES;
+                            // If we get closed in this state it's probably not clean because we should be sending this when we send messages
+                            [self _performDelegateBlock:^{
+                                if ([self.delegate respondsToSelector:@selector(webSocket:didCloseWithCode:reason:wasClean:)]) {
+                                    [self.delegate webSocket:self didCloseWithCode:SRStatusCodeGoingAway reason:@"Stream end encountered" wasClean:NO];
+                                }
+                            }];
+                        }
+                    });
+                }
+                
+                break;
+            }
+                
+            case NSStreamEventHasBytesAvailable: {
+                SRFastLog(@"NSStreamEventHasBytesAvailable %@", aStream);
+                const int bufferSize = 2048;
+                uint8_t buffer[bufferSize];
+                
+                while (_inputStream.hasBytesAvailable) {
+                    NSInteger bytes_read = [_inputStream read:buffer maxLength:bufferSize];
+                    
+                    if (bytes_read > 0) {
+                        [_readBuffer appendBytes:buffer length:bytes_read];
+                    } else if (bytes_read < 0) {
+                        [self _failWithError:_inputStream.streamError];
+                    }
+                    
+                    if (bytes_read != bufferSize) {
+                        break;
+                    }
+                };
+                [self _pumpScanner];
+                break;
+            }
+                
+            case NSStreamEventHasSpaceAvailable: {
+                SRFastLog(@"NSStreamEventHasSpaceAvailable %@", aStream);
+                [self _pumpWriting];
+                break;
+            }
+                
+            default:
+                SRFastLog(@"(default)  %@", aStream);
+                break;
+        }
+}
+
+@end
+
+
+@implementation SRIOConsumer
+
+@synthesize bytesNeeded = _bytesNeeded;
+@synthesize consumer = _scanner;
+@synthesize handler = _handler;
+@synthesize readToCurrentFrame = _readToCurrentFrame;
+@synthesize unmaskBytes = _unmaskBytes;
+
+- (void)setupWithScanner:(stream_scanner)scanner handler:(data_callback)handler bytesNeeded:(size_t)bytesNeeded readToCurrentFrame:(BOOL)readToCurrentFrame unmaskBytes:(BOOL)unmaskBytes;
+{
+    _scanner = [scanner copy];
+    _handler = [handler copy];
+    _bytesNeeded = bytesNeeded;
+    _readToCurrentFrame = readToCurrentFrame;
+    _unmaskBytes = unmaskBytes;
+    assert(_scanner || _bytesNeeded);
+}
+
+
+@end
+
+
+@implementation SRIOConsumerPool {
+    NSUInteger _poolSize;
+    NSMutableArray *_bufferedConsumers;
+}
+
+- (id)initWithBufferCapacity:(NSUInteger)poolSize;
+{
+    self = [super init];
+    if (self) {
+        _poolSize = poolSize;
+        _bufferedConsumers = [[NSMutableArray alloc] initWithCapacity:poolSize];
+    }
+    return self;
+}
+
+- (id)init
+{
+    return [self initWithBufferCapacity:8];
+}
+
+- (SRIOConsumer *)consumerWithScanner:(stream_scanner)scanner handler:(data_callback)handler bytesNeeded:(size_t)bytesNeeded readToCurrentFrame:(BOOL)readToCurrentFrame unmaskBytes:(BOOL)unmaskBytes;
+{
+    SRIOConsumer *consumer = nil;
+    if (_bufferedConsumers.count) {
+        consumer = [_bufferedConsumers lastObject];
+        [_bufferedConsumers removeLastObject];
+    } else {
+        consumer = [[SRIOConsumer alloc] init];
+    }
+    
+    [consumer setupWithScanner:scanner handler:handler bytesNeeded:bytesNeeded readToCurrentFrame:readToCurrentFrame unmaskBytes:unmaskBytes];
+    
+    return consumer;
+}
+
+- (void)returnConsumer:(SRIOConsumer *)consumer;
+{
+    if (_bufferedConsumers.count < _poolSize) {
+        [_bufferedConsumers addObject:consumer];
+    }
+}
+
+@end
+
+
+@implementation  NSURLRequest (SRCertificateAdditions)
+
+- (NSArray *)SR_SSLPinnedCertificates;
+{
+    return [NSURLProtocol propertyForKey:@"SR_SSLPinnedCertificates" inRequest:self];
+}
+
+@end
+
+@implementation  NSMutableURLRequest (SRCertificateAdditions)
+
+- (NSArray *)SR_SSLPinnedCertificates;
+{
+    return [NSURLProtocol propertyForKey:@"SR_SSLPinnedCertificates" inRequest:self];
+}
+
+- (void)setSR_SSLPinnedCertificates:(NSArray *)SR_SSLPinnedCertificates;
+{
+    [NSURLProtocol setProperty:SR_SSLPinnedCertificates forKey:@"SR_SSLPinnedCertificates" inRequest:self];
+}
+
+@end
+
+@implementation NSURL (SRWebSocket)
+
+- (NSString *)SR_origin;
+{
+    NSString *scheme = [self.scheme lowercaseString];
+        
+    if ([scheme isEqualToString:@"wss"]) {
+        scheme = @"https";
+    } else if ([scheme isEqualToString:@"ws"]) {
+        scheme = @"http";
+    }
+    
+    BOOL portIsDefault = !self.port ||
+                         ([scheme isEqualToString:@"http"] && self.port.integerValue == 80) ||
+                         ([scheme isEqualToString:@"https"] && self.port.integerValue == 443);
+    
+    if (!portIsDefault) {
+        return [NSString stringWithFormat:@"%@://%@:%@", scheme, self.host, self.port];
+    } else {
+        return [NSString stringWithFormat:@"%@://%@", scheme, self.host];
+    }
+}
+
+@end
+
+//#define SR_ENABLE_LOG
+
+static inline void SRFastLog(NSString *format, ...)  {
+#ifdef SR_ENABLE_LOG
+    __block va_list arg_list;
+    va_start (arg_list, format);
+    
+    NSString *formattedString = [[NSString alloc] initWithFormat:format arguments:arg_list];
+    
+    va_end(arg_list);
+    
+    NSLog(@"[SR] %@", formattedString);
+#endif
+}
+
+
+#ifdef HAS_ICU
+
+static inline int32_t validate_dispatch_data_partial_string(NSData *data) {
+    if ([data length] > INT32_MAX) {
+        // INT32_MAX is the limit so long as this Framework is using 32 bit ints everywhere.
+        return -1;
+    }
+
+    int32_t size = (int32_t)[data length];
+
+    const void * contents = [data bytes];
+    const uint8_t *str = (const uint8_t *)contents;
+    
+    UChar32 codepoint = 1;
+    int32_t offset = 0;
+    int32_t lastOffset = 0;
+    while(offset < size && codepoint > 0)  {
+        lastOffset = offset;
+        U8_NEXT(str, offset, size, codepoint);
+    }
+    
+    if (codepoint == -1) {
+        // Check to see if the last byte is valid or whether it was just continuing
+        if (!U8_IS_LEAD(str[lastOffset]) || U8_COUNT_TRAIL_BYTES(str[lastOffset]) + lastOffset < (int32_t)size) {
+            
+            size = -1;
+        } else {
+            uint8_t leadByte = str[lastOffset];
+            U8_MASK_LEAD_BYTE(leadByte, U8_COUNT_TRAIL_BYTES(leadByte));
+            
+            for (int i = lastOffset + 1; i < offset; i++) {
+                if (U8_IS_SINGLE(str[i]) || U8_IS_LEAD(str[i]) || !U8_IS_TRAIL(str[i])) {
+                    size = -1;
+                }
+            }
+            
+            if (size != -1) {
+                size = lastOffset;
+            }
+        }
+    }
+    
+    if (size != -1 && ![[NSString alloc] initWithBytesNoCopy:(char *)[data bytes] length:size encoding:NSUTF8StringEncoding freeWhenDone:NO]) {
+        size = -1;
+    }
+    
+    return size;
+}
+
+#else
+
+// This is a hack, and probably not optimal
+static inline int32_t validate_dispatch_data_partial_string(NSData *data) {
+    static const int maxCodepointSize = 3;
+    
+    for (int i = 0; i < maxCodepointSize; i++) {
+        NSString *str = [[NSString alloc] initWithBytesNoCopy:(char *)data.bytes length:data.length - i encoding:NSUTF8StringEncoding freeWhenDone:NO];
+        if (str) {
+            return (int32_t)data.length - i;
+        }
+    }
+    
+    return -1;
+}
+
+#endif
+
+static _SRRunLoopThread *networkThread = nil;
+static NSRunLoop *networkRunLoop = nil;
+
+@implementation NSRunLoop (SRWebSocket)
+
++ (NSRunLoop *)SR_networkRunLoop {
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        networkThread = [[_SRRunLoopThread alloc] init];
+        networkThread.name = @"com.squareup.SocketRocket.NetworkThread";
+        [networkThread start];
+        networkRunLoop = networkThread.runLoop;
+    });
+    
+    return networkRunLoop;
+}
+
+@end
+
+
+@implementation _SRRunLoopThread {
+    dispatch_group_t _waitGroup;
+}
+
+@synthesize runLoop = _runLoop;
+
+- (void)dealloc
+{
+    sr_dispatch_release(_waitGroup);
+}
+
+- (id)init
+{
+    self = [super init];
+    if (self) {
+        _waitGroup = dispatch_group_create();
+        dispatch_group_enter(_waitGroup);
+    }
+    return self;
+}
+
+- (void)main;
+{
+    @autoreleasepool {
+        _runLoop = [NSRunLoop currentRunLoop];
+        dispatch_group_leave(_waitGroup);
+        
+        // Add an empty run loop source to prevent runloop from spinning.
+        CFRunLoopSourceContext sourceCtx = {
+            .version = 0,
+            .info = NULL,
+            .retain = NULL,
+            .release = NULL,
+            .copyDescription = NULL,
+            .equal = NULL,
+            .hash = NULL,
+            .schedule = NULL,
+            .cancel = NULL,
+            .perform = NULL
+        };
+        CFRunLoopSourceRef source = CFRunLoopSourceCreate(NULL, 0, &sourceCtx);
+        CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
+        CFRelease(source);
+        
+        while ([_runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]) {
+            
+        }
+        assert(NO);
+    }
+}
+
+- (NSRunLoop *)runLoop;
+{
+    dispatch_group_wait(_waitGroup, DISPATCH_TIME_FOREVER);
+    return _runLoop;
+}
+
+@end

+ 23 - 0
SDK/ThirdClass/socket/SocketRocketUtility.h

@@ -0,0 +1,23 @@
+//
+//  SocketRocketUtility.h
+
+//
+
+#import <Foundation/Foundation.h>
+#import "SRWebSocket.h"
+
+@interface SocketRocketUtility : NSObject
+
+/** 连接状态 */
+@property (nonatomic,assign) SRReadyState socketReadyState;
+@property (nonatomic,  copy) void (^didReceiveMessage)(id message);
+//+ (SocketRocketUtility *)instance;
+//单例->初始化蓝牙
++(instancetype)sharedInstance;
+
+-(void)SRWebSocketOpen;//开启连接
+-(void)SRWebSocketClose;//关闭连接
+- (void)sendData:(NSDictionary *)paramDic withRequestURI:(NSString*)requestURI;//发送数据
+- (void)registerNetworkNotifications;//监测网络状态
+
+@end

+ 301 - 0
SDK/ThirdClass/socket/SocketRocketUtility.m

@@ -0,0 +1,301 @@
+//
+//  SocketRocketUtility.m
+//  SUN
+//
+//  Created by 孙俊 on 17/2/16.
+//  Copyright © 2017年 SUN. All rights reserved.
+//
+
+#import "SocketRocketUtility.h"
+
+#define dispatch_main_async_safe(block)\
+if ([NSThread isMainThread]) {\
+block();\
+} else {\
+dispatch_async(dispatch_get_main_queue(), block);\
+}
+
+#define WeakSelf(type)  __weak typeof(type) weak##type = type;
+///*自定义打印 宏*/
+//#ifdef DEBUG
+//#define NSLog(format, ...) do {                                                                          \
+//fprintf(stderr, "<%s : %d> %s\n",                                           \
+//[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String],  \
+//__LINE__, __func__);                                                        \
+//(NSLog)((format), ##__VA_ARGS__);                                           \
+//fprintf(stderr, "-------\n");                                               \
+//} while (0)
+//
+//#else
+//#define NSLog( ...)
+//
+//#endif
+typedef NS_ENUM(NSUInteger, SocketDataType) {
+    distributeOrder,
+    cancelCall,
+    orderLost,
+    changeDeviceType,
+};
+@interface SocketRocketUtility()<SRWebSocketDelegate>
+{
+    NSTimer * heartBeat;
+    NSTimeInterval reConnectTime;
+    SocketDataType type;
+    NSString *host;
+}
+
+@property (nonatomic,strong) SRWebSocket *socket;
+
+@end
+
+@implementation SocketRocketUtility
+
+//单例静态
+static SocketRocketUtility* 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];
+    });
+    return instance;
+}
+
+//+(SocketRocketUtility *)instance{
+//    static SocketRocketUtility *Instance = nil;
+//    static dispatch_once_t predicate;
+//    dispatch_once(&predicate, ^{
+//        Instance = [[SocketRocketUtility alloc] init];
+//    });
+//    return Instance;
+//}
+
+- (void)registerNetworkNotifications{
+//    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkChangedNote:) name:AFNetworkingReachabilityDidChangeNotification object:nil];
+}
+- (void)networkChangedNote:(NSNotification *)note{
+    
+//    AFNetworkReachabilityStatus status = [note.userInfo[AFNetworkingReachabilityNotificationStatusItem] integerValue];
+//    switch (status) {
+//        case AFNetworkReachabilityStatusUnknown:
+//            NSLog(@"网络类型:未知网络");
+//            break;
+//        case AFNetworkReachabilityStatusNotReachable:
+//            NSLog(@"网络类型:断网");
+//            break;
+//        case AFNetworkReachabilityStatusReachableViaWWAN:
+//            NSLog(@"网络类型:数据流量");
+//            [self SRWebSocketOpen];
+//            break;
+//        case AFNetworkReachabilityStatusReachableViaWiFi:
+//            NSLog(@"网络类型:WIFI");
+//            [self SRWebSocketOpen];
+//            break;
+//    }
+    
+}
+
+-(void)SRWebSocketOpen{
+    
+    
+    //如果是同一个url return
+    if (self.socket) {
+        return;
+    }
+    if(self.socket.readyState == SR_OPEN){
+        return;
+    }
+
+    self.socket = [[SRWebSocket alloc] initWithURLRequest:
+                   [NSURLRequest requestWithURL:[NSURL URLWithString:@"ws://172.16.14.127/examples/websocket/chat"]]];//这里填写你服务器的地址
+    
+//    NSLog(@"请求的websocket地址:%@",self.socket.url.absoluteString);
+    self.socket.delegate = self;   //实现这个 SRWebSocketDelegate 协议
+    [self.socket open];     //open 就是直接连接了
+}
+
+-(void)SRWebSocketClose{
+    if (self.socket){
+        [self.socket close];
+        self.socket = nil;
+        //断开连接时销毁心跳
+        [self destoryHeartBeat];
+    }
+}
+
+#pragma mark - socket delegate
+- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
+    
+    //每次正常连接的时候清零重连时间
+    reConnectTime = 0;
+    
+    //开启心跳
+    [self initHeartBeat];
+    if (webSocket == self.socket) {
+        NSLog(@"************************** socket 连接成功************************** ");
+    }
+}
+
+- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
+
+    if (webSocket == self.socket) {
+        NSLog(@"************************** socket 连接失败************************** ");
+        _socket = nil;
+        //连接失败就重连
+        [self reConnect];
+    }
+}
+
+- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean {
+    
+    if (webSocket == self.socket) {
+        NSLog(@"************************** socket连接断开************************** ");
+        NSLog(@"被关闭连接,code:%ld,reason:%@,wasClean:%d",(long)code,reason,wasClean);
+            [self SRWebSocketClose];
+    }
+
+}
+
+/*该函数是接收服务器发送的pong消息,其中最后一个是接受pong消息的,
+ 在这里就要提一下心跳包,一般情况下建立长连接都会建立一个心跳包,
+ 用于每隔一段时间通知一次服务端,客户端还是在线,这个心跳包其实就是一个ping消息,
+ 我的理解就是建立一个定时器,每隔十秒或者十五秒向服务端发送一个ping消息,这个消息可是是空的
+ */
+
+-(void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload{
+    NSString *reply = [[NSString alloc] initWithData:pongPayload encoding:NSUTF8StringEncoding];
+    NSLog(@"reply===%@",reply);
+}
+#pragma mark - 收到的回调
+- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message  {
+    
+    if (webSocket == self.socket) {
+//        NSLog(@"************************** socket收到数据了************************** ");
+//        NSLog(@"message:%@",message);
+        if(!message){
+            return;
+        }
+        [self handleReceivedMessage:message];
+
+    }
+}
+- (void)handleReceivedMessage:(id)message{
+
+        if(self.didReceiveMessage){
+            self.didReceiveMessage(message);
+        }
+
+}
+
+//重连机制
+- (void)reConnect
+{
+    
+   [self SRWebSocketClose];
+    //超过一分钟就不再重连 所以只会重连5次 2^5 = 64
+    if (reConnectTime > 64*2) {
+        //您的网络状况不是很好,请检查网络后重试
+        return;
+    }
+   
+    
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(reConnectTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+        self.socket = nil;
+        [self SRWebSocketOpen];
+        NSLog(@"重连");
+    });
+    
+    //重连时间2的指数级增长
+    if (reConnectTime == 0) {
+        reConnectTime = 2;
+    }else{
+        reConnectTime *= 2;
+    }
+    
+}
+
+//初始化心跳
+- (void)initHeartBeat
+{
+    dispatch_main_async_safe(^{
+        [self destoryHeartBeat];
+       
+        heartBeat = [NSTimer timerWithTimeInterval:30 target:self selector:@selector(ping) userInfo:nil repeats:YES];
+        //和服务端约定好发送什么作为心跳标识,尽可能的减小心跳包大小
+        [[NSRunLoop currentRunLoop]addTimer:heartBeat forMode:NSRunLoopCommonModes];
+    })
+}
+
+
+//取消心跳
+- (void)destoryHeartBeat
+{
+    dispatch_main_async_safe(^{
+        if (heartBeat) {
+            if ([heartBeat respondsToSelector:@selector(isValid)]){
+                if ([heartBeat isValid]){
+                    [heartBeat invalidate];
+                    heartBeat = nil;
+                }
+            }
+        }
+    })
+}
+
+//pingPong
+- (void)ping{
+    if (self.socket.readyState == SR_OPEN) {
+        [self.socket sendPing:nil];
+    }
+}
+
+- (void)sendData:(NSDictionary *)paramDic withRequestURI:(NSString *)requestURI{
+    
+    //这一块的数据格式由你们跟你们家服务器哥哥商定
+//     NSLog(@"socketSendData--configDic --------------- %@",requestURI);
+
+    WeakSelf(self);
+    dispatch_queue_t queue =  dispatch_queue_create("zy", NULL);
+    
+    dispatch_async(queue, ^{
+        if (weakself.socket != nil) {
+            // 只有 SR_OPEN 开启状态才能调 send 方法啊,不然要崩
+            if (weakself.socket.readyState == SR_OPEN) {
+                [weakself.socket send:requestURI];    // 发送数据
+                
+            } else if (weakself.socket.readyState == SR_CONNECTING) {
+
+                [weakself reConnect];
+                
+            } else if (weakself.socket.readyState == SR_CLOSING || weakself.socket.readyState == SR_CLOSED) {
+                // websocket 断开了,调用 reConnect 方法重连
+                NSLog(@"重连");
+                
+                [weakself reConnect];
+            }
+        } else {
+            // 这里要看你的具体业务需求;不过一般情况下,调用发送数据还是希望能把数据发送出去,所以可以再次打开链接;不用担心这里会有多个socketopen;因为如果当前有socket存在,会停止创建哒
+            [weakself SRWebSocketOpen];
+        }
+    });
+}
+
+-(SRReadyState)socketReadyState{
+    return self.socket.readyState;
+}
+-(void)dealloc{
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+    NSLog(@"SocketRocketUtility dealloced");
+}
+
+
+@end

+ 2 - 1
SDK/Tool/AlgorithmTool.h

@@ -42,7 +42,8 @@ NS_ASSUME_NONNULL_BEGIN
 //json字符串转字典
 +(NSDictionary *)dictionaryWithJsonString:(NSString *)jsonString;
 
-//返回时间戳
+
+//返回时间戳 精确到毫秒
 + (NSString *)returnTimestamp;
 
 @end

+ 10 - 25
SDK/Tool/AlgorithmTool.m

@@ -12,7 +12,7 @@
  //优先计算校验位--无误再进行数据处理  数据前面所有字节数相加是否等于最后一位
 +(BOOL)verificationRusult:(NSData*)characteristicValue{
 
-       if (characteristicValue.length<3){
+       if (characteristicValue.length<4){
             NSLog(@"无效报文");
             return NO;
        }
@@ -87,19 +87,23 @@
 
 //Data To Int:返回 不定个数 Byte的int数据
 +(int)dataToInt:(NSData*)data{
+    
    //2或4个字节
   int a = 0;
   [data getBytes:&a length:data.length];
   return a;
+    
 }
 
 //Data To Int:返回 不定个数 Byte的int数据 数据溢出要大小端转换
 +(int)dataToSwapBigIntToHost:(NSData*)data andRange:(NSRange)range{
+    
    //四个字节
   int a = 0;
   [data getBytes:&a range:range];
   a = NSSwapBigIntToHost(a);
   return a;
+    
 }
 
 /**
@@ -108,7 +112,6 @@
 +(NSString *)hexadecimalString:(NSData *)data{
 
     NSString *result;
-
     const unsigned char *dataBuffer = (const unsigned char *)[data bytes];
     if (!dataBuffer) {
         return nil;
@@ -120,7 +123,6 @@
         [hexString appendString:[NSString stringWithFormat:@"%02lx",(unsigned long)dataBuffer[i]]];
     }
     result = [NSString stringWithString:hexString];
-
     return result;
 
 }
@@ -182,7 +184,11 @@
     
 }
 
-// 返回时间戳
+
+
+
+
+// 返回时间戳 精确到毫秒
 + (NSString *)returnTimestamp{
     
     NSDateFormatter *formatter = [[NSDateFormatter alloc] init] ;
@@ -195,29 +201,8 @@
     NSDate *datenow = [NSDate date];
     NSString *timeSp = [NSString stringWithFormat:@"%ld", (long)[datenow timeIntervalSince1970]*1000];
     NSLog(@"时间戳  ===>> %@",timeSp);
-    
     return timeSp;
     
 }
 
-////获取当前时间 (以毫秒为单位)
-////返回值格式:2019-04-19 10:33:35.886
-//- (NSString *)getNowTimeTimestamp{
-//
-//    NSDate *datenow = [NSDate date];//现在时间,你可以输出来看下是什么格式
-//
-//    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
-//
-//    [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"];
-//
-//    [formatter setTimeZone:[NSTimeZone timeZoneWithName:@"Asia/Beijing"]];
-//
-//    NSString *dateString      = [formatter stringFromDate: datenow];
-//
-//    NSLog(@"当前时间戳对应的时间是:%@",dateString);
-//
-//    return dateString;
-//
-//}
-
 @end

+ 16 - 0
SDK/Tool/BugTool.h

@@ -0,0 +1,16 @@
+//
+//  BugTool.h
+//  Unity-iPhone
+//
+//  Created by duowan123 on 2022/4/6.
+//
+
+#import <Foundation/Foundation.h>
+
+@interface BugTool : NSObject
+
++(void)startAvoidBug;
+
+@end
+
+

+ 47 - 0
SDK/Tool/BugTool.m

@@ -0,0 +1,47 @@
+//
+//  BugTool.m
+//  Unity-iPhone
+//
+//  Created by duowan123 on 2022/4/6.
+//
+
+#import "BugTool.h"
+#import "AvoidCrash.h"
+//#import <Bugly/Bugly.h>
+
+@implementation BugTool
+
++(void)startAvoidBug{
+    
+//    //bugly抓取
+//    NSString * bundleIdentifier = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"];
+//    if ([bundleIdentifier isEqualToString:@"com.Oujia.Run"]){
+//        [Bugly startWithAppId:@"36a0c05291"];
+//    }else if ([bundleIdentifier isEqualToString:@"com.Oujia.Dance"]){
+//        [Bugly startWithAppId:@"403d275730"];
+//    }else if ([bundleIdentifier isEqualToString:@"com.Oujia.Tricycle"]){
+//        [Bugly startWithAppId:@"60d408c425"];
+//    }
+    
+//    //AvoidCrash防奔溃 + bug闪退信息上报
+    [AvoidCrash makeAllEffective];
+//    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(dealwithCrashMessage:) name:AvoidCrashNotification object:nil];
+//
+//}
+//
+//- (void)dealwithCrashMessage:(NSNotification *)note{
+//
+//  NSDictionary *info = note.userInfo;
+//  NSString *errorReason = [NSString stringWithFormat:@"【ErrorReason】%@========【ErrorPlace】%@========【DefaultToDo】%@========【ErrorName】%@", info[@"errorReason"], info[@"errorPlace"], info[@"defaultToDo"], info[@"errorName"]];
+//  NSLog(@"errorReason = %@",errorReason);
+//  NSArray *callStack = info[@"callStackSymbols"];
+//  [self reportErrorName:@"Bugly_ErrorName_AvoidCrash" errorReason:errorReason callStack:callStack extraInfo:nil];
+//
+//}
+//
+///** 上报错误信息 */
+//- (void)reportErrorName:(NSString *)errorName errorReason:(NSString *)errorReason callStack:(NSArray *)aStackArray extraInfo:(NSDictionary *)info{
+//    [Bugly reportExceptionWithCategory:3 name:errorName reason:errorReason callStack:aStackArray extraInfo:info terminateApp:NO];
+}
+
+@end

+ 29 - 0
SDK/Tool/CacheTool.h

@@ -0,0 +1,29 @@
+//
+//  CacheTool.h
+//  Unity-iPhone
+//
+//  Created by duowan123 on 2022/5/7.
+//
+
+#import <Foundation/Foundation.h>
+#import "GameInfo.h"
+#import "MYFactoryManager.h"
+
+@interface CacheTool : NSObject
+
++(void)cacheGameInfoInfo:(GameInfo*)gameInfo;
+
++(NSString*)getUserInfo;
++(NSString*)getToken;
++(NSString*)getGameId;
++(NSString*)getGameType;
++(NSString*)getGameMac;
++(NSString*)getInviteUser;
++(NSString*)getInviteInfo;
+//获取缓存vibrate
++(NSString*)getGameVibrate;
+//获取缓存debug
++(NSString*)getGameDebug;
+
+@end
+

+ 172 - 0
SDK/Tool/CacheTool.m

@@ -0,0 +1,172 @@
+//
+//  CacheTool.m
+//  Unity-iPhone
+//
+//  Created by duowan123 on 2022/5/7.
+//
+
+#import "CacheTool.h"
+
+
+@implementation CacheTool
+#pragma mark ===============================================>>玩游戏过程中缓存 动作数据 和时间戳 数据存入plist
++(void)cacheGameInfoInfo:(GameInfo*)gameInfo{
+ 
+        
+    
+//    //总数
+//    int total_step_count = game->getMotionCount(STEP_COUNT) - gameInfo.step;
+//    int total_jump_count = game->getMotionCount(JUMP_COUNT) - gameInfo.jump;
+//    int total_crouch_count = game->getMotionCount(DOWN_COUNT) - gameInfo.crouch;
+//    int total_tick_count = game->getMotionCount(KICK_COUNT) - gameInfo.tick;
+//    int total_paper_count = game->getMotionCount(PAPER_COUNT) - gameInfo.paper;
+//    int total_scissors_count = game->getMotionCount(SCISSORS_COUNT) - gameInfo.scissors;
+//    int total_rock_count = game->getMotionCount(ROCK_COUNT) - gameInfo.rock;
+//    int total_trample_count = game->getMotionCount(ROCK_COUNT) - gameInfo.trample;
+//
+//    //缓存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:gameInfo.firstTime];
+//    [movements setObject:[NSNumber numberWithInt:durationTime] forKey:@"duration"];
+//
+//    NSDictionary * dict = [NSDictionary dictionaryWithDictionary:movements];
+//
+//    //归档缓存
+//    [IOS_NSUSERDEFAULT setObject:dict forKey:IOSSDK_MOTIONCOUNT];
+//    [IOS_NSUSERDEFAULT synchronize];
+//
+}
+
+
+
+//获取getUserInfo
++(NSString*)getUserInfo{
+    NSDictionary * jsonDict = [IOS_NSUSERDEFAULT objectForKey:IOSSDK_USERINFO];
+    NSDictionary * user = jsonDict[@"user"];
+    if ([user isKindOfClass:[NSNull class]] || user == nil || [user isEqual:[NSNull null]]){
+        return @"";
+    }else{
+        NSData *jsonData = [NSJSONSerialization dataWithJSONObject:user options:NSJSONWritingPrettyPrinted error:nil];
+        NSString * userJsonString =  [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
+        return userJsonString;
+    }
+    
+}
+
+//获取token
++(NSString*)getToken{
+    NSDictionary * urlDict = [IOS_NSUSERDEFAULT objectForKey:IOSSDK_USERINFO];
+    NSString * token =  [urlDict objectForKey:@"token"];
+    if ([token isKindOfClass:[NSNull class]] || token == nil || [token isEqual:[NSNull null]]){
+//        [PopupView showCusHUDA:@"获取token失败,请从趣动启动"];
+        return @"";
+    }else{
+        return token;
+    }
+    
+}
+
+//获取缓存game_id
++(NSString*)getGameId{
+    NSDictionary * urlDict = [IOS_NSUSERDEFAULT objectForKey:IOSSDK_USERINFO];
+    NSString * game_id =  [urlDict objectForKey:@"game_id"];
+    if ([game_id isKindOfClass:[NSNull class]] || game_id == nil || [game_id isEqual:[NSNull null]]){
+//         [PopupView showCusHUDA:@"获取id失败,请从趣动启动"];
+        return @"";
+    }else{
+        return game_id;
+    }
+}
+
+//获取缓存game_type
++(NSString*)getGameType{
+    NSDictionary * urlDict = [IOS_NSUSERDEFAULT objectForKey:IOSSDK_USERINFO];
+    NSString * game_type =  [urlDict objectForKey:@"game_type"];
+    if ([game_type isKindOfClass:[NSNull class]] || game_type == nil || [game_type isEqual:[NSNull null]]){
+//         [PopupView showCusHUDA:@"获取type失败,请从趣动启动"];
+        return @"";
+    }else{
+        return game_type;
+    }
+}
+
+//获取缓存mac
++(NSString*)getGameMac{
+    NSDictionary * urlDict = [IOS_NSUSERDEFAULT objectForKey:IOSSDK_USERINFO];
+    NSString * mac =  [urlDict objectForKey:@"mac"];
+    if ([mac isKindOfClass:[NSNull class]] || mac == nil || [mac isEqual:[NSNull null]]){
+//         [PopupView showCusHUDA:@"获取mac失败,请从趣动启动"];
+        return @"";
+    }else{
+        return mac;
+    }
+}
+    
+//获取缓存邀请信息
++(NSString*)getInviteUser{
+    NSDictionary * urlDict = [IOS_NSUSERDEFAULT objectForKey:IOSSDK_USERINFO];
+    NSDictionary * invite = urlDict[@"invite"];
+    if ([invite isKindOfClass:[NSNull class]] || invite == nil || [invite isEqual:[NSNull null]]){
+//         [PopupView showCusHUDA:@"获取getInviteUser失败,请从趣动启动"];
+        return @"";
+    }else{
+        //user字典 -> 字符串 -> Char
+        NSDictionary * user =  [invite objectForKey:@"user"];
+        NSData * userData = [NSJSONSerialization dataWithJSONObject:user options:NSJSONWritingPrettyPrinted error:nil];
+        NSString * userString =  [[NSString alloc] initWithData:userData encoding:NSUTF8StringEncoding];
+        return userString;
+    }
+        
+}
+
++(NSString*)getInviteInfo{
+    
+    NSDictionary * urlDict = [IOS_NSUSERDEFAULT objectForKey:IOSSDK_USERINFO];
+    NSDictionary * invite = urlDict[@"invite"];
+    if ([invite isKindOfClass:[NSNull class]] || invite == nil || [invite isEqual:[NSNull null]]){
+//         [PopupView showCusHUDA:@"获取邀请信息失败,请从趣动启动"];
+        return @"";
+    }else{
+        NSString * info = [invite objectForKey:@"info"];
+        return info;
+    }
+ 
+}
+
+//获取缓存vibrate
++(NSString*)getGameVibrate{
+    NSDictionary * urlDict = [IOS_NSUSERDEFAULT objectForKey:IOSSDK_USERINFO];
+    NSString * vibrate =  [urlDict objectForKey:@"vibrate"];
+    if ([vibrate isKindOfClass:[NSNull class]] || vibrate == nil || [vibrate isEqual:[NSNull null]]){
+//         [PopupView showCusHUDA:@"获取mac失败,请从趣动启动"];
+        return @"";
+    }else{
+        return vibrate;
+    }
+}
+
+//获取缓存debug
++(NSString*)getGameDebug{
+    NSDictionary * urlDict = [IOS_NSUSERDEFAULT objectForKey:IOSSDK_USERINFO];
+    NSString * debug =  [urlDict objectForKey:@"debug"];
+    if ([debug isKindOfClass:[NSNull class]] || debug == nil || [debug isEqual:[NSNull null]]){
+//         [PopupView showCusHUDA:@"获取mac失败,请从趣动启动"];
+        return @"";
+    }else{
+        return debug;
+    }
+}
+
+@end

+ 0 - 157
SDK/Tool/GameObjc.h

@@ -1,157 +0,0 @@
-//
-//#import <Foundation/Foundation.h>
-//
-//NS_ASSUME_NONNULL_BEGIN
-//
-//@interface GameObjc : NSObject
-//+ (instancetype)new NS_UNAVAILABLE;
-//- (instancetype)init NS_UNAVAILABLE;
-//- (instancetype)initWithGametype:(int)gametype NS_DESIGNATED_INITIALIZER;
-//
-//- (void)gameProcess:(int)timeStamp
-//           rightPos:(int *)rightPos
-//           rightAtt:(int *)rightAtt
-//           rightAcc:(int *)rightAcc
-//          rightZupt:(int)rightZupt
-//        right_press:(int)right_press
-//            leftPos:(int *)leftPos
-//            leftAtt:(int *)leftAtt
-//           leftAcc:(int *)leftAcc
-//           leftZupt:(int)leftZupt
-//         left_press:(int)left_press
-//               jump:(int)jump
-//               down:(int)down
-//               rssi:(int)rssi
-//         girl_shoes:(int)girl_shoes;
-//
-//- (void)runGameProcess:(int)timeStamp
-//              rightPos:(int *)rightPos
-//              rightAtt:(int *)rightAtt
-//              rightAcc:(int *)rightAcc
-//             rightZupt:(int)rightZupt
-//           right_press:(int)right_press
-//               leftPos:(int *)leftPos
-//               leftAtt:(int *)leftAtt
-//              leftAcc:(int *)leftAcc
-//              leftZupt:(int)leftZupt
-//            left_press:(int)left_press
-//                  jump:(int)jump
-//                  down:(int)down
-//            girl_shoes:(int)girl_shoes;
-//
-//- (void)getGameResult:(int *)matrix;
-//
-//- (int)getStepFreq:(int)leftOrRight;
-//- (int)getStepStatus:(int)leftOrRight;
-//- (int)getStepCount:(int)leftOrRight;
-//
-//- (float)getGamePos:(int)left_or_right index:(int)index;
-//
-//- (void)start;
-//- (void)end;
-//- (void)isBingo;
-//-(int)getInteractionCMD;
-//-(NSString*)getGameDataStr;
-//-(void)GameProcessBuf:(uint8_t*)buff length:(int)length;
-//
-///// 向外提供,手动释放,如需要,可调用
-//- (void)handRelease;
-//
-//@end
-//
-//@interface RunGameObjc : NSObject
-//- (int)getResultLeftRight:(int *)pos
-//                   devNum:(short)devNum;
-//- (int)getResultJump:(short)jump;
-//- (int)getResultDown:(short)down;
-//- (void)setResultConLeft:(short)zupt;
-//- (void)setResultConRight:(short)zupt;
-//- (int)getResultLeft:(int *)pos girl_shoes:(int)girl_shoes;
-//- (int)getResultRight:(int *)pos girl_shoes:(int)girl_shoes;
-//- (void)process:(int)timeStamp
-//       rightPos:(int *)rightPos
-//       rightAtt:(int *)rightAtt
-//       rightAcc:(int *)rightAcc
-//      rightZupt:(int)rightZupt
-//    right_press:(int)right_press
-//        leftPos:(int *)leftPos
-//        leftAtt:(int *)leftAtt
-//       leftAcc:(int *)leftAcc
-//       leftZupt:(int)leftZupt
-//     left_press:(int)left_press
-//           jump:(int)jump
-//           down:(int)down
-//     girl_shoes:(int)girl_shoes;
-//- (void)getResult:(int *)dec;
-///// 向外提供,手动释放
-//- (void)handRelease;
-//@end
-//
-//@interface DanceGameObjc : NSObject
-////- (int)gamePositionProcess:(int *)pos
-////                   stepPos:(int *)stepPos
-////                      rssi:(int)rssi
-////               hostOrSlave:(short)hostOrSlave;
-////- (void)gameBoundary:(int *)globalPos;
-////- (int)getDirectionFloat:(float *)pos rssi:(int)rssi;
-////- (short)danceGameProcess:(int *)pos
-////                     zupt:(short)zupt
-////                     rssi:(int)rssi
-////              hostOrSlave:(short)hostOrSlave;
-//- (void)process:(int *)rightPos
-//       rightAtt:(int *)rightAtt
-//      rightZupt:(int)rightZupt
-//    right_press:(int)right_press
-//        leftPos:(int *)leftPos
-//        leftAtt:(int *)leftAtt
-//       leftZupt:(int)leftZupt
-//     left_press:(int)left_press
-//           jump:(int)jump
-//           down:(int)down
-//           rssi:(int)rssi;
-//
-//- (void)getResult:(int *)matrix;
-////- (float)getRssiDistance:(int)rssi;
-////- (int)savePosAndRssi:(int *)pos
-////                 zupt:(short)zupt
-////                 rssi:(int)rssi
-////          hostOrSlave:(short)hostOrSlave;
-///// 向外提供,手动释放,如需要,可调用
-//- (void)handRelease;
-//@end
-//
-//
-//@interface FootStepObjc : NSObject
-////pos开辟3个空间
-//- (void)stepCal:(int)timeStamp posList:(int *)pos zupt:(int)zupt girl_shoes:(int)girl_shoes;
-//- (int)getStepFreq;
-//- (int)getStepStatus;
-//- (int)getStepCount;
-///// 向外提供,手动释放,如需要,可调用
-//- (void)handRelease;
-//@end
-//
-//
-//@interface InertialTrajProcessObjc : NSObject
-//- (void)trajRotate:(int *)pos;
-////rotateMatrix只能开辟4个空间
-//- (void)trajRotate:(int *)pos
-//      rotateMatrix:(float *)rotateMatrix;
-//- (void)resetHeading:(short)heading;
-///// 向外提供,手动释放
-//- (void)handRelease;
-//@end
-//
-////@interface OriginTrajObj : NSObject
-////- (void)process:(int*)right_pos
-////        right_att:(int*)right_att
-////        right_zupt:(int)right_zupt
-////        left_pos:(int*)left_pos
-////        left_att:(int*)left_att
-////        left_zupt:(int) left_zupt;
-////
-////- (float)getGamePos:(int)left_or_right
-////               index:(int)index;
-////@end
-//
-//NS_ASSUME_NONNULL_END

+ 0 - 387
SDK/Tool/GameObjc.mm

@@ -1,387 +0,0 @@
-//
-//#import "GameObjc.h"
-//#include "Game.h"
-//#include "DanceGame.h"
-//#include "FootStep.h"
-//#include "InertialTrajProcess.h"
-////#include "OriginTraj.h"
-////#include <math.h>
-//
-//#define NSLog(format, ...) printf("TIME:%s FILE:%s(%d行) FUNCTION:%s \n %s\n\n",__TIME__, [[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, __PRETTY_FUNCTION__, [[NSString stringWithFormat:(format), ##__VA_ARGS__] UTF8String])
-//
-//
-//@interface GameObjc()
-//{
-//@private
-//    Game *game;
-//    int gametype;
-//}
-//@end
-//
-//@implementation GameObjc
-//
-//- (instancetype)initWithGametype:(int)gametype{
-//    self = [super init];
-//    if (self){
-//        gametype = gametype;
-//        game = new Game(gametype);
-//    }
-//    return self;
-//}
-//
-//- (void)gameProcess:(int)timeStamp
-//           rightPos:(int *)rightPos
-//           rightAtt:(int *)rightAtt
-//           rightAcc:(int *)rightAcc
-//          rightZupt:(int)rightZupt
-//        right_press:(int)right_press
-//            leftPos:(int *)leftPos
-//            leftAtt:(int *)leftAtt
-//           leftAcc:(int *)leftAcc
-//           leftZupt:(int)leftZupt
-//         left_press:(int)left_press
-//               jump:(int)jump
-//               down:(int)down
-//               rssi:(int)rssi
-//         girl_shoes:(int)girl_shoes{
-//    game->GameProcess(timeStamp, rightPos, rightAtt, rightAcc,rightZupt,right_press,leftPos, leftAtt, leftAcc,leftZupt, left_press,jump,down, rssi,girl_shoes);
-//}
-//
-//- (void)runGameProcess:(int)timeStamp
-//              rightPos:(int *)rightPos
-//              rightAtt:(int *)rightAtt
-//              rightAcc:(int *)rightAcc
-//             rightZupt:(int)rightZupt
-//           right_press:(int)right_press
-//               leftPos:(int *)leftPos
-//               leftAtt:(int *)leftAtt
-//              leftAcc:(int *)leftAcc
-//              leftZupt:(int)leftZupt
-//            left_press:(int)left_press
-//                  jump:(int)jump
-//                  down:(int)down
-//            girl_shoes:(int)girl_shoes{
-//    game->RunGameProcess(rightPos, rightAtt, rightAcc,rightZupt,right_press,leftPos, leftAtt, leftAcc,leftZupt, left_press,jump,down,girl_shoes);
-//
-//}
-//
-//- (void)getGameResult:(int *)matrix{
-//    game->getGameResult(matrix);
-//}
-//
-//- (int)getStepFreq:(int)leftOrRight{
-//    return game->getStepFreq(leftOrRight);
-//}
-//- (int)getStepStatus:(int)leftOrRight{
-//    return game->getStepStatus(leftOrRight);
-//}
-//- (int)getStepCount:(int)leftOrRight{
-//    return game->getStepCount(leftOrRight);
-//}
-//
-//- (float)getGamePos:(int)left_or_right index:(int)index{
-//    return game->getGamePos(left_or_right, index);
-//}
-//
-//- (void)start{
-//    game->start(nil);
-//}
-//- (void)end{
-//    game->end();
-//}
-//
-//- (void)isBingo{
-//    game->isBingo();
-//}
-//
-//-(int)getInteractionCMD{
-//    return game->getInteractionCMD();
-//}
-//
-//-(NSString*)getGameDataStr{
-//
-////    NSString * string =  [NSString stringWithCString:game->getGameDataStr().c_str() encoding:[NSString defaultCStringEncoding]];
-//    NSString * aString = [NSString stringWithUTF8String:game->getGameDataStr().c_str()];
-////    NSLog(@"剑波需要的数据1 %@",string);
-////    NSLog(@"剑波需要的数据2 %@",aString);
-//    return aString;
-//
-//}
-//
-//-(void)GameProcessBuf:(uint8_t*)buff length:(int)length{
-//
-//    game->GameProcessBuf(buff, length);
-//
-//}
-//
-///// 向外提供,手动释放
-//- (void)handRelease{
-//    delete game;
-//}
-//- (void)dealloc{
-//    delete game;
-//}
-//
-//@end
-//
-//@interface RunGameObjc ()
-//{
-//    @private
-//    RunGame * runGame;
-//}
-//@end
-//
-//@implementation RunGameObjc
-//- (instancetype)init{
-//    self = [super init];
-//    if (self) {
-//        runGame = new RunGame();
-//    }
-//    return self;
-//}
-//- (int)getResultLeftRight:(int *)pos
-//                   devNum:(short)devNum{
-//    return runGame->getResultLeftRight(pos, devNum);
-//}
-//- (int)getResultJump:(short)jump{
-//    return runGame->getResultJump(jump);
-//}
-//- (int)getResultDown:(short)down{
-//    return runGame->getResultDown(down);
-//}
-//- (void)setResultConLeft:(short)zupt{
-//    runGame->setResultConLeft(zupt);
-//}
-//- (void)setResultConRight:(short)zupt{
-//     runGame->setResultConRight(zupt);
-//}
-//- (int)getResultLeft:(int *)pos girl_shoes:(int)girl_shoes{
-//    return runGame->getResultLeft(pos,girl_shoes);
-//}
-//- (int)getResultRight:(int *)pos girl_shoes:(int)girl_shoes{
-//    return runGame->getResultRight(pos,girl_shoes);
-//}
-//
-//- (void)process:(int)timeStamp
-//       rightPos:(int *)rightPos
-//       rightAtt:(int *)rightAtt
-//       rightAcc:(int *)rightAcc
-//      rightZupt:(int)rightZupt
-//    right_press:(int)right_press
-//        leftPos:(int *)leftPos
-//        leftAtt:(int *)leftAtt
-//       leftAcc:(int *)leftAcc
-//       leftZupt:(int)leftZupt
-//     left_press:(int)left_press
-//           jump:(int)jump
-//           down:(int)down
-//     girl_shoes:(int)girl_shoes{
-//
-//    runGame->Process(rightPos, rightAtt, rightAcc,rightZupt,right_press,leftPos, leftAtt, leftAcc,leftZupt, left_press,jump,down,girl_shoes);
-//
-////    Process(int* right_pos, int* right_att, int* right_acc, int right_zupt, int right_press,
-////                 int* left_pos, int* left_att, int* left_acc, int left_zupt, int left_press,
-////                 int jump, int down, int girl_shoes)
-//
-//}
-//
-//- (void)getResult:(int *)dec{
-//    runGame->getResult(dec);
-//}
-//
-///// 向外提供,手动释放
-//- (void)handRelease{
-//    delete runGame;
-//}
-//- (void)dealloc{
-//    delete runGame;
-//}
-//@end
-//
-//@interface DanceGameObjc()
-//{
-//@private
-//    DanceGame *danceGame;
-//}
-//@end
-//
-//@implementation DanceGameObjc
-//- (instancetype)init{
-//    self = [super init];
-//    if (self) {
-//        danceGame = new DanceGame();
-//    }
-//    return self;
-//}
-//
-////- (int)gamePositionProcess:(int *)pos
-////                   stepPos:(int *)stepPos
-////                      rssi:(int)rssi
-////               hostOrSlave:(short)hostOrSlave{
-////    //SInt16 ==> short*
-////    return  danceGame->game_position_process(pos, stepPos, rssi, hostOrSlave);
-////}
-//
-////- (void)gameBoundary:(int *)globalPos{
-////    danceGame->game_boundary(globalPos);
-////}
-////- (int)getDirectionFloat:(float *)pos
-////                    rssi:(int)rssi{
-////    //float==>32位
-////    return  danceGame->getDirectionFloat(pos,rssi);
-////}
-////- (short)danceGameProcess:(int *)pos
-////                     zupt:(short)zupt
-////                     rssi:(int)rssi
-////              hostOrSlave:(short)hostOrSlave{
-////    return danceGame->dance_game_process(pos, zupt, rssi, hostOrSlave);
-////}
-//
-//- (void)process:(int *)rightPos
-//       rightAtt:(int *)rightAtt
-//       rightAcc:(int *)rightAcc
-//      rightZupt:(int)rightZupt
-//    right_press:(int)right_press
-//        leftPos:(int *)leftPos
-//        leftAtt:(int *)leftAtt
-//       leftAcc:(int *)leftAcc
-//       leftZupt:(int)leftZupt
-//     left_press:(int)left_press
-//           jump:(int)jump
-//           down:(int)down
-//           rssi:(int)rssi{
-//    danceGame->Process(rightPos, rightAtt,rightAcc, rightZupt, right_press,leftPos, leftAtt,leftAtt, leftZupt, left_press,jump, down, rssi);
-//}
-//
-//- (void)getResult:(int *)matrix{
-//    danceGame->getResult(matrix);
-//}
-////- (float)getRssiDistance:(int)rssi{
-////    return danceGame->getRssiDistance(rssi);
-////}
-////- (int)savePosAndRssi:(int *)pos
-////                 zupt:(short)zupt
-////                 rssi:(int)rssi
-////          hostOrSlave:(short)hostOrSlave{
-////    return danceGame->savePosAndRssi(pos, zupt, rssi, hostOrSlave);
-////}
-///// 向外提供,手动释放
-//- (void)handRelease{
-//    delete danceGame;
-//}
-//- (void)dealloc{
-//    delete danceGame;
-//}
-//@end
-//
-//@interface FootStepObjc ()
-//{
-//@private
-//    FootStep *footStep;
-//}
-//@end
-//
-//@implementation FootStepObjc
-//
-//- (instancetype)init{
-//    self = [super init];
-//    if (self) {
-//        footStep = new FootStep();
-//    }
-//    return self;
-//}
-////pos开辟3个空间
-////- (void)stepCal:(int)timeStamp posList:(int *)pos zupt:(int)zupt girl_shoes:(int)girl_shoes{
-//    footStep->stepCal(timeStamp, pos, zupt,girl_shoes);
-//}
-//- (int)getStepFreq{
-//    return footStep->getStepFreq();
-//}
-//- (int)getStepStatus{
-//    return footStep->getStepStatus();
-//}
-//- (int)getStepCount{
-//    return footStep->getStepCount();
-//}
-//- (void)dealloc{
-//    delete footStep;
-//}
-///// 向外提供,手动释放
-//- (void)handRelease{
-//    delete footStep;
-//}
-//
-//@end
-//
-//@interface InertialTrajProcessObjc ()
-//{
-//    @private
-//    InertialTrajProcess * inertialTrajProcess;
-//}
-//@end
-//@implementation InertialTrajProcessObjc
-//- (instancetype)init{
-//    self = [super init];
-//    if (self) {
-//        inertialTrajProcess = new InertialTrajProcess();
-//    }
-//    return self;
-//}
-//- (void)trajRotate:(int *)pos{
-//    inertialTrajProcess->TrajRotate(pos);
-//}
-////rotateMatrix只能开辟4个空间
-//- (void)trajRotate:(int *)pos
-//      rotateMatrix:(float *)rotateMatrix{
-//    inertialTrajProcess->TrajRotate(pos,rotateMatrix);
-//}
-//- (void)resetHeading:(short)heading{
-//    inertialTrajProcess->ResetHeading(heading);
-//}
-///// 向外提供,手动释放
-//- (void)handRelease{
-//    delete inertialTrajProcess;
-//}
-//- (void)dealloc{
-//    delete inertialTrajProcess;
-//}
-//@end
-//
-//
-////@interface OriginTrajObj ()
-////{
-////    @private
-////    OriginTraj * originTraj;
-////}
-////@end
-////@implementation OriginTrajObj
-////- (instancetype)init{
-////    self = [super init];
-////    if (self){
-////        originTraj = new OriginTraj();
-////    }
-////    return self;
-////}
-////
-////- (void)process:(int*)right_pos
-////        right_att:(int*)right_att
-////        right_zupt:(int)right_zupt
-////        left_pos:(int*)left_pos
-////        left_att:(int*)left_att
-////      left_zupt:(int) left_zupt{
-////    originTraj->Process(right_pos, right_att, right_zupt, left_pos, left_att, left_zupt);
-////}
-////
-////- (float)getGamePos:(int)left_or_right
-////              index:(int)index{
-////    return originTraj->getGamePos(left_or_right, index);
-////}
-////
-/////// 向外提供,手动释放
-////- (void)handRelease{
-////    delete originTraj;
-////}
-////- (void)dealloc{
-////    delete originTraj;
-////}
-////@end

+ 16 - 102
SDK/Tool/MYFactoryManager.h

@@ -15,18 +15,16 @@
 #import "AlgorithmTool.h"
 #import "UIColor+Hex.h"
 
-//#import "IOSPlatformSDK.h"
-//
 //蓝牙
 #import <CoreBluetooth/CoreBluetooth.h>
 #import "BTDataProcess.h"
 //蓝牙提供的sdk算法
-#import "GameObjc.h"
 #define LEFT_FOOT_OC 1
 #define RIGHT_FOOT_OC 2
 //蓝牙框架封装
 #import "LEONBLManager.h"
 #import "BTDataSend.h"
+#import "BTDataAnalysis.h"
 #import "CBPeripheral+ADName.h"
 #define BTDataInstance [BTDataProcess sharedInstance]
 #define LEManager [LEONBLManager sharedInstance]
@@ -37,13 +35,17 @@
 //第三方
 #import "AFNetworking.h"
 #import "MBProgressHUD.h"
+
 //UI
 #import "SearchDeviceViewController.h"
-#import "AnimationView.h"
+#import "FriendsListViewController.h"
+#import "MainLoadingView.h"
+#import "ViceLoadingView.h"
 #import "PopupView.h"
 #import "NoDeviceTip.h"
 #import <AudioToolbox/AudioToolbox.h>
 #import "DebugView.h"
+#import "CacheTool.h"
 
 /*************************** 获取屏幕 宽度、高度 ***************************/
 #define SCREEN_WIDTH ([UIScreen mainScreen].bounds.size.width)
@@ -63,16 +65,18 @@
 //app跳转 用户信息
 #define IOSSDK_USERINFO @"iosSdk_userInfo"
 //缓存的步频数据
-#define IOSSDK_BLESDKDATA @"iosSdk_bleSdk_frequency"
-//游戏组数时间戳 参数是play_gorup
-#define IOSSDK_TIMESTAMP @"iosSdk_timestamp"
+#define IOSSDK_MOTIONCOUNT @"iosSdk_motionCount"
+ 
 //custom System UserDefaults
 #define IOS_NSUSERDEFAULT [NSUserDefaults standardUserDefaults]
 #define CUS_NOTIFICATIONCENTER [NSNotificationCenter defaultCenter]
-#define IOSSDK_TOKEN [[IOS_NSUSERDEFAULT objectForKey:IOSSDK_USERINFO] objectForKey:@"token"]
-#define IOSSDK_GAMEID [[IOS_NSUSERDEFAULT objectForKey:IOSSDK_USERINFO] objectForKey:@"game_type"]
-//#define IOSSDK_GAMEID @"3"
-//#define IOSSDK_TOKEN @"shoes:61652aa99523f9.65681365I94"
+
+//log
+//#ifdef DEBUG
+//#define NSLog(...) NSLog(@"%s 第%d行 \n %@\n\n",__func__,__LINE__,[NSString stringWithFormat:__VA_ARGS__])
+//#else
+//#define NSLog(...)
+//#endif
 
 @interface MYFactoryManager : NSObject
 
@@ -85,99 +89,9 @@
 + (void)makeBoundsWithView:(UIView *)view color:(UIColor *)color width:(CGFloat)width;
 //圆角
 + (void)clipsToBoundsWithView:(UIView *)view Radius:(NSInteger)radius;
-/**高度自适应*/
-+ (CGFloat)heightForString:(NSString *)string fontSize:(CGFloat)fontSize andWidth:(CGFloat)width;
-/**宽度自适应*/
-+ (CGFloat)widthForString:(NSString *)string fontSize:(CGFloat)fontSize andHeight:(CGFloat)height;
+
 //正常加载还是打包后sdk加载
 +(UIImage*)imageString:(NSString*)imageName;
-//发送测试group通知
-+(void)postGroupCFNotificaiton:(NSString*)string;
-//开启后台任务保活
--(void)comeToBackgroundMode;
-//#pragma mark -- 参数判断
-//+(BOOL)ifLoogIn:(BOOL)tip;
-//+(bool)internetStatus;
-//
-//#pragma mark -- 各类弹窗
-//+(void)popChooseSSIDListViewController;
-//
-//#pragma mark -- 授权
-//+(BOOL)authorizationCarmen;
-//
-//#pragma mark -- 正则
-////获取*****手机格式
-//+ (NSString *)getPhoneText:(NSString *)phoneNum;
-////手机格式
-//+ (BOOL)phoneNum:(NSString *) textString;
-////检测是否为邮箱
-//+ (BOOL)emailNum:(NSString *)emailStr;
-//
-//
-////字符串转字典与字典转字符串
-//+ (NSDictionary *)parseJSONStringToNSDictionary:(NSString *)JSONString;
-//+ (NSString*)dictionaryToJson:(NSDictionary *)dic;
-//+ (NSString*)arrayToJson:(NSArray *)arr;
-//+ (NSArray *)parseJSONStringToNSArray:(NSString *)JSONString;
-//
-////时间计算
-//+ (NSString*)returnNowDateString;
-//+ (NSString*)returnNowTimeString;
-//+ (NSString *)getStartTimeDate:(NSNumber *)dateTime format:(NSString *)format;
-//+ (NSString *)returnUploadTime:(NSString *)timeStr;
-//+ (NSString *)getRealTime:(NSString *)dateTime format:(NSString *)format;
-//+ (NSString *)returnTimestamp:(NSString *)timeStr;
-//+ (void)countdownWith:(UIButton *)but;//倒计时
-//
-//#pragma mark -------------------------------------------------------------------------------------- 勒夫曼德
-////16位数字MD5加密
-//+ (NSString *)getMd5_16Bit_String:(NSString *)srcString;
-////将十六进制的字符串转换成NSString则可使用如下方式:
-//+ (NSString *)convertHexStrToString:(NSString *)str;
-////将NSString转换成十六进制的字符串则可使用如下方式:
-//+ (NSString *)convertStringToHexStr:(NSString *)str;
-////十六进制转换为二进制
-//+ (NSString *)convertDataToHexStr:(NSData *)data;
-////温度图文混排富文本
-//+(NSAttributedString*)labelAttribute:(NSString*)firstLabelText  secondLabelText:(NSString*)secondLabelText;
-////修改头部视图背景
-//+(NSString*)changePicturesAccordingToPeriods;
-////国际化地名简体转拼音
-//+ (NSString *)transform:(NSString *)chinese;
-////返回档位信息
-//+(NSString*)returnStallStr:(NSString*)command deviceinfo:(NSString*)deviceinfo;
-////返回天气图片
-//+(NSString*)returnWeatherImageStr:(NSString*)deviceInfo;
-////返回室外天气
-//+(NSString*)returnOutDoorAqi:(NSInteger)aqiValue;
-////验证报文
-//+(NSString*)authenticationMessage:(NSString*)MessageConent;
-////获取当前手机连接的wifi是否是luftmed-
-//+ (NSString*)getCurrentSSID;
-//+ (BOOL)ifConnetLuftmed;
-////获取UDID
-//+(NSString*)getUDIDString;
-////返回PM25污染度对应的文本
-//+(NSString*)getPM25ValueText:(NSString*)value;
-////返回PM25污染度对应的颜色
-//+(UIColor*)getPM25ValueColor:(NSString*)value;
-////返回PM25污染度对应角度
-//+(CGFloat)getPM25TotalAngle:(NSInteger)temp10;
-////返回TVOC污染度对应的文本
-//+(NSString*)getTVOCValueText:(NSString*)value;
-////返回TVOC污染度对应的颜色
-//+(UIColor*)getTVOCValueColor:(NSString*)value;
-////TVOC真实值
-//+(NSString*)returnRealTVOCValue:(NSString*)value;
-//
-//#pragma mark -------------------------------------------------------------------------------------- 车载相关
-////或异算法
-//+(NSString*)HardDriveVerificationAlgorithm:(NSString*)string_input;
-////字符串转16进制数据流 -- 用于蓝牙发送
-//+(NSData *)convertHexStrToData:(NSString *)str;
-////单个16进制字节-转换-》10进制
-//+(NSInteger)hexToInt:(NSString*)hex;
-//
 
 
 @end

+ 17 - 1232
SDK/Tool/MYFactoryManager.m

@@ -7,8 +7,7 @@
 //
 
 #import "MYFactoryManager.h"
-#import <SystemConfiguration/CaptiveNetwork.h>//get ssid
-#import <CommonCrypto/CommonDigest.h>//get MD5
+
 
 @interface MYFactoryManager ()
 @end
@@ -49,41 +48,11 @@ static MYFactoryManager * instance;
     view.layer.masksToBounds = YES;
 }
 
-//计算高度
-+ (CGFloat)heightForString:(NSString *)string fontSize:(CGFloat)fontSize andWidth:(CGFloat)width{
-    
-    if (string != nil&&![string isKindOfClass:[NSNull class]]){
-        
-        CGRect rect = [string boundingRectWithSize:CGSizeMake(width, MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:fontSize]} context:nil];
-        return rect.size.height;
-        
-    }else{
-        
-        return 20;
-        
-    }
-
-}
-
-//计算文本宽度
-+ (CGFloat)widthForString:(NSString *)string fontSize:(CGFloat)fontSize andHeight:(CGFloat)height{
-    
-    if (string != nil&&![string isKindOfClass:[NSNull class]]){
-        
-        CGRect rect = [string boundingRectWithSize:CGSizeMake(MAXFLOAT, height) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:[UIFont systemFontOfSize:fontSize]} context:nil];
-        return rect.size.width;
-
-    }else{
-        
-        return 50;
-        
-    }
-}
 
 //正常加载还是打包后sdk加载
 +(UIImage*)imageString:(NSString*)imageName{
     
-    BOOL ifSdk = NO;
+    BOOL ifSdk = YES;
     UIImage *orangeImage;
     if (ifSdk==YES){//打包成sdk后 加载imageUrl要用[self class]的方式
         NSBundle * refreshBundle = [NSBundle bundleWithPath:[[NSBundle bundleForClass:[self class]] pathForResource:@"IOSToUnityBundle" ofType:@"bundle"]];
@@ -97,1208 +66,24 @@ static MYFactoryManager * instance;
     
 }
 
-#pragma mark ------  发送app group通知
-+ (void)postGroupCFNotificaiton:(NSString*)string{
-    
-    NSString * notificaitonName = @"OPEN_NOTIFICATION";
-    CFStringRef strRef = (__bridge CFStringRef)notificaitonName;
-    CFNotificationCenterRef notification = CFNotificationCenterGetDarwinNotifyCenter ();
-    //第一种生成参数方法 测试无效
-//    NSDictionary * ocDict = @{@"key":@"123"};
-//    CFDictionaryRef dicRef = (__bridge CFDictionaryRef)ocDict;
-    //第二种 共享沙河数据
-    NSUserDefaults* userDefault = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.Oujia.AppAndGame"];
-    [userDefault setObject:string forKey:@"type"];//主副设备 断开的type
-    [userDefault synchronize];
-    //之后发送通知
-    CFNotificationCenterPostNotification(notification, strRef, NULL,nil, YES);
- 
-}
-
-
-#pragma mark -- leon add
--(void)comeToBackgroundMode{
-    //初始化一个后台任务BackgroundTask,这个后台任务的作用就是告诉系统当前app在后台有任务处理,需要时间
-    UIApplication*app = [UIApplication sharedApplication];
-    self.bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
-    [app endBackgroundTask:self.bgTask];
-    self.bgTask = UIBackgroundTaskInvalid;
-    }];
-    //开启定时器 不断向系统请求后台任务执行的时间
-    NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:30.0 target:self selector:@selector(applyForMoreTime) userInfo:nil repeats:YES];
-    [timer fire];
-}
-
--(void)applyForMoreTime{
-    //如果系统给的剩余时间小于60秒 就终止当前的后台任务,再重新初始化一个后台任务,重新让系统分配时间,这样一直循环下去,保持APP在后台一直处于active状态。
-    if ([UIApplication sharedApplication].backgroundTimeRemaining < 30){
-    [[UIApplication sharedApplication] endBackgroundTask:self.bgTask];
-    self.bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
-    [[UIApplication sharedApplication] endBackgroundTask:self.bgTask];
-    self.bgTask = UIBackgroundTaskInvalid;
-    }];
-    }
-}
-
-//加载xib
-- (void)tableViewRegisterNib{
-    
-//    BOOL ifSdk = NO;
-//    if (ifSdk){
-//        NSBundle *bkBundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"IOSToUnityBundle" ofType:@"bundle"]];
-//        [self.tableView registerNib:[UINib nibWithNibName:@"PeripheralCell" bundle:bkBundle] forCellReuseIdentifier:@"PeripheralCell"];
-//    }else{
-//        [self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([PeripheralCell class]) bundle:nil] forCellReuseIdentifier:@"PeripheralCell"];
-//    }
-    
-}
-
-////倒计时
-//+ (void)countdownWith:(UIButton *)but{
-//    
-//    __block int timeout=59; //倒计时时间
-//    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
-//    dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,queue);
-//    dispatch_source_set_timer(_timer,dispatch_walltime(NULL, 0),1.0*NSEC_PER_SEC, 0); //每秒执行
-//    dispatch_source_set_event_handler(_timer, ^{
-//        if(timeout<=0){ //倒计时结束,关闭
-//            dispatch_source_cancel(_timer);
-//            dispatch_async(dispatch_get_main_queue(), ^{
-//                //设置界面的按钮显示 根据自己需求设置
-//                //设置按钮的样式
-//                but.titleLabel.font = [UIFont  systemFontOfSize:10];
-//                [but setTitle:@"发送验证码" forState:UIControlStateNormal];
-//                [but setTitleColor:[UIColor colorWithHexString:@"#BABBBB"] forState:(UIControlStateNormal)];
-//                but.userInteractionEnabled = YES;
-//            });
-//        }else{
-//            
-//            int seconds = timeout % 60;
-//            NSString *strTime = [NSString stringWithFormat:@"%.2d", seconds];
-//            dispatch_async(dispatch_get_main_queue(), ^{
-//                //设置界面的按钮显示 根据自己需求设置
-//                but.titleLabel.font = [UIFont  systemFontOfSize:10];
-//                [but setTitle:[NSString stringWithFormat:@"重新发送(%@)",strTime] forState:UIControlStateNormal];
-//                [but setTitleColor:[UIColor colorWithHexString:@"#BABBBB"] forState:(UIControlStateNormal)];
-//                but.userInteractionEnabled = NO;
-//                
-//            });
-//            timeout--;
-//        }
-//    });
-//    dispatch_resume(_timer);
-//    
-//}
-//
-//#pragma mark ---------------------------------------------------------------- 参数判断
-////网络链接状态
-//+(bool)internetStatus{
-//    
-//    Reachability * reachability   = [Reachability reachabilityWithHostName:@"www.apple.com"];
-//    NetworkStatus internetStatus = [reachability currentReachabilityStatus];
-//    bool  net = NO;
-//    switch (internetStatus){
-//        case ReachableViaWiFi:
-//            net = YES;
-//            break;
-//        case ReachableViaWWAN:
-//            net = YES;
-//            break;
-//        case NotReachable:
-//            net = NO;
-//            [MBProgressHUD showTextMessage:@"当前无网络连接,请检查网络配置!"];
-//        default:
-//            break;
-//    }
-//    
-//    return net;
-//}
-//
-//+(BOOL)ifLoogIn:(BOOL)tip{
-//    
-//    UserInfoModel * userModel = [UserInfoModel getUserInfoModelFormLocal];
-//    AccessTokenInfo * token = [AccessTokenInfo getAccessTokenModelFormLocal];
-//    //9aafc5e3-5910-433c-b33c-3e85b1ec8917
-//    if (userModel.uuid.length!=16||userModel==nil||token.access_token.length!=36||token==nil){//未登录
-//        
-//        if (tip == YES){
-//            [MBProgressHUD showTextMessage:MyLocalizedString(@"Use Smart series equipment, please log in first!")];
-//        }
-//
-//        return NO;
-//        
-//    }else{
-//     
-//        return YES;
-//        
-//    }
-//    
-//}
-//
-//
-//
-//#pragma mark ---------------------------------------------------------------- 各类弹窗
-////其他网络  提示用户切换网络为luftmed
-//+(void)popChooseSSIDListViewController{
-//    
-//    //链接失败毛玻璃效果
-//    PopToSystemViewController  * visualEffecVC = [PopToSystemViewController  new];
-//    
-//    visualEffecVC.closeTask = ^{
-//        
-//        NSString * urlStr =  [kDefaults objectForKey:@"simulation_api"];
-//        
-//        if (urlStr.length<=0){
-//            urlStr = UIApplicationOpenSettingsURLString;
-//        }
-//        
-//        if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:urlStr]]){
-//            
-//            if (iOS10){
-//                
-//                //iOS10.0以上  使用的操作
-//                [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlStr] options:@{} completionHandler:nil];
-//                
-//            }else{
-//                
-//                //iOS10.0以下  使用的操作
-//                [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlStr]];
-//                
-//            }
-//            
-//        }
-//
-//    };
-//    
-//    [[UIApplication sharedApplication].keyWindow addSubview:visualEffecVC.view];
-//    
-//}
-//
-//
+//#pragma mark ------  发送app group通知
+//+ (void)postGroupCFNotificaiton:(NSString*)string{
 //
-//#pragma mark ---------------------------------------------------------------- 系统授权类
-////申请摄像头授权
-//+(BOOL)authorizationCarmen{
-//    
-//    NSString *mediaType = AVMediaTypeVideo;
-//    AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:mediaType];
-//    if(authStatus ==AVAuthorizationStatusRestricted){
-//        NSLog(@"Restricted");
-//        return NO;
+//    NSString * notificaitonName = @"OPEN_NOTIFICATION";
+//    CFStringRef strRef = (__bridge CFStringRef)notificaitonName;
+//    CFNotificationCenterRef notification = CFNotificationCenterGetDarwinNotifyCenter ();
+//    //第一种生成参数方法 测试无效
+////    NSDictionary * ocDict = @{@"key":@"123"};
+////    CFDictionaryRef dicRef = (__bridge CFDictionaryRef)ocDict;
+//    //第二种 共享沙河数据
+//    NSUserDefaults* userDefault = [[NSUserDefaults alloc] initWithSuiteName:@"group.com.Oujia.AppAndGame"];
+//    [userDefault setObject:string forKey:@"type"];//主副设备 断开的type
+//    [userDefault synchronize];
+//    //之后发送通知
+//    CFNotificationCenterPostNotification(notification, strRef, NULL,nil, YES);
+//    //
 //
-//    }else if(authStatus == AVAuthorizationStatusDenied){
-//        NSLog(@"Denied");
-//        //应该是这个,如果不允许的话
-//        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:MyLocalizedString(@"Tip")
-//                                                        message:MyLocalizedString(@"Please allow access to the camera in the device \" settings privacy camera -Luftmed\"")
-//                                                       delegate:self
-//                                              cancelButtonTitle:MyLocalizedString(@"Confirm")
-//                                              otherButtonTitles:nil];
-//        [alert show];
-//        return NO;
-//
-//    }else if(authStatus == AVAuthorizationStatusAuthorized){//允许访问
-//        
-//        NSLog(@"Authorized");
-//        return YES;
-//        
-//    }else if(authStatus == AVAuthorizationStatusNotDetermined){
-//        
-//        [AVCaptureDevice requestAccessForMediaType:mediaType completionHandler:^(BOOL granted) {
-//            if(granted){//点击允许访问时调用
-//                
-//                //用户明确许可与否,媒体需要捕获,但用户尚未授予或拒绝许可。
-//                NSLog(@"Granted access to %@", mediaType);
-//                
-//            }else{
-//                
-//                NSLog(@"Not granted access to %@", mediaType);
-//                
-//            }
-//            
-//        }];
-//        
-//        return NO;
-//        
-//    }
-//    
-//    return NO;
-//    
-//}
-//
-//
-//#pragma mark ---------------------------------------------------------------- 正则
-//+ (BOOL)phoneNum:(NSString *)mobileNum{
-//    
-//    if (mobileNum.length != 11){
-//        return NO;
-//    }
-//    /**
-//     * 手机号码:
-//     * 13[0-9], 14[5,7], 15[0, 1, 2, 3, 5, 6, 7, 8, 9], 17[0, 1, 6, 7, 8], 18[0-9]
-//     * 移动号段: 134,135,136,137,138,139,147,150,151,152,157,158,159,170,178,182,183,184,187,188
-//     * 联通号段: 130,131,132,145,155,156,170,171,172,175,176,185,186
-//     * 电信号段: 133,149,153,170,173,177,180,181,189
-//     */
-//    NSString *MOBILE = @"^1(3[0-9]|4[57]|5[0-35-9]|7[0135678]|8[0-9])\\d{8}$";
-//    /**
-//     * 中国移动:China Mobile
-//     * 134,135,136,137,138,139,147,150,151,152,157,158,159,170,178,182,183,184,187,188
-//     */
-//    NSString *CM = @"(^1(3[4-9]|4[7]|5[0-27-9]|7[08]|8[2-478])\\d{8}$";
-//    /**
-//     * 中国联通:China Unicom
-//     * 130,131,132,145,155,156,170,171,172,175,176,185,186
-//     */
-//    NSString *CU = @"(^1(3[0-2]|4[5]|5[56]|701256||8[56])\\d{8}$";
-//    /**
-//     * 中国电信:China Telecom
-//     * 133,149,153,170,173,177,180,181,189
-//     */
-//    NSString *CT = @"^1(3[3]|4[9]|53|7[037]|8[019])\\d{8}$";
-//    NSPredicate *regextestmobile = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", MOBILE];
-//    NSPredicate *regextestcm = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CM];
-//    NSPredicate *regextestcu = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CU];
-//    NSPredicate *regextestct = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", CT];
-//    
-//    if (([regextestmobile evaluateWithObject:mobileNum] == YES)
-//        || ([regextestcm evaluateWithObject:mobileNum] == YES)
-//        || ([regextestct evaluateWithObject:mobileNum] == YES)
-//        || ([regextestcu evaluateWithObject:mobileNum] == YES))
-//    {
-//        return YES;
-//        
-//    }else{
-//        
-//        return NO;
-//    }
-//    
-//}
-//
-////获取部分显示手机格式
-//+ (NSString *)getPhoneText:(NSString *)phoneNum {
-//    NSString *headStr = [phoneNum substringToIndex:3];//截取掉下标2之前的字符串
-//    NSString *backStr = [phoneNum substringFromIndex:7];//截取掉下标6之后的字符串
-//    return [NSString stringWithFormat:@"%@****%@",headStr,backStr];
-//}
-//
-//#pragma mark - ***** 检测是否为邮箱
-//+ (BOOL)emailNum:(NSString *)emailStr{
-//    
-//    NSString *pattern = @"^[a-zA-Z0-9][\\w\\.-]*[a-zA-Z0-9]@[a-zA-Z0-9][\\w\\.-]*[a-zA-Z0-9]\\.[a-zA-Z][a-zA-Z\\.]*[a-zA-Z]$";
-//    NSRegularExpression *regex = [[NSRegularExpression alloc] initWithPattern:pattern options:0 error:nil];
-//    NSArray *results = [regex matchesInString:emailStr options:0 range:NSMakeRange(0, emailStr.length)];
-//    return results.count > 0;
-//    
-//}
-//
-//#pragma mark ---------------------------------------------------------------- 字符串转字典与字典转字符串
-//+ (NSDictionary *)parseJSONStringToNSDictionary:(NSString *)JSONString {
-//    NSData *JSONData = [JSONString dataUsingEncoding:NSUTF8StringEncoding];
-//    NSDictionary *responseJSON = [NSJSONSerialization JSONObjectWithData:JSONData options:NSJSONReadingMutableContainers error:nil];
-//    return responseJSON;
-//}
-//
-//+ (NSArray *)parseJSONStringToNSArray:(NSString *)JSONString {
-//    NSData *JSONData = [JSONString dataUsingEncoding:NSUTF8StringEncoding];
-//    NSArray *responseJSON = [NSJSONSerialization JSONObjectWithData:JSONData options:NSJSONReadingMutableContainers error:nil];
-//    return responseJSON;
-//}
-//
-//+ (NSString*)arrayToJson:(NSArray *)arr
-//{
-//    NSError *parseError = nil;
-//    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:arr options:NSJSONWritingPrettyPrinted error:&parseError];
-//    return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
-//}
-//
-//+ (NSString*)dictionaryToJson:(NSDictionary *)dic{
-//    
-//    NSError *parseError = nil;
-//    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:&parseError];
-//    return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
-//    
-//}
-//
-//
-//#pragma mark ---------------------------------------------------------------- 时间
-////返回当前的日期
-//+(NSString*)returnNowDateString{
-//    
-//    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
-//    // ----------设置你想要的格式,hh与HH的区别:分别表示12小时制,24小时制
-//    //            [formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"];
-//    [formatter setDateFormat:@"yyyyMMdd"];
-//    //现在时间,你可以输出来看下是什么格式
-//    NSDate *datenow = [NSDate date];
-//    //----------将nowDateStr按formatter格式转成nsstring
-//    NSString *nowDateStr = [formatter stringFromDate:datenow];
-//    NSLog(@"nowDateStr =  %@",nowDateStr);
-//    return nowDateStr;
-//    
 //}
-//
-////返回当前的时间
-//+(NSString*)returnNowTimeString{
-//    
-//    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
-//    // ----------设置你想要的格式,hh与HH的区别:分别表示12小时制,24小时制
-//    //            [formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"];
-//    [formatter setDateFormat:@"HHmmss"];
-//    //现在时间,你可以输出来看下是什么格式
-//    NSDate *datenow = [NSDate date];
-//    //----------将nsdate按formatter格式转成nsstring
-//    NSString *nowtimeStr = [formatter stringFromDate:datenow];
-//    NSLog(@"nowtimeStr =  %@",nowtimeStr);
-//    return nowtimeStr;
-//    
-//}
-//
-//+ (NSString *)getStartTimeDate:(NSNumber *)dateTime format:(NSString *)format{
-//    if (format == nil){
-//        format = @"yyyy/MM/dd";
-//    }
-//    NSString *timeS = @"";
-//    if ([[MYFactoryManager returnRealValue:dateTime] length] > 3){
-//        timeS = [dateTime stringValue];
-//        timeS = [timeS substringToIndex:timeS.length-3];
-//        NSTimeInterval time= [timeS doubleValue];//因为时差问题要加8小时 == 28800 sec
-//        NSDate *detaildate=[NSDate dateWithTimeIntervalSince1970:time];
-//        //实例化一个NSDateFormatter对象
-//        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
-//        //设定时间格式,这里可以设置成自己需要的格式 @"yyyy/MM/dd"
-//        [dateFormatter setDateFormat:format];
-//        timeS = [dateFormatter stringFromDate: detaildate];
-//    }
-//    return timeS;
-//}
-//
-//
-//+ (NSString *)getRealTime:(NSString *)dateTime format:(NSString *)format{
-//    
-//    if (format == nil) {
-//        format = @"yyyy-MM-dd HH:mm:ss";
-//    }
-//    if ([[MYFactoryManager returnRealValue:dateTime] length] > 3) {
-//        dateTime = [dateTime substringToIndex:dateTime.length-3];
-//        NSTimeInterval time= [dateTime doubleValue];//因为时差问题要加8小时 == 28800 sec
-//        NSDate *detaildate=[NSDate dateWithTimeIntervalSince1970:time];
-//        //实例化一个NSDateFormatter对象
-//        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
-//        //设定时间格式,这里可以设置成自己需要的格式 @"yyyy/MM/dd"
-//        [dateFormatter setDateFormat:format];
-//        dateTime = [dateFormatter stringFromDate: detaildate];
-//    }
-//    return dateTime;
-//}
-//
-//+ (NSString *)returnRealValue:(id)sendValue {
-//    if ([sendValue isKindOfClass:[NSNull class]] || sendValue == NULL) {
-//        return @"";
-//    }
-//    if ([sendValue isKindOfClass:[NSNumber class]]) {
-//        return [sendValue stringValue];
-//    }
-//    return sendValue;
-//}
-//
-///*处理返回应该显示的时间*/
-//+ (NSString *) returnUploadTime:(NSString *)timeStr
-//{
-//    NSTimeInterval time= [timeStr doubleValue];//因为时差问题要加8小时 == 28800 sec
-//    NSDate *detaildate=[NSDate dateWithTimeIntervalSince1970:time];
-//    //实例化一个NSDateFormatter对象
-//    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
-//    //设定时间格式,这里可以设置成自己需要的格式
-//    [dateFormatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"];
-//    NSString *currentDateStr = [dateFormatter stringFromDate: detaildate];
-//    NSDate *datenow = [NSDate date];
-//    NSDateFormatter * dm = [[NSDateFormatter alloc]init];
-//    //指定输出的格式   这里格式必须是和上面定义字符串的格式相同,否则输出空
-//    [dm setDateFormat:@"YYYY-MM-dd HH:mm:ss"];
-//    NSDate * newdate = [dm dateFromString:currentDateStr];
-//    long dd = (long)[datenow timeIntervalSince1970] - [newdate timeIntervalSince1970];
-//    NSString *timeString=@"";
-//    if (dd/3600<1)
-//    {
-//        timeString = [NSString stringWithFormat:@"%ld", dd/60];
-//        timeString=[NSString stringWithFormat:@"%@分钟前", timeString];
-//    }
-//    if (dd/3600>1&&dd/86400<1)
-//    {
-//        timeString = [NSString stringWithFormat:@"%ld", dd/3600];
-//        timeString=[NSString stringWithFormat:@"%@小时前", timeString];
-//    }
-//    if (dd/86400>1)
-//    {
-//        timeString = [NSString stringWithFormat:@"%ld", dd/86400];
-//        timeString=[NSString stringWithFormat:@"%@天前", timeString];
-//    }
-//    return timeString;
-//}
-//
-//
-//// 返回时间戳
-//+ (NSString *)returnTimestamp:(NSString *)timeStr{
-//    //实例化一个NSDateFormatter对象
-//    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
-//    //设定时间格式,这里可以设置成自己需要的格式
-//    [dateFormatter setDateFormat:@"yyyy-MM-dd"];
-//    NSDate *date = [dateFormatter dateFromString:timeStr];
-//    NSTimeInterval timeSp = [date timeIntervalSince1970];
-//    return [NSString stringWithFormat:@"%f",timeSp];
-//}
-//
-//
-//#pragma mark ---------------------------------------------------------------------------------------- 勒夫曼德
-////16位MD5加密方式 16*2 =32 再截取中间16位
-//+ (NSString *)getMd5_16Bit_String:(NSString *)srcString{
-//
-//    const char *cStr = [srcString UTF8String];
-//    unsigned char digest[CC_MD5_DIGEST_LENGTH];
-//    CC_MD5( cStr, strlen(cStr), digest );
-//    NSMutableString *result = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
-//    for(int i = 0; i < CC_MD5_DIGEST_LENGTH; i++){
-//        [result appendFormat:@"%02x", digest[i]];
-//    }
-//    //32位 加密 取出来
-//    NSString * result_16 = [[result substringToIndex:24] substringFromIndex:8];//即9~25位
-//    
-//    return   [result_16 uppercaseString];
-//    
-//}
-//
-////将十六进制的字符串转换成NSString则可使用如下方式:
-//+ (NSString *)convertHexStrToString:(NSString *)str{
-//    if (!str || [str length] == 0) {
-//        return nil;
-//    }
-//    NSMutableData *hexData = [[NSMutableData alloc] initWithCapacity:8];
-//    NSRange range;
-//    if ([str length] % 2 == 0) {
-//        range = NSMakeRange(0, 2);
-//    } else {
-//        range = NSMakeRange(0, 1);
-//    }
-//    for (NSInteger i = range.location; i < [str length]; i += 2) {
-//        unsigned int anInt;
-//        NSString *hexCharStr = [str substringWithRange:range];
-//        NSScanner *scanner = [[NSScanner alloc] initWithString:hexCharStr];
-//        
-//        [scanner scanHexInt:&anInt];
-//        NSData *entity = [[NSData alloc] initWithBytes:&anInt length:1];
-//        [hexData appendData:entity];
-//        
-//        range.location += range.length;
-//        range.length = 2;
-//    }
-//    NSString *string = [[NSString alloc]initWithData:hexData encoding:NSUTF8StringEncoding];
-//    return string;
-//}
-//
-////将NSString转换成十六进制的字符串则可使用如下方式:
-//+ (NSString *)convertStringToHexStr:(NSString *)str{
-//    if (!str || [str length] == 0) {
-//        return @"";
-//    }
-//    NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding];
-//    
-//    NSMutableString *string = [[NSMutableString alloc] initWithCapacity:[data length]];
-//    
-//    [data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
-//        unsigned char *dataBytes = (unsigned char*)bytes;
-//        for (NSInteger i = 0; i < byteRange.length; i++) {
-//            NSString *hexStr = [NSString stringWithFormat:@"%x", (dataBytes[i]) & 0xff];
-//            if ([hexStr length] == 2) {
-//                [string appendString:hexStr];
-//            } else {
-//                [string appendFormat:@"0%@", hexStr];
-//            }
-//        }
-//    }];
-//    
-//    return string;
-//}
-///**
-// 十六进制转换为二进制
-// @return 二进制数
-// */
-//+ (NSString *)convertDataToHexStr:(NSData *)data
-//{
-//    if (!data || [data length] == 0) {
-//        return @"";
-//    }
-//    NSMutableString *string = [[NSMutableString alloc] initWithCapacity:[data length]];
-//    
-//    [data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
-//        unsigned char *dataBytes = (unsigned char*)bytes;
-//        for (NSInteger i = 0; i < byteRange.length; i++) {
-//            NSString *hexStr = [NSString stringWithFormat:@"%x", (dataBytes[i]) & 0xff];
-//            if ([hexStr length] == 2) {
-//                [string appendString:hexStr];
-//            } else {
-//                [string appendFormat:@"0%@", hexStr];
-//            }
-//        }
-//    }];
-//    return string;
-//}
-//
-//#pragma mark -- 图文混排富文本
-//+(NSAttributedString*)labelAttribute:(NSString *)firstLabelText secondLabelText:(NSString *)secondLabelText{
-//    
-//    NSString* firstStr ;
-//    NSString* secondStr ;
-//    NSString* finalStr ;
-//    
-////    if ([firstLabelText isEqualToString:@"00"]){
-////
-////        firstStr = [NSString stringWithFormat:@"%@",firstLabelText];
-////        secondStr = [NSString stringWithFormat:@"%@",secondLabelText];
-////        finalStr = [NSString stringWithFormat:@"%@   %@",firstStr,secondStr];
-////
-////    }else{
-//    
-//        firstStr = [NSString stringWithFormat:@"%@℃",firstLabelText];
-//        secondStr = [NSString stringWithFormat:@"%@%",secondLabelText];
-//        finalStr = [NSString stringWithFormat:@"%@   %@",firstStr,secondStr];
-////    }
-//    
-//   // 1.创建一个富文本
-//    NSMutableAttributedString *attritube =  [[NSMutableAttributedString alloc] initWithString:finalStr];
-//    
-//    // 修改富文本中的不同文字的样式
-//    // 创建带有图片的富文本--1
-//    NSTextAttachment *temperatureAttch = [[NSTextAttachment alloc] init];
-//    temperatureAttch.bounds = CGRectMake(0, -3.5, 22, 22);
-//    temperatureAttch.image = [UIImage imageNamed:@"myair_temperature_img"];
-//    NSAttributedString *temperatureAttchImage = [NSAttributedString attributedStringWithAttachment:temperatureAttch];
-//    
-//    // 创建带有图片的富文本--2
-//    NSTextAttachment *humidity = [[NSTextAttachment alloc] init];
-//    humidity.bounds = CGRectMake(0, -3.5, 22, 22);
-//    humidity.image = [UIImage imageNamed:@"myair_humidity_img"];
-//    NSAttributedString *humidityImage = [NSAttributedString attributedStringWithAttachment:humidity];
-//    
-//    // 用label的attributedText属性来使用富文本
-//    [attritube insertAttributedString:temperatureAttchImage atIndex:0];// 插入某个位置
-//    [attritube insertAttributedString:humidityImage atIndex:7];// 插入某个位置
-//    
-//    return attritube;
-//    
-//}
-//
-//#pragma mark -- 头部背景视图
-//+(NSString*)changePicturesAccordingToPeriods{
-//    NSString * headImageStr;
-//    NSDateFormatter *formatter = [[NSDateFormatter alloc]init]; //初始化格式器
-//    [formatter setDateFormat:@"HH"];//定义时间为这种格式: YYYY-MM-dd hh:mm:ss
-//    NSString *currentTime = [formatter stringFromDate:[NSDate date]];//将NSDate *对象 转化为 NSString *对象
-//    NSLog(@"当前时间是----%@", currentTime);//控制台打印出当前时间
-////    int time = [currentTime intValue];
-////    if(time>=6&&time<12) {
-////        NSLog(@"上午");
-//        headImageStr = @"bg_outdoor_morning_img";
-//        
-////    }else if (time>=12&&time<17){
-////        NSLog(@"下午");
-////        headImageStr = @"bg_outdoor_afteroom_img";
-////
-////    }else if (time>=17&&time<19){
-////        NSLog(@"傍晚");
-////        headImageStr = @"bg_outdoor_dusk_img";
-////
-////    }else if (time>=19&&time<24){
-////        NSLog(@"晚上");
-////        headImageStr = @"bg_outdoor_night_img";
-////
-////    }else if (time>=0&&time<6){
-////        NSLog(@"凌晨");
-////        headImageStr = @"bg_outdoor_night_img";
-////
-////    }
-//    
-//    return headImageStr;
-//}
-//
-//#pragma mark -- 定位的城市简体转拼音
-//+(NSString *)transform:(NSString *)chinese{
-//    
-//    if (chinese!=nil&&chinese.length>0){
-//        NSMutableString *pinyin = [chinese mutableCopy];
-//        CFStringTransform((__bridge CFMutableStringRef)pinyin, NULL, kCFStringTransformMandarinLatin, NO);//带音标的拼音
-//        CFStringTransform((__bridge CFMutableStringRef)pinyin, NULL, kCFStringTransformStripCombiningMarks, NO);//不带音标的拼音
-//        NSString * strUrl = [pinyin stringByReplacingOccurrencesOfString:@" " withString:@""];
-//        strUrl = [strUrl stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[strUrl substringToIndex:1] uppercaseString]];
-//        NSString *finalStr = [strUrl substringToIndex:[strUrl length] - 3];
-//        NSLog(@"转换过来的拼音的城市名称是:%@", finalStr);
-//        return finalStr;
-//    }else{
-//        return @"No Data";
-//    }
-//
-//}
-//
-//#pragma mark -- 返回机器状态信息
-//+(NSString*)returnStallStr:(NSString*)command deviceinfo:(NSString*)deviceInfo{
-//    
-//    NSString * deviceStatus ;
-//    //开关机
-//    if ([command isEqualToString:@"A0"]) {
-//        
-//        if ([deviceInfo isEqualToString:@"00000000"]) {
-//            
-//            deviceStatus = @"当前是关机";
-//            
-//        }else if ([deviceInfo isEqualToString:@"00000001"]){
-//            
-//            deviceStatus = @"当前是开机";
-//            
-//        }
-//        
-//    }
-//    
-//    //档位
-//    if ([command isEqualToString:@"A4"]){
-//        
-//        deviceStatus = @"当前是Auto档位";
-//
-//    }else if([command isEqualToString:@"A8"]){
-//        
-//        deviceStatus = @"当前是Max档位";
-//        
-//    }else if([command isEqualToString:@"A9"]){
-//        
-//        deviceStatus = @"当前是Sleep档位";
-//        
-//    }else if([command isEqualToString:@"A1"]){//机器当前是 1 2 3
-//        
-//        if ([deviceInfo isEqualToString:@"00000001"]) {
-//            
-//            deviceStatus = @"当前是一档";
-//
-//        }else if ([deviceInfo isEqualToString:@"00000002"]){
-//            
-//            deviceStatus = @"当前是二档";
-//            
-//        }else if ([deviceInfo isEqualToString:@"00000003"]){
-//            
-////            [SVProgressHUD showSuccessWithStatus:@"当前的档位是三档"];
-//            deviceStatus = @"当前是三档";
-//
-//        }
-//        
-//    }
-//    return deviceStatus;
-//}
-//
-//#pragma mark -- 返回室外天气图片
-//+(NSString*)returnWeatherImageStr:(NSString*)deviceInfo{
-//    
-//    NSString * imageString;
-//    
-//    NSString * weatherStr = [deviceInfo substringWithRange:NSMakeRange(5, 3)];
-//    NSString*path =[[NSBundle mainBundle] pathForResource:@"weatherImageDict" ofType:@"plist"];
-//    NSMutableDictionary * dictplist =[[NSMutableDictionary alloc] initWithContentsOfFile:path];
-//    NSMutableDictionary * airImageDict = dictplist[@"airImageDict"];
-////    NSLog(@"path%@",airImageDict);
-//    
-//    for (NSString * key in [airImageDict allKeys]){
-//        
-//        if ([weatherStr isEqualToString:key]){//获取的天气在图片字典中
-//            imageString = [key lowercaseString];//转UI图片小写字母
-//            break;
-//        }
-//        
-//    }
-//    NSLog(@"返回的天气图片 %@  遍历天气字典结果 %@",weatherStr,imageString);
-//
-//    if (imageString.length==0) {
-//        imageString = @"w0";
-//    }
-//    
-//    return imageString;
-//    
-//}
-//
-//#pragma mark -- 室外天气质量
-//+(NSString*)returnOutDoorAqi:(NSInteger)aqiValue{
-//    
-//    NSString * aqi;
-//
-//    if (aqiValue>0&& aqiValue<=50){
-//
-//        NSLog(@"优");
-//        aqi = [NSString stringWithFormat:@"AQI: %@",MyLocalizedString(@"Good")];
-//        
-//    }else if (aqiValue>50&& aqiValue<=100){
-//        
-//        NSLog(@"良");
-//        aqi = [NSString stringWithFormat:@"AQI: %@",MyLocalizedString(@"Average")];
-//
-//    }else if (aqiValue>100&& aqiValue<=150){
-//        
-//        NSLog(@"轻度污染");
-//        aqi = [NSString stringWithFormat:@"AQI: %@",MyLocalizedString(@"Pollution")];
-//
-//    }else if (aqiValue>150&& aqiValue<=200){
-//        
-//        NSLog(@"中度污染");
-//        aqi = [NSString stringWithFormat:@"AQI: %@",MyLocalizedString(@"Moderate Pollution")];
-//
-//    }else if (aqiValue>200&& aqiValue<=300){
-//        
-//        NSLog(@"重度污染");
-//        aqi = [NSString stringWithFormat:@"AQI: %@",MyLocalizedString(@"Heavy Pollution")];
-//
-//    }else if (aqiValue>300){
-//        
-//        NSLog(@"严重污染");
-//        aqi = [NSString stringWithFormat:@"AQI: %@",MyLocalizedString(@"Serious Pollution")];
-//
-//    }else{
-//        
-//        aqi = [NSString stringWithFormat:@"AQI: %@",MyLocalizedString(@"No data")];
-//
-//    }
-//    
-//    return aqi;
-//    
-//}
-//
-//#pragma mark --- 验证报文
-//+(NSString*)authenticationMessage:(NSString*)MessageConent{
-//    
-//    int total = 0;
-//
-//    NSData * data = [MessageConent  dataUsingEncoding:NSUTF8StringEncoding];//字符串 UTF-8编码 转换出来的是10进制数据流
-//
-//    Byte * testByteArr = (Byte *)[data bytes];//16进制数据流 转换成Byte数组 数组里面是10进制数据
-//    
-////        NSLog(@"长度是:%ld",[data length]);//一个字符对应一个长度
-//    
-//    for(int i=0;i<[data length];i++){//转换出来的是10进制数据流
-//        
-////        printf("testByte = %d\n",testByteArr[i]);
-//        total = total+testByteArr[i];
-//        
-//    }
-//    
-//    NSString * back = [MYFactoryManager getHexByDecimal:total];
-//    
-//    NSString * finalStr;
-//    
-//    //截取后面两位
-//    if (back.length==4){
-//        finalStr = [back substringFromIndex:2];
-//    }else{
-//        finalStr = [back substringFromIndex:1];
-//    }
-//    return finalStr;
-//    
-//}
-//
-////十进制转换成16进制字符串
-//+ (NSString *)getHexByDecimal:(NSInteger)decimal{
-//    //3819
-//    NSString *hex =@"";
-//    NSString *letter;
-//    NSInteger number;
-//    for (int i = 0; i<9; i++){
-//        
-//        number = decimal % 16;
-//        decimal = decimal / 16;
-//        switch (number) {
-//                
-//            case 10:
-//                letter =@"A"; break;
-//            case 11:
-//                letter =@"B"; break;
-//            case 12:
-//                letter =@"C"; break;
-//            case 13:
-//                letter =@"D"; break;
-//            case 14:
-//                letter =@"E"; break;
-//            case 15:
-//                letter =@"F"; break;
-//            default:
-//                letter = [NSString stringWithFormat:@"%ld", number];
-//        }
-//        hex = [letter stringByAppendingString:hex];
-//        if (decimal == 0) {
-//            break;
-//        }
-//    }
-//    return hex;
-//}
-//
-//+ (NSString*)getCurrentSSID{
-//    
-//    NSDictionary * ifs = [MYFactoryManager fetchSSIDInfo];;
-//    NSString *ssid = [ifs objectForKey:@"SSID"];
-//    if (ssid.length<=0){
-//        return @"未知网络";
-//    }else{
-//        return ssid;
-//    }
-//    
-//}
-//
-//
-//#pragma mark -- 获取当前链接的wifi - 是不是luftmed
-//+ (BOOL)ifConnetLuftmed{
-//    
-//    BOOL wifiOK = FALSE;
-//    NSDictionary *ifs;
-//    NSString *ssid;
-//    
-//    if (!wifiOK){
-//        
-//        ifs = [MYFactoryManager fetchSSIDInfo];
-//        ssid = [ifs objectForKey:@"SSID"];
-//        
-//        if(ssid!= nil){
-//            
-//            wifiOK= TRUE;
-//            
-//            NSString * tails;
-//            if (ssid.length==12){
-//                tails = [ssid substringWithRange:NSMakeRange(8, 4)];
-//            }
-//            
-//            NSLog(@"当前的SSID是 ========>> %@  %@",ssid,tails);
-//            
-//            if (ssid.length == 12&&[self judgePassWordLegal:tails]){
-//                
-//                if ([ssid hasPrefix:@"luftmed_"]||[ssid hasPrefix:@"luftmed-"]){//当前连接的网络是 luftmed_wifi 协议三判断是否已经配网
-//                    
-//                    return YES;
-//                    
-//                }else{
-//                    
-//                    return NO;
-//                    
-//                }
-//                
-//            }else{
-//                
-//                return NO;
-//            }
-//            
-//        }else{
-//            
-//            return NO;
-//
-//        }
-//        
-//    }
-//    
-//    return NO;
-//    
-//}
-//
-////是否由数字或者字母组成
-//+(BOOL)judgePassWordLegal:(NSString*)ssid{
-//    
-//    NSString *regex = @"^[a-z0-9A-Z]*$";
-//    
-//    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
-//    
-//    if ([predicate evaluateWithObject:ssid] == YES) {
-//        
-//        return YES;
-//        
-//    }else{
-//        
-//        return NO;
-//    }
-//
-//}
-////是否由数字+字母组成
-//+(BOOL)judgePassWordLegalCountOrAZ:(NSString *)ssid{
-//    BOOL result = false;
-//    if ([ssid length] == 4){
-//        // 判断长度大于8位后再接着判断是否同时包含数字和字符
-//        NSString * regex = @"^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,16}$";
-//        NSPredicate *pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
-//        result = [pred evaluateWithObject:ssid];
-//    }
-//    return result;
-//    NSLog(@"result ===> %@",result?@"YES":@"NO");
-//}
-//
-//
-//
-//+(id)fetchSSIDInfo{
-//    
-//    NSArray *ifs = (__bridge_transfer id)CNCopySupportedInterfaces();
-////    NSLog(@"Supported interfaces: %@", ifs);
-//    id info = nil;
-//    for (NSString *ifnam in ifs) {
-////        NSLog(@"遍历到的SSID数据是ifnam--%@",ifnam);
-//        info = (__bridge_transfer id)CNCopyCurrentNetworkInfo((__bridge CFStringRef)ifnam);
-////        NSLog(@"%@ => %@", ifnam, info);
-//        if (info && [info count]) { break; }
-//    }
-//    return info;
-//    
-//}
-//
-//#pragma mark -------------------------------- 获取UDID
-//+(NSString*)getUDIDString{
-//    
-//    NSString *identifierStr = [[[UIDevice currentDevice] identifierForVendor] UUIDString];
-//    NSString * udid = [identifierStr stringByReplacingOccurrencesOfString:@"-" withString:@""];
-//    NSString * udidString = [udid substringToIndex:16];
-////    NSLog(@"udidString = %@",udidString);
-//    return udidString;
-//}
-//
-//#pragma mark --------------------------------- 返回PM25对应的文本
-//+(NSString*)getPM25ValueText:(NSString*)value{
-//    
-//    CGFloat floatValue = [value floatValue];
-//    NSString * text;
-//    //    优    0~35μg/m³
-//    //    良    35~75μg/m³
-//    //    轻度污染    75~115μg/m³
-//    //    中度污染    115~150μg/m³
-//    //    重度污染    150~250μg/m³
-//    //    严重污染    大于250μg/m³及以上
-//    if (floatValue>=0&&floatValue<40){//优
-//        text = MyLocalizedString(@"Good");
-//    }else  if(floatValue>=40&&floatValue<100){//一般
-//        text = MyLocalizedString(@"Average");
-//    }else  if(floatValue>=100&&floatValue<180){//轻度
-//        text = MyLocalizedString(@"Pollution");
-//    }else  if(floatValue>=180&&floatValue<250){//重度
-//        text = MyLocalizedString(@"Moderate Pollution");
-//    }else  if(floatValue>=250&&floatValue<1000){//严重
-//        text = MyLocalizedString(@"Heavy Pollution");
-//    }
-//    return text;
-//    
-//}
-//
-//#pragma mark --- 返回PM25对应的颜色
-//+(UIColor*)getPM25ValueColor:(NSString*)value{
-//    CGFloat floatValue = [value floatValue];
-//    UIColor * color ;
-////    优    0~35μg/m³
-////    良    35~75μg/m³
-////    轻度污染    75~115μg/m³
-////    中度污染    115~150μg/m³
-////    重度污染    150~250μg/m³
-////    严重污染    大于250μg/m³及以上
-//    if (floatValue>=0&&floatValue<40){//优
-//        color = PM25ExcellentColor;
-//    }else  if(floatValue>=40&&floatValue<100){//一般
-//        color = PM25NormalColor;
-//    }else  if(floatValue>=100&&floatValue<180){//轻度
-//        color = PM25LightColor;
-//    }else  if(floatValue>=180&&floatValue<250){//重度
-//        color = PM25SevereColor;
-//    }else  if(floatValue>=250&&floatValue<1000){//严重
-//        color = PM25SeriousColor;
-//    }
-//    return color;
-//}
-//
-//#pragma mark --- 返回PM25 角度
-//+(CGFloat)getPM25TotalAngle:(NSInteger)temp10{
-//    
-//    CGFloat totalAngle;
-//    if (temp10>=0&&temp10<=40){//优秀
-//        CGFloat progress = temp10 /40.0;
-//        CGFloat newAngle = progress * 70;
-//        totalAngle = 55+newAngle;
-//    }else if(temp10>40&&temp10<=99){//一般
-//        CGFloat progress = (temp10-40) /60.0;
-//        CGFloat newAngle = progress * 60;
-//        totalAngle = 55+70+newAngle;
-//    }else if(temp10>99&&temp10<=179){//轻度污染
-//        CGFloat progress = (temp10-100) /80.0;
-//        CGFloat newAngle = progress * 50;
-//        totalAngle = 55+130+newAngle;
-//    }else if(temp10>179&&temp10<=249){//轻度污染
-//        CGFloat progress = (temp10-180) /70.0;
-//        CGFloat newAngle = progress * 60;
-//        totalAngle = 55+180+newAngle;
-//    }else{//严重
-//        CGFloat progress = (temp10-250)/750.0;
-//        CGFloat newAngle = progress * 30;
-//        totalAngle = 55+220+newAngle;
-//    }
-//    
-//    return totalAngle;
-//}
-//
-//#pragma mark --------------------------------- 返回TVOC 文本
-//+(NSString*)getTVOCValueText:(NSString*)value{
-//    NSString * valveString = [NSString stringWithFormat:@"%.2f", [value floatValue]/100];
-//    CGFloat floatValue = [valveString floatValue];
-//    NSString * text;
-//    if (floatValue>=0&&floatValue<2.0){//优
-//        text = MyLocalizedString(@"Good");
-//    }else  if(floatValue>=2.0&&floatValue<4.0){//一般
-//        text = MyLocalizedString(@"Average");
-//    }else  if(floatValue>=4.0&&floatValue<6.0){//轻度
-//        text = MyLocalizedString(@"Pollution");
-//    }else  if(floatValue>=6.0&&floatValue<8.0){//重度
-//        text = MyLocalizedString(@"Moderate Pollution");
-//    }else  if(floatValue>=8.0&&floatValue<9.9){//严重
-//        text = MyLocalizedString(@"Heavy Pollution");
-//    }
-//    return text;
-//}
-//
-//#pragma mark --- 返回TVOC 颜色
-//+(UIColor*)getTVOCValueColor:(NSString*)value{
-//    
-//    NSString * valveString = [NSString stringWithFormat:@"%.2f", [value floatValue]/100];
-//    CGFloat floatValue = [valveString floatValue];
-////    NSLog(@"floatValue  = %f",floatValue);
-//    UIColor * color ;
-//    if (floatValue>=0&&floatValue<2.0){//优
-//        color = PM25ExcellentColor;
-//    }else  if(floatValue>=2.0&&floatValue<4.0){//一般
-//        color = PM25NormalColor;
-//    }else  if(floatValue>=4.0&&floatValue<6.0){//轻度
-//        color = PM25LightColor;
-//    }else  if(floatValue>=6.0&&floatValue<8.0){//重度
-//        color = PM25SevereColor;
-//    }else  if(floatValue>=8.0&&floatValue<9.9){//严重
-//        color = PM25SeriousColor;
-//    }
-//    return color;
-//
-//}
-//
-////返回TVOC真实值
-//+(NSString*)returnRealTVOCValue:(NSString*)value{
-//    
-//    NSString * text = [NSString stringWithFormat:@"%.2f", [value floatValue]/100];
-////    NSLog(@"text = %@",text);
-//    NSString * tail = [text substringWithRange:NSMakeRange(3, 1)];
-//    if ([tail isEqualToString:@"0"]) {
-//        text = [text substringToIndex:3];
-//    }
-////    NSLog(@"tail = %@",tail);
-//    if ([text isEqualToString:@"0.0"]) {
-//        text = @"0";
-//    }
-//   
-//    return text;
-//}
-//
-//
-//#pragma mark ---------------------------------------------------------------- 车载相关
-//+(NSString*)HardDriveVerificationAlgorithm:(NSString*)string_input{
-//    
-//    //    NSString * string_input = @"0380000D00007CEC79EEF51F000106";
-//    //string_input = 指令 + 数据长度 + 流水号 + MAC地址 + 数据
-//    int i = 0;
-//    NSMutableArray * stringArr = [NSMutableArray new];
-//    
-//    while (i<string_input.length-1) {
-//        
-//        NSString * tempStr = [string_input substringWithRange:NSMakeRange(i, 2)];
-//        NSString * temp10 = [NSString stringWithFormat:@"%lu",strtoul([tempStr UTF8String],0,16)];
-//        //NSLog(@"转换出来的10进制数字是 %@ %@",tempStr,temp10);
-//        [stringArr addObject:temp10];
-//        i = i+2;
-//        
-//    }
-//    
-//    //取数组内容-》异或校验算法对比
-//    int sum = 0;
-//    for (NSString * temp10 in stringArr){
-//        int temp = [temp10 intValue];
-//        sum = sum^temp;
-//        
-//    }
-//    
-//    //转16进制
-//    NSString * checkCode = [self getHexByDecimal:sum];
-//    
-//    NSLog(@"int总和转换出来的16进制的字符串是 %d  %@",sum,checkCode);
-//    
-//    if (checkCode.length<2){
-//        checkCode = [NSString stringWithFormat:@"0%@",checkCode];
-//        return checkCode;
-//    }else{
-//        return checkCode;
-//    }
-//    
-//}
-//
-////字符串转16进制数据流
-//+(NSData *)convertHexStrToData:(NSString *)str{
-//    
-//    if (!str || [str length] == 0){
-//        return nil;
-//    }
-//    NSMutableData *hexData = [[NSMutableData alloc] initWithCapacity:8];
-//    NSRange range;
-//    if ([str length] % 2 == 0) {
-//        range = NSMakeRange(0, 2);
-//    } else {
-//        range = NSMakeRange(0, 1);
-//    }
-//    for (NSInteger i = range.location; i < [str length]; i += 2){
-//        
-//        unsigned int anInt;
-//        NSString *hexCharStr = [str substringWithRange:range];
-//        NSScanner *scanner = [[NSScanner alloc] initWithString:hexCharStr];
-//        
-//        [scanner scanHexInt:&anInt];
-//        NSData *entity = [[NSData alloc] initWithBytes:&anInt length:1];
-//        [hexData appendData:entity];
-//        
-//        range.location += range.length;
-//        range.length = 2;
-//        
-//    }
-//    
-//    NSLog(@"发送数据 字符串转16进制数据流 hexdata: %@", hexData);
-//    return hexData;
-//    
-//}
-//
-//+(NSInteger)hexToInt:(NSString*)hex{
-//    
-////    NSLog(@"16转10报错信息 =  %@",hex);
-//    NSString * hexFormatStr = [NSString stringWithFormat:@"%lu",strtoul([hex UTF8String],0,16)];
-//    NSInteger temp10 = [hexFormatStr integerValue];
-//    return temp10;
-//    
-//}
-//
-///*!* @brief 把格式化的JSON格式的字符串转换成字典* @param jsonString JSON格式的字符串* @return 返回字典*/
-////json格式字符串转字典:
-//+ (NSDictionary *)dictionaryWithJsonString:(NSString *)jsonString {
-//    if (jsonString == nil) {
-//        return nil;
-//    }
-//    NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];NSError *err;
-//    NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonDataoptions:NSJSONReadingMutableContainerserror:&err];
-//    if(err) {
-//        NSLog(@"json解析失败:%@",err);
-//        return nil;
-//        
-//    }return dic;
-//    
-//}
-////字典转json格式字符串:
-//+ (NSString*)dictionaryToJson:(NSDictionary *)dic{
-//    NSError *parseError = nil;
-//    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:&parseError];
-//    return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
-//    
-//}
-////NSJSONWritingPrettyPrinted  是有换位符的。如果NSJSONWritingPrettyPrinted 是nil 的话 返回的数据是没有 换位符的
-
 
 
 @end

BIN
SDK/UI/.DS_Store


+ 0 - 286
SDK/UI/AnimationVIew/AnimationView.m

@@ -1,286 +0,0 @@
-//
-//  AnimationVIew.m
-//  luftemd
-//
-//  Created by leon on 2017/11/1.
-//  Copyright © 2017年 林柏显. All rights reserved.
-//
-
-/*************************** 获取屏幕 宽度、高度 ***************************/
-#define SCREEN_WIDTH ([UIScreen mainScreen].bounds.size.width)
-#define SCREEN_HEIGHT ([UIScreen mainScreen].bounds.size.height)
-#define RGBA(a,b,c,d) [UIColor colorWithRed:a/255.0 green:b/255.0 blue:c/255.0 alpha:d]
-
-#define WS(weakSelf)  __weak __typeof(&*self)weakSelf = self;
-
-#import "AnimationView.h"
-#import "MYFactoryManager.h"
-
-
-@implementation AnimationView
-
-+(instancetype)shanreAnimationView{
-    
-    static AnimationView * animationView = nil;
-    static dispatch_once_t onceToken;
-    dispatch_once(&onceToken, ^{
-        animationView =  [AnimationView new];
-    });
-    return animationView;
-    
-}
-
-//-(void)startAnimation{
-//    
-//    self.animationView =  [UIView new];
-//    self.animationView.frame = CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
-//    self.animationView.backgroundColor = RGBA(76, 76, 76, 0.8);
-//    [[UIApplication sharedApplication].keyWindow addSubview:self.animationView];
-//    
-//    //
-//    self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake((SCREEN_WIDTH - 90) / 2,(SCREEN_HEIGHT - 90) / 2, 90, 90)];
-//    [self.animationView addSubview:self.imageView];
-//    
-//    if (self.imageView.isAnimating) return;
-//    // 1.加载所有的动画图片
-//    NSMutableArray *images = [NSMutableArray array];
-//    
-//    for (int i = 0 ; i<60; i++){
-//        
-//        NSString * filename = nil;
-//        // 计算文件名
-//        if (i < 10){
-//            filename = [NSString stringWithFormat:@"linking000%d",i];
-//        } else {
-//            filename = [NSString stringWithFormat:@"linking00%d",i];
-//        }
-//        //        NSLog(@"filename = %@",filename);
-//        UIImage *image = [UIImage imageNamed:filename];
-//        // 添加图片到数组中
-//        [images addObject:image];
-//        
-//    }
-//    
-//    self.imageView.animationImages = images;
-//    // 2.设置播放次数(1次)
-//    self.imageView.animationRepeatCount = 0;
-//    // 3.设置播放时间
-//    self.imageView.animationDuration = images.count * 0.1;
-//    [self.imageView startAnimating];
-//
-//}
-//
-////label显示
-//-(void)startAnimationWithAnimationLabel:(NSString*)title{
-//    
-//    //蒙层背景
-//    self.animationView =  [UIView new];
-//    self.animationView.frame = CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
-//    self.animationView.backgroundColor = RGBA(76, 76, 76, 0.8);
-//    [[UIApplication sharedApplication].keyWindow addSubview:self.animationView];
-//        
-//    //白底背景
-//    self.backView = [[UIView alloc] initWithFrame:CGRectMake((SCREEN_WIDTH - 180) / 2,(SCREEN_HEIGHT - 180) / 2, 180, 180)];
-//    self.backView.backgroundColor = [UIColor whiteColor];
-//    [MYFactoryManager clipsToBoundsWithView:self.backView Radius:10];
-//    [self.animationView addSubview:self.backView];
-//    
-//    //动画imageview
-//    self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(30,10,120, 120)];
-//    [self.backView addSubview:self.imageView];
-//
-//    if (self.imageView.isAnimating) return;
-//    // 1.加载所有的动画图片
-//    NSMutableArray *images = [NSMutableArray array];
-//
-//    for (int i = 0; i<60; i++){
-//        NSString *filename = nil;
-//        // 计算文件名
-//        if (i < 10){
-//            filename = [NSString stringWithFormat:@"linking000%d",i];
-//        } else {
-//            filename = [NSString stringWithFormat:@"linking00%d",i];
-//        }
-//        //        NSLog(@"filename = %@",filename);
-//        UIImage *image = [UIImage imageNamed:filename];
-//        // 添加图片到数组中
-//        [images addObject:image];
-//    }
-//    self.imageView.animationImages = images;
-//    // 2.设置播放次数(1次)
-//    self.imageView.animationRepeatCount = 0;
-//    // 3.设置播放时间
-//    self.imageView.animationDuration = images.count * 0.1;
-//    [self.imageView startAnimating];
-//
-//    //tip
-//    self.animationLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 140,180, 40)];
-//    self.animationLabel.text = title;
-//    self.animationLabel.textColor = [UIColor whiteColor];
-//    self.animationLabel.font = [UIFont systemFontOfSize:12];
-//    self.animationLabel.textAlignment = NSTextAlignmentCenter;
-//    self.animationLabel.backgroundColor = [UIColor whiteColor];
-//    [self.backView addSubview:self.animationLabel];
-//
-//}
-//
-////倒计时按钮显示
-//-(void)startAnimationWithCountButton{
-//    
-//    //蒙层背景
-//    self.animationView =  [UIView new];
-//    self.animationView.frame = CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
-//    self.animationView.backgroundColor = RGBA(76, 76, 76, 0.8);
-//    [[UIApplication sharedApplication].keyWindow addSubview:self.animationView];
-//    
-//    //白底背景
-//    self.backView = [[UIView alloc] initWithFrame:CGRectMake((SCREEN_WIDTH - 180) / 2,(SCREEN_HEIGHT - 180) / 2, 180, 180)];
-//    self.backView.backgroundColor = [UIColor whiteColor];
-//    [MYFactoryManager clipsToBoundsWithView:self.backView Radius:10];
-//    [self.animationView addSubview:self.backView];
-//    
-//    //动画imageview
-//    self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake(30,10,120, 120)];
-//    [self.backView addSubview:self.imageView];
-//    
-//    if (self.imageView.isAnimating) return;
-//    // 1.加载所有的动画图片
-//    NSMutableArray *images = [NSMutableArray array];
-//    
-//    for (int i = 0; i<60; i++){
-//        NSString *filename = nil;
-//        // 计算文件名
-//        if (i < 10){
-//            filename = [NSString stringWithFormat:@"linking000%d",i];
-//        } else {
-//            filename = [NSString stringWithFormat:@"linking00%d",i];
-//        }
-//        //        NSLog(@"filename = %@",filename);
-//        UIImage *image = [UIImage imageNamed:filename];
-//        // 添加图片到数组中
-//        [images addObject:image];
-//    }
-//    self.imageView.animationImages = images;
-//    // 2.设置播放次数(1次)
-//    self.imageView.animationRepeatCount = 0;
-//    // 3.设置播放时间
-//    self.imageView.animationDuration = images.count*0.1;
-//    [self.imageView startAnimating];
-//    
-//    self.countButton = [UIButton buttonWithType:UIButtonTypeCustom];
-//    self.countButton.frame = CGRectMake(0, 140,180, 40);
-//    self.countButton.titleLabel.font = [UIFont systemFontOfSize:12];;
-//    self.countButton.titleLabel.textAlignment = NSTextAlignmentCenter;
-//    [self.countButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
-//    self.countButton.backgroundColor = [UIColor whiteColor];
-//    self.countButton.userInteractionEnabled = NO;
-//    [self.backView addSubview:self.countButton];
-//
-//    __block int timeout = 59; //倒计时时间
-//    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
-//    dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,queue);
-//    dispatch_source_set_timer(_timer,dispatch_walltime(NULL, 0),1.0*NSEC_PER_SEC, 0); //每秒执行
-//    dispatch_source_set_event_handler(_timer, ^{
-//        if(timeout<=0){ //倒计时结束,关闭
-//            dispatch_source_cancel(_timer);
-//            dispatch_async(dispatch_get_main_queue(), ^{
-//
-//            });
-//        }else{
-//            
-//            int seconds = timeout % 60;
-//            NSString *strTime = [NSString stringWithFormat:@"%.2d", seconds];
-//            dispatch_async(dispatch_get_main_queue(), ^{
-//                [self.countButton setTitle:[NSString stringWithFormat:@"%@%@s..",@"蓝牙连接丢失...",strTime] forState:UIControlStateNormal];
-//            });
-//            timeout--;
-//        }
-//    });
-//    dispatch_resume(_timer);
-//    
-//}
-
--(void)stopAnimation{
-    
-//    if (self.imageView.isAnimating){
-        
-        [self.imageView stopAnimating];
-        [self.animationView removeFromSuperview];
-        [self.backView removeFromSuperview];
-        [self.imageView removeFromSuperview];
-        [self.animationLabel removeFromSuperview];
-        [self.countButton removeFromSuperview];
-        
-//    }
-    
-    [self pauseLayer:self.imageView.layer];
-    
-}
-
-//初始化小风扇动画
--(void)addAnimation{
-    
-    if (self.animationView!=nil){
-        [self stopAnimation];
-    }
-    
-    self.animationView =  [UIView new];
-    self.animationView.frame = CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
-    self.animationView.backgroundColor = RGBA(76, 76, 76, 0.8);
-    [[UIApplication sharedApplication].keyWindow addSubview:self.animationView];
-    
-    //
-    self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake((SCREEN_WIDTH - 90) / 2,(SCREEN_HEIGHT - 90) / 2, 90, 90)];
-    self.imageView.image = [UIImage imageNamed:@"loading"];
-    [self.animationView addSubview:self.imageView];
-    
-    //tip
-    self.animationLabel = [[UILabel alloc] initWithFrame:CGRectMake((SCREEN_WIDTH - 90) / 2, (SCREEN_HEIGHT - 90)/2+90+10,180, 40)];
-//    self.animationLabel.text = @"链接鞋子...";
-    self.animationLabel.textColor = [UIColor whiteColor];
-    self.animationLabel.font = [UIFont systemFontOfSize:12];
-    self.animationLabel.textAlignment = NSTextAlignmentCenter;
-    self.animationLabel.backgroundColor = [UIColor clearColor];
-    [self.animationView addSubview:self.animationLabel];
-    
-    //添加旋转动画
-    _rotationAnimation = [self rotationDurTime:2 angle:360.f direction:-1 repeatCount:MAXFLOAT];
-    _rotationAnimation.delegate = self;
-    _rotationAnimation.removedOnCompletion = NO;
-    [_rotationAnimation setRepeatCount:HUGE_VALF];
-    _rotationAnimation.speed = 1;
-    [self.imageView.layer addAnimation:self.rotationAnimation forKey:@"rotate"];
-    
-    WS(ws);
-    //链接超时
-    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(15 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
-        [ws stopAnimation];
-    });
-}
-
-//暂停layer上面的动画
--(void)pauseLayer:(CALayer*)layer{
-    
-    CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
-    layer.speed = 0.0;
-    layer.timeOffset = pausedTime;
-    
-}
-
-//周期时间 角度 方向 重复次数
--(CABasicAnimation *)rotationDurTime:(float)durTime angle:(float)angle direction:(int)direction repeatCount:(int)repeatCount{
-    
-    CABasicAnimation* animation  = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
-//    animation.fromValue = [NSNumber numberWithFloat:0.f];
-    animation.toValue = [NSNumber numberWithFloat:M_PI];
-    animation.duration= durTime;
-    animation.cumulative= YES;//是否累加
-    animation.removedOnCompletion=NO;
-    animation.fillMode =kCAFillModeForwards;
-    animation.autoreverses = NO;//自动逆转
-    animation.repeatCount = repeatCount;
-    return animation;
-    
-}
-
-@end

+ 5 - 8
SDK/UI/AnimationVIew/AnimationView.h → SDK/UI/AnimationVIew/MainLoadingView.h

@@ -1,15 +1,15 @@
 //
-//  AnimationVIew.h
-//  luftemd
+//  MainLoadingView.h
+//  Unity-iPhone
 //
-//  Created by leon on 2017/11/1.
-//  Copyright © 2017年 林柏显. All rights reserved.
+//  Created by duowan123 on 2022/8/2.
 //
 
+
 #import <UIKit/UIKit.h>
 #import <QuartzCore/QuartzCore.h>
 
-@interface AnimationView : UIView<CAAnimationDelegate>
+@interface MainLoadingView : UIView<CAAnimationDelegate>
 
 @property(nonatomic,strong)UIView * animationView;
 @property(nonatomic,strong)UIView * backView;
@@ -20,9 +20,6 @@
 
 +(instancetype)shanreAnimationView;
 
-//-(void)startAnimation;
-//-(void)startAnimationWithAnimationLabel:(NSString*)title;
-//-(void)startAnimationWithCountButton;
 
 -(void)stopAnimation;
 

+ 116 - 0
SDK/UI/AnimationVIew/MainLoadingView.m

@@ -0,0 +1,116 @@
+//
+//  MainLoadingView.m
+//  Unity-iPhone
+//
+//  Created by duowan123 on 2022/8/2.
+//
+
+/*************************** 获取屏幕 宽度、高度 ***************************/
+#define SCREEN_WIDTH ([UIScreen mainScreen].bounds.size.width)
+#define SCREEN_HEIGHT ([UIScreen mainScreen].bounds.size.height)
+#define RGBA(a,b,c,d) [UIColor colorWithRed:a/255.0 green:b/255.0 blue:c/255.0 alpha:d]
+
+#define WS(weakSelf)  __weak __typeof(&*self)weakSelf = self;
+
+#import "MainLoadingView.h"
+#import "MYFactoryManager.h"
+
+@implementation MainLoadingView
+
++(instancetype)shanreAnimationView{
+    
+    static MainLoadingView * animationView = nil;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        animationView =  [MainLoadingView new];
+    });
+    return animationView;
+    
+}
+
+
+-(void)stopAnimation{
+    
+//    if (self.imageView.isAnimating){
+        
+        [self.imageView stopAnimating];
+        [self.animationView removeFromSuperview];
+        [self.backView removeFromSuperview];
+        [self.imageView removeFromSuperview];
+        [self.animationLabel removeFromSuperview];
+        [self.countButton removeFromSuperview];
+        
+//    }
+    
+    [self pauseLayer:self.imageView.layer];
+    
+}
+
+//初始化动画
+-(void)addAnimation{
+    
+    if (self.animationView!=nil){
+        [self stopAnimation];
+    }
+    
+    self.animationView =  [UIView new];
+    self.animationView.frame = CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+    self.animationView.backgroundColor = RGBA(76, 76, 76, 0.8);
+    [[UIApplication sharedApplication].keyWindow addSubview:self.animationView];
+    
+    //
+    self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake((SCREEN_WIDTH - 90) / 2,(SCREEN_HEIGHT - 90) / 2, 90, 90)];
+    self.imageView.image = [MYFactoryManager imageString:@"loading"];
+    [self.animationView addSubview:self.imageView];
+    
+    //tip
+    self.animationLabel = [[UILabel alloc] initWithFrame:CGRectMake((SCREEN_WIDTH - 90) / 2, (SCREEN_HEIGHT - 90)/2+90+10,180, 40)];
+//    self.animationLabel.text = @"链接鞋子...";
+    self.animationLabel.textColor = [UIColor whiteColor];
+    self.animationLabel.font = [UIFont systemFontOfSize:12];
+    self.animationLabel.textAlignment = NSTextAlignmentCenter;
+    self.animationLabel.backgroundColor = [UIColor clearColor];
+    [self.animationView addSubview:self.animationLabel];
+    
+    //添加旋转动画
+    _rotationAnimation = [self rotationDurTime:2 angle:360.f direction:-1 repeatCount:MAXFLOAT];
+    _rotationAnimation.delegate = self;
+    _rotationAnimation.removedOnCompletion = NO;
+    [_rotationAnimation setRepeatCount:HUGE_VALF];
+    _rotationAnimation.speed = 1;
+    [self.imageView.layer addAnimation:self.rotationAnimation forKey:@"rotate"];
+    
+    WS(ws);
+    //链接超时
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(15 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+        [ws stopAnimation];
+    });
+    
+}
+
+//暂停layer上面的动画
+-(void)pauseLayer:(CALayer*)layer{
+    
+    CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
+    layer.speed = 0.0;
+    layer.timeOffset = pausedTime;
+    
+}
+
+//周期时间 角度 方向 重复次数
+-(CABasicAnimation *)rotationDurTime:(float)durTime angle:(float)angle direction:(int)direction repeatCount:(int)repeatCount{
+    
+    CABasicAnimation* animation  = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
+//    animation.fromValue = [NSNumber numberWithFloat:0.f];
+    animation.toValue = [NSNumber numberWithFloat:M_PI];
+    animation.duration= durTime;
+    animation.cumulative= YES;//是否累加
+    animation.removedOnCompletion=NO;
+    animation.fillMode =kCAFillModeForwards;
+    animation.autoreverses = NO;//自动逆转
+    animation.repeatCount = repeatCount;
+    return animation;
+    
+}
+
+@end

+ 30 - 0
SDK/UI/AnimationVIew/ViceLoadingView.h

@@ -0,0 +1,30 @@
+//
+//  ViceLoadingView.h
+//  Unity-iPhone
+//
+//  Created by duowan123 on 2022/8/2.
+//
+
+#import <UIKit/UIKit.h>
+#import <QuartzCore/QuartzCore.h>
+
+@interface ViceLoadingView : UIView<CAAnimationDelegate>
+
+@property(nonatomic,strong)UIView * animationView;
+@property(nonatomic,strong)UIView * backView;
+@property(nonatomic ,strong) UIImageView *imageView;
+@property(nonatomic,strong)UILabel * animationLabel;
+@property(nonatomic,strong)UIButton * countButton;
+
+
++(instancetype)shanreAnimationView;
+
+
+-(void)stopAnimation;
+
+-(void)addAnimation;
+
+//动画
+@property (nonatomic , strong) CABasicAnimation * rotationAnimation;//旋转
+
+@end

+ 116 - 0
SDK/UI/AnimationVIew/ViceLoadingView.m

@@ -0,0 +1,116 @@
+//
+//  ViceLoadingView.m
+//  Unity-iPhone
+//
+//  Created by duowan123 on 2022/8/2.
+//
+
+/*************************** 获取屏幕 宽度、高度 ***************************/
+#define SCREEN_WIDTH ([UIScreen mainScreen].bounds.size.width)
+#define SCREEN_HEIGHT ([UIScreen mainScreen].bounds.size.height)
+#define RGBA(a,b,c,d) [UIColor colorWithRed:a/255.0 green:b/255.0 blue:c/255.0 alpha:d]
+
+#define WS(weakSelf)  __weak __typeof(&*self)weakSelf = self;
+
+#import "ViceLoadingView.h"
+#import "MYFactoryManager.h"
+
+@implementation ViceLoadingView
+
++(instancetype)shanreAnimationView{
+    
+    static ViceLoadingView * animationView = nil;
+    static dispatch_once_t onceToken;
+    dispatch_once(&onceToken, ^{
+        animationView =  [ViceLoadingView new];
+    });
+    return animationView;
+    
+}
+
+
+-(void)stopAnimation{
+    
+//    if (self.imageView.isAnimating){
+        
+        [self.imageView stopAnimating];
+        [self.animationView removeFromSuperview];
+        [self.backView removeFromSuperview];
+        [self.imageView removeFromSuperview];
+        [self.animationLabel removeFromSuperview];
+        [self.countButton removeFromSuperview];
+        
+//    }
+    
+    [self pauseLayer:self.imageView.layer];
+    
+}
+
+//初始化动画
+-(void)addAnimation{
+    
+    if (self.animationView!=nil){
+        [self stopAnimation];
+    }
+    
+    self.animationView =  [UIView new];
+    self.animationView.frame = CGRectMake(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+    self.animationView.backgroundColor = RGBA(76, 76, 76, 0.8);
+    [[UIApplication sharedApplication].keyWindow addSubview:self.animationView];
+    
+    //
+    self.imageView = [[UIImageView alloc] initWithFrame:CGRectMake((SCREEN_WIDTH - 90) / 2,(SCREEN_HEIGHT - 90) / 2, 90, 90)];
+    self.imageView.image = [MYFactoryManager imageString:@"loading"];
+    [self.animationView addSubview:self.imageView];
+    
+    //tip
+    self.animationLabel = [[UILabel alloc] initWithFrame:CGRectMake((SCREEN_WIDTH - 90) / 2, (SCREEN_HEIGHT - 90)/2+90+10,180, 40)];
+//    self.animationLabel.text = @"链接鞋子...";
+    self.animationLabel.textColor = [UIColor whiteColor];
+    self.animationLabel.font = [UIFont systemFontOfSize:12];
+    self.animationLabel.textAlignment = NSTextAlignmentCenter;
+    self.animationLabel.backgroundColor = [UIColor clearColor];
+    [self.animationView addSubview:self.animationLabel];
+    
+    //添加旋转动画
+    _rotationAnimation = [self rotationDurTime:2 angle:360.f direction:-1 repeatCount:MAXFLOAT];
+    _rotationAnimation.delegate = self;
+    _rotationAnimation.removedOnCompletion = NO;
+    [_rotationAnimation setRepeatCount:HUGE_VALF];
+    _rotationAnimation.speed = 1;
+    [self.imageView.layer addAnimation:self.rotationAnimation forKey:@"rotate"];
+    
+    WS(ws);
+    //链接超时
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(15 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
+        [ws stopAnimation];
+    });
+    
+}
+
+//暂停layer上面的动画
+-(void)pauseLayer:(CALayer*)layer{
+    
+    CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
+    layer.speed = 0.0;
+    layer.timeOffset = pausedTime;
+    
+}
+
+//周期时间 角度 方向 重复次数
+-(CABasicAnimation *)rotationDurTime:(float)durTime angle:(float)angle direction:(int)direction repeatCount:(int)repeatCount{
+    
+    CABasicAnimation* animation  = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
+//    animation.fromValue = [NSNumber numberWithFloat:0.f];
+    animation.toValue = [NSNumber numberWithFloat:M_PI];
+    animation.duration= durTime;
+    animation.cumulative= YES;//是否累加
+    animation.removedOnCompletion=NO;
+    animation.fillMode =kCAFillModeForwards;
+    animation.autoreverses = NO;//自动逆转
+    animation.repeatCount = repeatCount;
+    return animation;
+    
+}
+
+@end

+ 2 - 2
SDK/UI/SearchDeviceViewController.h → SDK/UI/CarouselView/SearchDeviceViewController.h

@@ -16,8 +16,8 @@
 @property (strong,nonatomic)CBPeripheral * currentPeripheral;
 
 @property (copy,nonatomic)void(^connectDeviceBlock)(CBPeripheral * peripheral);
-
-@property (nonatomic, copy)void(^searchDeviceTask)();
+//
+@property (copy,nonatomic)void(^closeBlock)();
 
 //
 -(void)reloadData;

+ 67 - 92
SDK/UI/SearchDeviceViewController.m → SDK/UI/CarouselView/SearchDeviceViewController.m

@@ -7,19 +7,17 @@
 
 #import "SearchDeviceViewController.h"
 
-#import "TXCarouselView.h"
 #import "ShoesCarouselView.h"
 
 @interface SearchDeviceViewController ()<ConnectDeviceDelegate>
 //
 @property (strong, nonatomic)ShoesCarouselView * shoesCarouselView;
-@property (nonatomic, strong) NSMutableArray *array;
-
 //button
 @property(nonatomic,strong)UIButton * nextButton;//
 @property(nonatomic,strong)UIButton * lastButton;//
-@property(nonatomic,strong)UIButton * searchButton;//
+@property(nonatomic,strong)UIButton * cancelButton;//
 @property(nonatomic,strong)UIButton * connectButton;//
+@property (nonatomic,strong)UIButton * clearnButton;//清理缓存
 
 //留白
 @property(nonatomic,strong)NoDeviceTip * tipView;
@@ -31,7 +29,6 @@
 -(void)viewDidLoad{
     
     [super viewDidLoad];
-    
     [self initUI];
     
 }
@@ -53,7 +50,7 @@
     }];
     [self.view addSubview:visualV];
     
-    //留白
+    //无设备
     [self.view addSubview:self.tipView];
         
     //设备列表
@@ -63,12 +60,6 @@
     [self.view addSubview:self.shoesCarouselView];
     self.shoesCarouselView.delegate = self;
     
-    //好友列表
-//    self.carouselView  = [[TXCarouselView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_WIDTH-300, SCREEN_HEIGHT-150)];
-//    self.carouselView.centerX = self.view.centerX;
-//    self.carouselView.centerY = self.view.centerY-20;
-//    [self.view addSubview:self.carouselView];
-    
     //上一个
     self.nextButton = [UIButton buttonWithType:UIButtonTypeSystem];
     self.nextButton.frame = CGRectMake(0, 0, SCALEoefficient(16), SCALEoefficient(32));
@@ -90,70 +81,41 @@
     self.lastButton.backgroundColor = [UIColor clearColor];
     
     //关闭弹窗
-    self.searchButton = [UIButton buttonWithType:UIButtonTypeCustom];
-    self.searchButton.frame = CGRectMake(SCREEN_WIDTH/2-SCALEoefficient(160)-20, self.shoesCarouselView.bottom-10, SCALEoefficient(160), SCALEoefficient(40));
-    [self.searchButton setTitle:@"关闭弹窗" forState:UIControlStateNormal];
-    [self.searchButton setImage:[MYFactoryManager imageString:@"gamepop_close"] forState:UIControlStateNormal];
-    [self.searchButton setFont: [UIFont systemFontOfSize: SCALEoefficient(14)]];
-    [self.searchButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
-    [self.view addSubview:self.searchButton];
-    [self.searchButton addTarget:self action:@selector(close) forControlEvents:UIControlEventTouchUpInside];
-    self.searchButton.backgroundColor = [UIColor whiteColor];
-    self.searchButton.layer.masksToBounds = YES;
-    self.searchButton.layer.cornerRadius = SCALEoefficient(20);
-    [self.searchButton setImageEdgeInsets:UIEdgeInsetsMake(0, SCALEoefficient(-15), 0, 0)];
-//    self.searchButton.imageView.contentMode = UIViewContentModeScaleAspectFill;
-    
-    //链接设备
-    self.connectButton = [UIButton buttonWithType:UIButtonTypeCustom];
-    self.connectButton.frame = CGRectMake(SCREEN_WIDTH/2+20, self.shoesCarouselView.bottom-10, SCALEoefficient(160), SCALEoefficient(40));
-    [self.connectButton setTitle:@"连接设备" forState:UIControlStateNormal];
-    [self.connectButton setImage:[MYFactoryManager imageString:@"gamepop_determine"] forState:UIControlStateNormal];
-    [self.connectButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
-    [self.connectButton setFont: [UIFont systemFontOfSize: SCALEoefficient(14)]];
-    [self.view addSubview:self.connectButton];
-    [self.connectButton addTarget:self action:@selector(selectedDeviceAction) forControlEvents:UIControlEventTouchUpInside];
-    self.connectButton.backgroundColor = [UIColor colorWithRed:255/255.0 green:221/255.0 blue:0/255.0 alpha:1.0];
-    self.connectButton.layer.masksToBounds = YES;
-    self.connectButton.layer.cornerRadius = SCALEoefficient(20);
-    [self.connectButton setImageEdgeInsets:UIEdgeInsetsMake(0, SCALEoefficient(-15), 0, 0)];
-//    self.connectButton.imageView.contentMode = UIViewContentModeScaleAspectFit;
+    self.cancelButton = [UIButton buttonWithType:UIButtonTypeCustom];
+    self.cancelButton.frame = CGRectMake(SCREEN_WIDTH-SCALEoefficient(100+20),SCALEoefficient(15), SCALEoefficient(100), SCALEoefficient(30));
+    [self.cancelButton setTitle:@"左踮脚 · 返回" forState:UIControlStateNormal];
+    [self.cancelButton setImage:[MYFactoryManager imageString:@"gamepop_close_notes"] forState:UIControlStateNormal];
+    [self.cancelButton setFont: [UIFont boldSystemFontOfSize: SCALEoefficient(12)]];
+    [self.cancelButton.titleLabel setTextColor:[UIColor whiteColor]];
+    self.cancelButton.backgroundColor = [UIColor clearColor];
+    [self.cancelButton setImageEdgeInsets:UIEdgeInsetsMake(0, SCALEoefficient(-10), 0, 0)];
+    [self.cancelButton addTarget:self action:@selector(closeAction) forControlEvents:UIControlEventTouchUpInside];
+    [self.view addSubview:self.cancelButton];
     
-    NSArray * array = @[@"gamepop_leftarrow_notes",@"gamepop_rihgtarrow_notes",@"gamepop_close_notes",@"gamepop_determine_notes"];
-    NSArray * titleArray = @[@"左踩 · 上一个",@"右踩 · 下一个",@"左垫脚 · 关闭",@"右垫脚 · 确认"];
+    //隐藏的清理缓存的按钮
+    self.clearnButton = [UIButton buttonWithType:UIButtonTypeCustom];
+    self.clearnButton.frame = CGRectMake(0, SCREEN_HEIGHT-SCALEoefficient(30)-SCALEoefficient(25), SCALEoefficient(60), SCALEoefficient(25));
+    self.clearnButton.backgroundColor = [UIColor clearColor];
+    [self.clearnButton addTarget:self action:@selector(clearCacheWithFilePath) forControlEvents:UIControlEventTouchUpInside];
+    [self.view addSubview:self.clearnButton];
 
-    for (int i =0; i<4; i++){
-        UIButton * searchButton = [UIButton buttonWithType:UIButtonTypeCustom];
-        searchButton.frame = CGRectMake(SCREEN_WIDTH-SCALEoefficient(62+20+20)*(4-i),SCALEoefficient(23), SCALEoefficient(62+20), SCALEoefficient(20));
-        [searchButton setTitle:titleArray[i] forState:UIControlStateNormal];
-        [searchButton setImage:[MYFactoryManager imageString:array[i]] forState:UIControlStateNormal];
-        [searchButton setFont: [UIFont boldSystemFontOfSize: SCALEoefficient(10)]];
-        [searchButton.titleLabel setTextColor:[UIColor whiteColor]];
-        [self.view addSubview:searchButton];
-//        searchButton.tag = i;
-//        [searchButton addTarget:self action:@selector(mapBtnClick:) forControlEvents:UIControlEventTouchUpInside];
-//        searchButton.backgroundColor = [UIColor yellowColor];
-        [searchButton setImageEdgeInsets:UIEdgeInsetsMake(0, SCALEoefficient(-10), 0, 0)];
-//        searchButton.imageView.contentMode = UIViewContentModeScaleAspectFill;
+    NSArray * array = @[@"gamepop_leftarrow_notes",@"gamepop_rihgtarrow_notes",@"gamepop_determine_notes"];
+    NSArray * titleArray = @[@"左踏 · 上一个",@"右踏 · 下一个",@"右踮脚 · 确认"];
+    for (int i =0; i<3; i++){
+        UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
+//        button.frame = CGRectMake(SCREEN_WIDTH-SCALEoefficient(62+20+20)*(4-i),SCALEoefficient(23), SCALEoefficient(62+20), SCALEoefficient(20));
+        button.frame = CGRectMake(SCREEN_WIDTH/3*i,SCREEN_HEIGHT-SCALEoefficient(30), SCREEN_WIDTH/3, SCALEoefficient(30));
+        [button setTitle:titleArray[i] forState:UIControlStateNormal];
+        [button setImage:[MYFactoryManager imageString:array[i]] forState:UIControlStateNormal];
+        [button setFont: [UIFont boldSystemFontOfSize: SCALEoefficient(10)]];
+        [button.titleLabel setTextColor:[UIColor whiteColor]];
+//        button.tag = i;
+        button.backgroundColor = [UIColor blackColor];
+        [button setImageEdgeInsets:UIEdgeInsetsMake(0, SCALEoefficient(-10), 0, 0)];
+        //        [searchButton addTarget:self action:@selector(mapBtnClick:) forControlEvents:UIControlEventTouchUpInside];
+        [self.view addSubview:button];
     }
     
-//    NSArray *arrayStr = [NSArray arrayWithObjects:
-//                         @"1111111111111111111111111111111111111111111111",
-//                         @"2222222222222222222222222222222222222222222222",
-//                         @"3333333333333333333333333333333333333333333333",
-//                         @"4444444444444444444444444444444444444444444444",
-//                         @"5555555555555555555555555555555555555555555555",
-//                         nil];
-//    for (int i = 0; i<arrayStr.count; i++){
-//        TXCarouselCellModel *model = [[TXCarouselCellModel alloc]init];
-//        model.imageUrl = [NSString stringWithFormat:@"zongshujidaowojia%d",i+1];
-//        model.titleStr = arrayStr[i];
-//        model.newsId = i;
-//        [self.array addObject:model];
-//    }
-//    [self.shoesCarouselView setArrayData:arrayStr];
-//    [self.carouselView setArrayData:arrayStr];
-    
 }
 
 #pragma mark -------------- 外部事件
@@ -162,10 +124,10 @@
     
     NSMutableArray * dataArr = [NSMutableArray new];
     for (int i = 0; i<self.deviceArray.count; i++){
-        TXCarouselCellModel *model = [[TXCarouselCellModel alloc]init];
-        model.newsId = i;
+        ShoesPeripheralMolde *model = [[ShoesPeripheralMolde alloc]init];
+        model.numberId = i;
         model.peripheral = self.deviceArray[i];
-        NSLog(@"model.peripheral === >> %@",model.peripheral.name);
+//        NSLog(@"model.peripheral === >> %@",model.peripheral.name);
         [dataArr addObject:model];
     }
     [self.shoesCarouselView setArrayData:dataArr];
@@ -185,22 +147,22 @@
         
     }else if(interaction == 3){//左踩 -- 选中上一个设备
         
-        [self nextAction];
-        
-    }else if(interaction == 4){//右踩 -- 选中下一个设备
-        
         [self lastAction];
+
+    }else if(interaction == 4){//右踩 -- 选中下一个设备
         
-    }else if(interaction == 5){//左垫脚 -- 关闭弹窗
+        [self nextAction];
+
+    }else if(interaction == 6){//左垫脚 -- 关闭弹窗
         
-        [self close];
+        [self closeAction];
         
-    }else if(interaction == 6){//右垫脚 -- 链接设备
+    }else if(interaction == 5){//右垫脚 -- 链接设备
      
         if (self.connectDeviceBlock){
             self.connectDeviceBlock(self.currentPeripheral);
         }
-        [self close];
+        [self closeAction];
         
     }
     
@@ -211,7 +173,7 @@
 //
 //    self.tipView.hidden = NO;
 //    if(self.searchDeviceTask){
-//        self.searchDeviceTask();
+//        [BTDataInstance initCBCentralManager];
 //    }
 //
 //}
@@ -227,23 +189,22 @@
     [_shoesCarouselView yw_gotoNext:1];
 }
 
-//关闭弹窗
--(void)closeAction{
-    [self close];
-}
-
 //确认选中的设备 开始蓝牙连接
 -(void)selectedDeviceAction{
     
     if (self.connectDeviceBlock){
         self.connectDeviceBlock(self.currentPeripheral);
     }
-    [self close];
+    [self closeAction];
     
 }
 
-//关闭毛玻璃遮罩
-- (void)close{
+//关闭弹窗
+- (void)closeAction{
+    
+    if (self.closeBlock){
+        self.closeBlock();
+    }
 
     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.4 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
         [UIView animateWithDuration:0.25 animations:^{
@@ -256,11 +217,25 @@
     
 }
 
+//清理缓存
+-(void)clearCacheWithFilePath{
+    [DebugViewInstance clearCacheWithFilePath];
+}
 
 #pragma mark -------------- shoesCarouseView delegate
+-(void)setCurrentperipheral:(CBPeripheral*)peripheral{
+    self.currentPeripheral = peripheral;
+}
 //来自shoesCarouseView被选中的当前蓝牙
 -(void)connectDevice:(CBPeripheral*)peripheral{
+    
     self.currentPeripheral = peripheral;
+    //链接蓝牙
+    if (self.connectDeviceBlock){
+        self.connectDeviceBlock(self.currentPeripheral);
+    }
+    [self closeAction];
+    
 }
 
 

+ 5 - 10
SDK/UI/CarouselView/ShoesCarouselView.h

@@ -8,10 +8,12 @@
 #import <UIKit/UIKit.h>
 #import <CoreBluetooth/CoreBluetooth.h>
 
-#import "TXCarouselCellModel.h"
+#import "ShoesPeripheralMolde.h"
 
 @protocol ConnectDeviceDelegate <NSObject>
 
+-(void)setCurrentperipheral:(CBPeripheral*)peripheral;
+
 -(void)connectDevice:(CBPeripheral*)peripheral;
 
 @end
@@ -23,19 +25,12 @@
 /**
  配置数据(固定TXCarouselView)
 
- @param array TXCarouselCellModelArray
+ @param array ShoesPeripheralMolde
  */
-//-(void)setArrayData:(NSArray <TXCarouselCellModel *>*)array;
+-(void)setArrayData:(NSArray <ShoesPeripheralMolde *>*)array;
 
-/**
- 配置数据(滑动TXCarouselView,加在ScrollViewv上时 需要传入)
- @param array TXCarouselCellModelArray
- @param superScrollView 父系ScrollView
- */
--(void)setArrayData:(NSArray <TXCarouselCellModel *>*)array;
 
 -(void)yw_gotoNext:(NSInteger)index;
 
-
 @end
 

+ 67 - 41
SDK/UI/CarouselView/ShoesCarouselView.m

@@ -10,7 +10,7 @@
 #import "ShoesCollectionCell.h"
 #import "TXCarouselViewLayout.h"
 
-#import "TXCarouselCellModel.h"
+#import "ShoesPeripheralMolde.h"
 #import <CoreMotion/CoreMotion.h>
 
 #define itemHight 1
@@ -43,7 +43,6 @@ UIScrollViewDelegate
 @property (nonatomic, strong) CarouselCurrentState *currentState;//当前 carousel 状态
 @property (nonatomic, strong) UIScrollView *superScrollView;
 @property (nonatomic, strong) UICollectionView *collectionView;
-@property (nonatomic, strong) NSMutableArray *modelArray;
 @property (nonatomic, assign) CGFloat lasttimePoint;
 @property (nonatomic, assign) CGFloat gyrValue;//加速计值
 @property (nonatomic, assign) CGSize carouselSize;
@@ -52,14 +51,14 @@ UIScrollViewDelegate
 
 @property (nonatomic, assign) CGFloat cIndex;
 @property (nonatomic, assign) BOOL turnLeft;//滑动方向
-@property (nonatomic, assign) BOOL isLeft_1;//第一次滑到最左边
-@property (nonatomic, assign) BOOL isRight_1;//第一次滑到最右边
+
+
+@property (nonatomic, strong) NSMutableArray *modelArray;
 
 @end
 
 @implementation ShoesCarouselView
 
-
 #pragma mark - 生命周期
 - (instancetype)initWithCoder:(NSCoder *)coder{
     
@@ -73,6 +72,7 @@ UIScrollViewDelegate
         self.currentState.isRestrict = NO;
         
         self.userInteractionEnabled = NO;
+        self.collectionView.scrollEnabled = NO;
   
     }
     return self;
@@ -98,6 +98,7 @@ UIScrollViewDelegate
 
 //
 -(void)setpoint{
+    NSLog(@"setpoint");
     [self.collectionView setContentOffset:CGPointMake(0, self.collectionView.contentOffset.y) animated:NO];
     [self.collectionView setContentOffset:CGPointMake(0+((self.modelArray.count/2)*(self.carouselSize.height*itemHight)), self.collectionView.contentOffset.y) animated:NO];
     self.currentState.lastCarouselPoint = 0;
@@ -105,34 +106,47 @@ UIScrollViewDelegate
 }
 
 #pragma  mark - loadData
--(void)setArrayData:(NSArray<TXCarouselCellModel *> *)array{
+-(void)setArrayData:(NSArray<ShoesPeripheralMolde *> *)array{
     
-    [self.modelArray removeAllObjects];
     if (array.count<=0){
         return;
     }
+    if (array.count == self.modelArray.count) {//没有新的数据源不刷新
+        return;
+    }
     
+    [self.modelArray removeAllObjects];
+
     [self.modelArray addObjectsFromArray:array];
+    
     [self.collectionView reloadData];
     [self.collectionView layoutIfNeeded];
     
     // 当只有一个数据源的时候 让cell滑到正中间
     if (array.count==1){
         
-        NSLog(@"设备列表只有一个数据源");
+//        NSLog(@"设备列表只有一个数据源");
         _cIndex = 0;
         [self testAction];
         
     }else{
         
         dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
-             [self setpoint];
+            
+            if (array.count>=5){
+
+            }else{
+                
+                [self setpoint];
+                
+            }
+            
          });
         
     }
         
     // 当只有两个数据源的时候 添加手势 防止collectionView数据少 没有占满屏幕 时候滑不动的BUG
-    if (array.count==2){
+    if (array.count>=2){
         UISwipeGestureRecognizer *  left = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(handleSwipeFrom:)];
        [left setDirection:(UISwipeGestureRecognizerDirectionLeft)];
        [self.collectionView addGestureRecognizer:left];
@@ -141,18 +155,18 @@ UIScrollViewDelegate
        [self.collectionView addGestureRecognizer:right];
      }
     
+    self.collectionView.scrollEnabled = NO;
+    
 }
 
 #pragma mark -- UISwipeGestureRecognizer
 - (void)handleSwipeFrom:(UISwipeGestureRecognizer *)recognizer{
     
    if(recognizer.direction == UISwipeGestureRecognizerDirectionLeft){
-       NSLog(@"swipe left");
        [self yw_gotoNext:1];
    }
     
    if(recognizer.direction == UISwipeGestureRecognizerDirectionRight){
-     NSLog(@"swipe right");
        [self yw_gotoNext:-1];
    }
     
@@ -160,69 +174,77 @@ UIScrollViewDelegate
 
 #pragma mark -- scrollView delegate
 -(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView{
+    NSLog(@"scrollViewWillBeginDragging");
     self.lastContentOffsetY = scrollView.contentOffset.x;
  }
 
 -(void)scrollViewDidScroll:(UIScrollView *)scrollView{
-    
+//    NSLog(@"scrollViewDidScroll");
     if (scrollView.contentOffset.x < self.lastContentOffsetY){
 //        NSLog(@"左左");
         self.turnLeft = YES;
-        //第一次滑到最左-1
-        self.isLeft_1 = NO;
 
     }else if (scrollView.contentOffset.x > self.lastContentOffsetY){
 //        NSLog(@"右右");
         self.turnLeft = NO;
-        //第一次滑到最右-1
-        self.isRight_1 = NO;
-
+   
     }
     
 }
 
 #pragma mark -- collectionView delegate
 - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
-    NSLog(@"numberOfItemsInSection-%zi",self.modelArray.count);
+//    NSLog(@"self.modelArray.count - %ld",self.modelArray.count);
     return  self.modelArray.count;
 }
 
 - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
     
     ShoesCollectionCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"ShoesCollectionCell" forIndexPath:indexPath];
-    [cell setCarouselCellModel:self.modelArray[indexPath.row]];
+    ShoesPeripheralMolde * model = self.modelArray[indexPath.row];
+    [cell setCarouselCellModel:model];
     
     __weak typeof(self) weakSelf = self;
-    
-//    [cell setBlock:^{
-//        weakSelf.currentState.isDragState = YES;
-//        weakSelf.currentState.isCenter = YES;
-//    }];
-    
     //单击cell 滚到cell位置
     cell.tapGestureBlock = ^(NSInteger i){
-        _cIndex = i;
-        [self testAction];
+        
+        if (i==_cIndex) {
+            NSLog(@"didSelectItemAtIndexPath 点击的 是 当前");
+            _cIndex = i;
+            if ([self.delegate respondsToSelector:@selector(connectDevice:)]){
+                [self.delegate connectDevice:model.peripheral];
+            }
+            
+        }else{
+            
+            NSLog(@"didSelectItemAtIndexPath 点击的 不是 当前");
+            _cIndex = i;
+            [weakSelf testAction];
+            
+        }
+        
     };
+    
+    //默认选中
+    [self jugeSelected];
+
     return cell;
     
 }
 
 - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath{
     
-    NSLog(@"选中了  ==== %ld",(long)indexPath.row);
+//    NSLog(@"选中了  ==== %ld",(long)indexPath.row);
     ShoesCollectionCell * cell = (ShoesCollectionCell*)[self.collectionView cellForItemAtIndexPath:indexPath];
     cell.cusSelected = YES;
     
-    //选中的cell滚到中间位置
-//    [self setpoint];
-    
     //将当前滚动到的cell->蓝牙 回调给SearchDeviceViewController
-    TXCarouselCellModel * model = self.modelArray[indexPath.row];
-    if ([self.delegate respondsToSelector:@selector(connectDevice:)]){
-        [self.delegate connectDevice:model.peripheral];
-    }
+    ShoesPeripheralMolde * model = self.modelArray[indexPath.row];
     
+    if ([self.delegate respondsToSelector:@selector(setCurrentperipheral:)]){
+        [self.delegate setCurrentperipheral:model.peripheral];
+    }
+      
 }
 
 - (void)collectionView:(UICollectionView *)collectionView didDeselectItemAtIndexPath:(NSIndexPath *)indexPath{
@@ -236,6 +258,8 @@ UIScrollViewDelegate
  回到屏幕正中间
  */
 -(void)setSlideEnd{
+    
+    NSLog(@"setSlideEnd");
 
     CGPoint collectionViewPoint = self.collectionView.contentOffset;
     if ( self.currentState.lastCarouselPoint == collectionViewPoint.x||self.currentState.isDragState){
@@ -253,7 +277,7 @@ UIScrollViewDelegate
     self.currentState.isDidScroll = YES;
 
     _cIndex = index;
-    NSLog(@"setSlideEnd:x[%f]----y[%f]---index[%f]",collectionViewPoint.x,collectionViewPoint.y,index);
+//    NSLog(@"setSlideEnd:x[%f]----y[%f]---index[%f]",collectionViewPoint.x,collectionViewPoint.y,index);
     
     [self jugeSelected];
 
@@ -265,7 +289,7 @@ UIScrollViewDelegate
     NSLog(@"yw_gotoNext:(NSInteger)index = %d %ld",(int)_cIndex,(long)index);
     if ((int)_cIndex<1 && index == -1){//滑到最左边
         return;
-    }else if ((int)_cIndex>self.modelArray.count-2 && index == 1){//滑到最
+    }else if ((int)_cIndex>self.modelArray.count-2 && index == 1){//滑到最
         return;
     }else{
         _cIndex = _cIndex + index;
@@ -276,11 +300,11 @@ UIScrollViewDelegate
 
 //setContentOffset到对应位置
 - (void)testAction{
-    
+    NSLog(@"testAction");
     CGFloat viewHeight = CGRectGetWidth(self.collectionView.frame);
     CGFloat itemHeight = self.carouselSize.height*itemHight;
     CGFloat offsetX = (_cIndex + (itemHeight/2)/itemHeight - (viewHeight/2)/itemHeight)*itemHeight;
-    NSLog(@"testAction:%f----_cIndex:%f",offsetX,_cIndex);
+//    NSLog(@"testAction:%f----_cIndex:%f",offsetX,_cIndex);
     [self.collectionView setContentOffset:CGPointMake(offsetX, 0) animated:YES];
     
     [self jugeSelected];
@@ -319,6 +343,8 @@ UIScrollViewDelegate
 //
 -(void)endScroll{
     
+    NSLog(@"endScroll");
+    
     __weak typeof(self)WeakSelf = self;
     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    
@@ -365,7 +391,7 @@ UIScrollViewDelegate
 -(TXCarouselViewLayout *)carouselViewLayout{
     
     if (!_carouselViewLayout){
-        CGFloat itemsHeight = self.carouselSize.height*itemHight;
+        CGFloat itemsHeight = _carouselSize.height*itemHight;
         _carouselViewLayout = [[TXCarouselViewLayout alloc] init];
         _carouselViewLayout.itemSize = CGSizeMake(itemsHeight, itemsHeight);
         _carouselViewLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;

+ 3 - 3
SDK/UI/CarouselView/ShoesCollectionCell.h

@@ -6,7 +6,7 @@
 //
 
 #import <UIKit/UIKit.h>
-#import "TXCarouselCellModel.h"
+#import "ShoesPeripheralMolde.h"
 
 NS_ASSUME_NONNULL_BEGIN
 
@@ -17,8 +17,8 @@ NS_ASSUME_NONNULL_BEGIN
 
 @property (assign, nonatomic) BOOL cusSelected;
 
-@property(nonatomic,strong)TXCarouselCellModel * model;
--(void)setCarouselCellModel:(TXCarouselCellModel *)model;
+@property(nonatomic,strong)ShoesPeripheralMolde * model;
+-(void)setCarouselCellModel:(ShoesPeripheralMolde *)model;
 
 //点击cell回调block
 @property(nonatomic,copy)void(^tapGestureBlock)(NSInteger i);

+ 6 - 8
SDK/UI/CarouselView/ShoesCollectionCell.m

@@ -42,9 +42,6 @@
     self.covierView.backgroundColor = [UIColor whiteColor];
     self.covierView.layer.cornerRadius = 15;
     
-//    self.imageView.layer.masksToBounds = YES;
-//    self.imageView.layer.cornerRadius = 70;
-    
     self.titleStr.font = [UIFont systemFontOfSize: SCALEoefficient(20)];
     
     //状态label
@@ -63,22 +60,20 @@
 #pragma mark - 点击事件
 - (void)myTableViewClick:(UIGestureRecognizer *)gestureRecognizer{
     if (self.tapGestureBlock){
-        self.tapGestureBlock(self.model.newsId);
+        self.tapGestureBlock(self.model.numberId);
     }
 }
 
 /**
  加载数据
- @param model TXCarouselCellModel
+ @param model ShoesPeripheralMolde
  */
--(void)setCarouselCellModel:(TXCarouselCellModel *)model{
+-(void)setCarouselCellModel:(ShoesPeripheralMolde *)model{
     
-//    self.imageView.image = [UIImage imageNamed:model.imageUrl];
     if (self.model!=model){
         self.model = model;
     }
     if (model.peripheral!=nil){
-        NSLog(@" %@ ",model.peripheral);
         self.titleStr.text = model.peripheral.advertiseName;
     }
     
@@ -87,8 +82,11 @@
 //更新状态
 -(void)setCusSelected:(BOOL)cusSelected{
    
+
     if (cusSelected == YES){
         
+        NSLog(@"cusSelected %ld ",(long)self.model.numberId);
+
         self.covierView.layer.masksToBounds = YES;
         self.covierView.layer.borderColor = [UIColor colorWithRed:255/255.0 green:196/255.0 blue:0/255.0 alpha:1.0].CGColor;
         self.covierView.layer.borderWidth = 3;

+ 10 - 12
SDK/UI/CarouselView/ShoesCollectionCell.xib

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="17701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
     <device id="retina6_1" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="17703"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     <objects>
@@ -20,18 +20,14 @@
                         <rect key="frame" x="0.0" y="0.0" width="193" height="181"/>
                         <subviews>
                             <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="gamepop_shoes.png" translatesAutoresizingMaskIntoConstraints="NO" id="Kjh-S8-wbt">
-                                <rect key="frame" x="26.5" y="20.5" width="140" height="100"/>
+                                <rect key="frame" x="30" y="37.5" width="133" height="66.5"/>
                                 <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                 <constraints>
-                                    <constraint firstAttribute="height" constant="100" id="2N3-0f-boH"/>
-                                    <constraint firstAttribute="width" constant="140" id="csp-CZ-mMg"/>
+                                    <constraint firstAttribute="width" secondItem="Kjh-S8-wbt" secondAttribute="height" multiplier="2:1" id="Ep2-1q-XN2"/>
                                 </constraints>
                             </imageView>
                             <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="设备名字7个字" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="qVV-VO-9dC">
-                                <rect key="frame" x="0.0" y="130.5" width="193" height="40"/>
-                                <constraints>
-                                    <constraint firstAttribute="height" constant="40" id="ljL-xf-aKV"/>
-                                </constraints>
+                                <rect key="frame" x="0.0" y="104" width="193" height="77"/>
                                 <fontDescription key="fontDescription" type="system" pointSize="20"/>
                                 <nil key="textColor"/>
                                 <nil key="highlightedColor"/>
@@ -40,10 +36,12 @@
                         <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                         <constraints>
                             <constraint firstAttribute="trailing" secondItem="qVV-VO-9dC" secondAttribute="trailing" id="7uS-XB-5xe"/>
-                            <constraint firstItem="Kjh-S8-wbt" firstAttribute="centerX" secondItem="tfp-Y9-ewB" secondAttribute="centerX" id="OnM-ie-CSx"/>
+                            <constraint firstAttribute="bottom" secondItem="qVV-VO-9dC" secondAttribute="bottom" id="FFU-ze-sep"/>
+                            <constraint firstItem="Kjh-S8-wbt" firstAttribute="leading" secondItem="tfp-Y9-ewB" secondAttribute="leading" constant="30" id="MXl-WI-DKR"/>
                             <constraint firstItem="Kjh-S8-wbt" firstAttribute="centerY" secondItem="tfp-Y9-ewB" secondAttribute="centerY" constant="-20" id="QWq-Ef-tO9"/>
+                            <constraint firstItem="qVV-VO-9dC" firstAttribute="top" secondItem="Kjh-S8-wbt" secondAttribute="bottom" id="fgi-Ah-VTs"/>
                             <constraint firstItem="qVV-VO-9dC" firstAttribute="leading" secondItem="tfp-Y9-ewB" secondAttribute="leading" id="g5E-nC-J2X"/>
-                            <constraint firstItem="qVV-VO-9dC" firstAttribute="top" secondItem="Kjh-S8-wbt" secondAttribute="bottom" constant="10" id="mSu-pJ-2wD"/>
+                            <constraint firstAttribute="trailing" secondItem="Kjh-S8-wbt" secondAttribute="trailing" constant="30" id="xQk-13-MdW"/>
                         </constraints>
                     </view>
                 </subviews>
@@ -68,6 +66,6 @@
         </collectionViewCell>
     </objects>
     <resources>
-        <image name="gamepop_shoes.png" width="68" height="43.5"/>
+        <image name="gamepop_shoes.png" width="99" height="46"/>
     </resources>
 </document>

+ 7 - 7
SDK/UI/CarouselView/TXCarouselCellModel.h → SDK/UI/CarouselView/ShoesPeripheralMolde.h

@@ -1,20 +1,20 @@
 //
-//  TXCarouselCellModel.h
-//  textView
+//  ShoesPeripheralMolde.h
+//  Unity-iPhone
 //
-//  Created by 新华龙mac on 2018/1/10.
-//  Copyright © 2018年 新华龙mac. All rights reserved.
+//  Created by duowan123 on 2022/8/19.
 //
 
 #import <Foundation/Foundation.h>
 #import <UIKit/UIKit.h>
 #import <CoreBluetooth/CoreBluetooth.h>
 
-@interface TXCarouselCellModel : NSObject
-@property (nonatomic, assign) NSInteger newsId;
+@interface ShoesPeripheralMolde : NSObject
+
+@property (nonatomic, assign) NSInteger numberId;
 @property (nonatomic, strong) NSString *titleStr;
 @property (nonatomic, strong) NSString *imageUrl;
-
 @property (nonatomic, strong) CBPeripheral *peripheral;
 
 @end
+

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff