#import "SensorPlugin.h" #import #import "AppEventChannel.h" #import #import #import #import @interface SensorPlugin() { FlutterEventSink flutterEventSink; FlutterEventChannel* flutterEventChannel; // CBCM对象 CBCentralManager* CM; // 位置服务对象 CLLocationManager * locationManager; UInt64 isOpenLastTime; bool isOpen; // 当前位置 FLTPosition *fltPosition; // 陀螺仪传感器 CMMotionManager *motionManager; // 返回的陀螺仪数据 FLTOrientation *newOriention; // 蓝牙是否打开 bool isBLOpen; // bleManager 对象 HeartBLEManager *bleManager; // 扫描出的设备 NSArray *ListPeripheral; // 当前连接设备 HeartBLEDevice *BleDevice; // 心率交换池数组 NSMutableArray *ListFLTHr; AppEventChannel *channelLocation; AppEventChannel *channelOriention; } @property (nonatomic, strong) FlutterEventSink eventSink; @property (nonatomic, strong) FlutterEventChannel *eventChannel ; @end @implementation SensorPlugin + (instancetype)sharedInstance { static SensorPlugin *instance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [[self alloc] init]; }); return instance; } + (void)registerWithRegistrar:(NSObject*)registrar { //注册methodChannel FlutterMethodChannel* channel = [FlutterMethodChannel methodChannelWithName:@"sensor" binaryMessenger:[registrar messenger]]; [registrar addMethodCallDelegate:SensorPlugin.sharedInstance channel:channel]; //初始化streamChannel AppEventChannel *evenChannal = [[AppEventChannel alloc]initWithNameMessge:registrar :@"com.beswell.sensor.event/location"]; SensorPlugin.sharedInstance -> channelLocation = evenChannal; AppEventChannel *channelOri = [[AppEventChannel alloc]initWithNameMessge:registrar :@"com.beswell.sensor.event/orientation"]; SensorPlugin.sharedInstance -> channelOriention = channelOri; AppEventChannel *channelHrm = [[AppEventChannel alloc]initWithNameMessge:registrar :@"com.beswell.sensor.event/HRM"]; AppEventChannel *channelWearScan = [[AppEventChannel alloc]initWithNameMessge:registrar :@"com.beswell.sensor.event/SportWearScanResult"]; AppEventChannel *channelWearConn = [[AppEventChannel alloc]initWithNameMessge:registrar :@"com.beswell.sensor.event/SportWearConnected"]; //初始化SensorApi FLTSensorApiSetup(registrar.messenger, SensorPlugin.sharedInstance); } // 构造函数,初始化一些变量 -(id) init { NSLog(@"init struct"); if (self=[super init]) { NSLog(@"init page obj"); //初始化 motionManager = [[CMMotionManager alloc] init]; //设置更新间隔每秒60次 motionManager.deviceMotionUpdateInterval = 1.0 / 60.0; //开启陀螺仪 if (motionManager.isDeviceMotionAvailable) { [motionManager startDeviceMotionUpdates]; } [motionManager startDeviceMotionUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMDeviceMotion * _Nullable motion, NSError * _Nullable error) { if(self->newOriention == nil){ self->newOriention = [[FLTOrientation alloc]init]; } // Gravity 获取手机的重力值在各个方向上的分量,根据这个就可以获得手机的空间位置,倾斜角度等 double gravityX = motion.gravity.x; double gravityY = motion.gravity.y; double gravityZ = motion.gravity.z; // 获取手机的倾斜角度(zTheta是手机与水平面的夹角, xyTheta是手机绕自身旋转的角度): double zTheta = atan2(gravityZ,sqrtf(gravityX * gravityX + gravityY * gravityY)) / M_PI * 180.0; double xyTheta = atan2(gravityX, gravityY) / M_PI * 180.0; // NSLog(@"手机与水平面的夹角 --- %.4f, 手机绕自身旋转的角度为 --- %.4f", zTheta, xyTheta); [self->newOriention setX:[[NSNumber alloc] initWithDouble:motion.gravity.x]]; [self->newOriention setY:[[NSNumber alloc] initWithDouble:motion.gravity.y]]; if(self->channelOriention != nil){ [self->channelOriention success: @[ (self->newOriention.x ?: [NSNull null]), (self->newOriention.y ?: [NSNull null]), (self->newOriention.z ?: [NSNull null]), ] ]; } }]; // 实例化bleManager bleManager = [HeartBLEManager sharedInstance]; // 设置蓝牙代理 [bleManager setDelegate:self]; // 初始化心率数组 ListFLTHr = [[NSMutableArray alloc]initWithCapacity:64]; // 初始化蓝牙协议对象 CM = [[CBCentralManager alloc] initWithDelegate:self queue:nil]; // 初始化位置对象 fltPosition = [[FLTPosition alloc]init]; } return self; } //StreamLocation /** */ - (void)locationStartMinTimeMs:(NSNumber *)minTimeMs minDistanceM:(NSNumber *)minDistanceM error:(FlutterError * _Nullable __autoreleasing *)error{ int isOpenTime = [[NSDate date] timeIntervalSince1970]; if(isOpenTime - isOpenLastTime > 5){ // NSLog(@"isLocationServiceOpenWithError%llu",(isOpenTime - isOpenLastTime)); if ([CLLocationManager locationServicesEnabled]) { isOpen = true; if (locationManager == nil) { locationManager = [[CLLocationManager alloc] init]; locationManager.delegate = self; [locationManager startUpdatingHeading];// 请求方向 [locationManager requestAlwaysAuthorization];// 请求前台和后台定位权限 ios >= 8.0 // [locationManager startUpdatingLocation];// 请求前台定位权限 NSLog(@"init locationManager"); } }else { isOpen = false; } isOpenLastTime = isOpenTime; } } - (void)locationStopWithError:(FlutterError * _Nullable __autoreleasing *)error{ // 停止更新 [ locationManager stopUpdatingLocation]; } // - (void)toGenAllClassOrientation:(FLTOrientation *)orientation hrm:(FLTHeartRateMeasurement *)hrm position:(FLTPosition *)position error:(FlutterError *_Nullable *_Nonnull)error{ } // 获取屏幕x向DPI - (nullable NSNumber *)getXDPIWithError:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { // NSLog(@"getXDPIWithError %@",[self getDpiOnPhone]); return [self getDpiOnPhone]; } // 获取屏幕y向DPI - (nullable NSNumber *)getYDPIWithError:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { // NSLog(@"getYDPIWithError"); return [self getDpiOnPhone]; } // 获取设备当前朝向 - (nullable FLTOrientation *)getOrientationWithError:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { // NSLog(@"getOrientationWithError%@ - %@ - %@",newOriention.x,newOriention.y,newOriention.z); return newOriention; } // 位置服务是否开启 - (nullable NSNumber *)isLocationServiceOpenWithError:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { NSNumber *isLocationOpen = [[NSNumber alloc]initWithBool:isOpen]; return isLocationOpen; } // 强制获取当前位置 - (void)getCurrentPositionForce:(nonnull NSNumber *)force completion:(nonnull void (^)(FLTPosition * _Nullable, FlutterError * _Nullable))completion { // NSLog(@"getCurrentPositionForce"); if (locationManager == nil) { locationManager = [[CLLocationManager alloc] init]; locationManager.delegate = self; [locationManager startUpdatingHeading];// 请求方向 [locationManager requestAlwaysAuthorization];// 请求前台和后台定位权限 ios >= 8.0 // [locationManager startUpdatingLocation];// 请求前台定位权限 } completion(fltPosition,NULL); } // 询问蓝牙是否开启 - (void)askEnableBluetoothWithCompletion:(void (^)(NSNumber * _Nullable, FlutterError * _Nullable))completion{ // NSLog(@"askEnableBluetoothWithCompletion"); NSNumber *blueToothOpen = [[NSNumber alloc]initWithBool:isBLOpen]; completion(blueToothOpen,NULL); } // 开始扫描心率带 - (void)sportWearScanStartWithError:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { NSLog(@"sportWearScanStartWithError"); [bleManager StartScanDevice]; } // 停止扫描心率带 - (void)sportWearScanStopWithError:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { NSLog(@"sportWearScanStopWithError"); [bleManager stopScan]; } // 获取心率带扫描结果 - (nullable NSArray *)getSportWearScanResultWithError:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { NSMutableArray *resultArr = [[NSMutableArray alloc]initWithCapacity:ListPeripheral.count]; for(int i =0;i *)getSportWearConnectedWithError:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { NSArray *bandArr; if(BleDevice){ FLTSportWear *bandWear = [FLTSportWear new]; bandWear.name = BleDevice.DeviceName; bandWear.address = BleDevice.UUIDStr; bandWear.rssi = [[NSNumber alloc]initWithInt:[BleDevice.RSSI intValue]]; bandArr = [[NSArray alloc] initWithObjects:bandWear, nil]; }else{ bandArr = [[NSArray alloc] init]; } return bandArr; } // 获取心率 - (nullable NSArray *)getSportWearHeartRateMeasurementWithError:(FlutterError * _Nullable __autoreleasing * _Nonnull)error { NSArray *hrArr = [NSArray arrayWithArray:ListFLTHr]; [ListFLTHr removeAllObjects]; return hrArr; } /** 屏幕相关 */ - (NSNumber *)getDpiOnPhone { //需要导入头文件:#import struct utsname systemInfo; uname(&systemInfo); NSString *platform = [NSString stringWithCString: systemInfo.machine encoding:NSASCIIStringEncoding]; // iPhone 6 Plus if([platform isEqualToString:@"iPhone7,1"]) return [[NSNumber alloc]initWithDouble:401]; // iPhone 6 if([platform isEqualToString:@"iPhone7,2"]) return [[NSNumber alloc]initWithDouble:326]; // iPhone 6s if([platform isEqualToString:@"iPhone8,1"]) return [[NSNumber alloc]initWithDouble:326]; // iPhone 6s Plus if([platform isEqualToString:@"iPhone8,2"]) return [[NSNumber alloc]initWithDouble:401]; // iPhone SE if([platform isEqualToString:@"iPhone8,4"]) return [[NSNumber alloc]initWithDouble:401]; // iPhone 7 if([platform isEqualToString:@"iPhone9,1"]) return [[NSNumber alloc]initWithDouble:326]; // iPhone 7 Plus if([platform isEqualToString:@"iPhone9,2"]) return [[NSNumber alloc]initWithDouble:401]; // iPhone 8 if([platform isEqualToString:@"iPhone10,1"])return [[NSNumber alloc]initWithDouble:326]; // iPhone 8 if([platform isEqualToString:@"iPhone10,4"])return [[NSNumber alloc]initWithDouble:326]; // iPhone 8 Plus if([platform isEqualToString:@"iPhone10,2"])return [[NSNumber alloc]initWithDouble:401]; // iPhone 8 Plus if([platform isEqualToString:@"iPhone10,5"])return [[NSNumber alloc]initWithDouble:401]; // iPhone X if([platform isEqualToString:@"iPhone10,3"])return [[NSNumber alloc]initWithDouble:458]; // iPhone X if([platform isEqualToString:@"iPhone10,6"])return [[NSNumber alloc]initWithDouble:458]; // iPhone XS if([platform isEqualToString:@"iPhone11,2"])return [[NSNumber alloc]initWithDouble:458]; // iPhone XS Max if([platform isEqualToString:@"iPhone11,4"])return [[NSNumber alloc]initWithDouble:458]; // iPhone XS Max if([platform isEqualToString:@"iPhone11,6"])return [[NSNumber alloc]initWithDouble:458]; // iPhone XR if([platform isEqualToString:@"iPhone11,8"])return [[NSNumber alloc]initWithDouble:326]; // iPhone 11 if([platform isEqualToString:@"iPhone12,1"])return [[NSNumber alloc]initWithDouble:326]; // iPhone 11 Pro Max if([platform isEqualToString:@"iPhone12,3"])return [[NSNumber alloc]initWithDouble:458]; // iPhone 11 if([platform isEqualToString:@"iPhone12,5"])return [[NSNumber alloc]initWithDouble:326]; // iPhone SE 2 if([platform isEqualToString:@"iPhone12,8"])return [[NSNumber alloc]initWithDouble:326]; // iPhone 12 mini if([platform isEqualToString:@"iPhone13,1"])return [[NSNumber alloc]initWithDouble:476]; // iPhone 12 if([platform isEqualToString:@"iPhone13,2"])return [[NSNumber alloc]initWithDouble:460]; // iPhone 12 Pro if([platform isEqualToString:@"iPhone13,3"])return [[NSNumber alloc]initWithDouble:460]; // iPhone 12 Pro Max if([platform isEqualToString:@"iPhone13,4"])return [[NSNumber alloc]initWithDouble:458]; //2021年新款iPhone 13 mini、13、13 Pro、13 Pro Max发布 // iPhone 13 mini if([platform isEqualToString:@"iPhone14,4"])return [[NSNumber alloc]initWithDouble:476]; // iPhone 13 if([platform isEqualToString:@"iPhone14,5"])return [[NSNumber alloc]initWithDouble:460]; // iPhone 13 Pro if([platform isEqualToString:@"iPhone14,2"])return [[NSNumber alloc]initWithDouble:460]; // iPhone 13 Pro Max if([platform isEqualToString:@"iPhone14,3"])return [[NSNumber alloc]initWithDouble:458]; //2022年新款iPhone 14、14Plus、14 Pro、14 Pro Max发布 // iPhone 14 if([platform isEqualToString:@"iPhone14,7"])return [[NSNumber alloc]initWithDouble:460]; // iPhone 14 Plus if([platform isEqualToString:@"iPhone14,8"])return [[NSNumber alloc]initWithDouble:458]; // iPhone 14 Pro if([platform isEqualToString:@"iPhone15,2"])return [[NSNumber alloc]initWithDouble:460]; // iPhone 14 Pro Max if([platform isEqualToString:@"iPhone15,3"])return [[NSNumber alloc]initWithDouble:460]; return [[NSNumber alloc]initWithDouble:460]; } /** locationManager相关 */ // 当获取到用户方向时就会调用 - (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading { // NSLog(@"%s", __func__); /* magneticHeading 设备与磁北的相对角度 trueHeading 设置与真北的相对角度, 必须和定位一起使用, iOS需要设置的位置来计算真北 真北始终指向地理北极点 */ // NSLog(@"%f", newHeading.magneticHeading); // 1.将获取到的角度转为弧度 = (角度 * π) / 180; CGFloat angle = newHeading.magneticHeading * M_PI / 180; [self->newOriention setZ:[[NSNumber alloc] initWithFloat:angle]]; [self->channelOriention success: @[ (newOriention.x ?: [NSNull null]), (newOriention.y ?: [NSNull null]), (newOriention.z ?: [NSNull null]), ] ]; // NSLog(@"locationManager %f - newHeading.magneticHeading %f",angle,newHeading.magneticHeading); // 2.旋转图片 /* 顺时针 正 逆时针 负数 */ // self.compasspointer.transform = CGAffineTransformIdentity; // self.compasspointer.transform = CGAffineTransformMakeRotation(-angle); } -(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status { // CLAuthorizationStatus /* 用户从未选择过权限 kCLAuthorizationStatusNotDetermined 无法使用定位服务,该状态用户无法改变 kCLAuthorizationStatusRestricted 用户拒绝该应用使用定位服务,或是定位服务总开关处于关闭状态 kCLAuthorizationStatusDenied 已经授权(废弃) kCLAuthorizationStatusAuthorized 用户允许该程序无论何时都可以使用地理信息 kCLAuthorizationStatusAuthorizedAlways 用户同意程序在可见时使用地理位置 kCLAuthorizationStatusAuthorizedWhenInUse*/ // 允许授权 if (status == kCLAuthorizationStatusAuthorizedAlways || status == kCLAuthorizationStatusAuthorizedWhenInUse) { NSLog(@"授权成功"); [locationManager startUpdatingLocation]; } else if(status == kCLAuthorizationStatusNotDetermined) { // 用户从未选择过权限 NSLog(@"等待用户授权"); } else{ NSLog(@"授权失败"); } } /** * 获取到位置信息之后就会去调用(如果不做控制会频繁调用,浪费电量) * * @param manager 调用者 * @param locations 获取到的地理位置信息 */ - ( void ) locationManager: ( CLLocationManager * ) manager didUpdateToLocation: ( CLLocation * ) newLocation fromLocation: ( CLLocation * ) oldLocation { //打印经纬度 // NSLog(@"latitude:%f - longitude:%f - altitude:%f",newLocation.coordinate.latitude,newLocation.coordinate.longitude, newLocation.altitude); [fltPosition setAltitude:[[NSNumber alloc] initWithFloat:newLocation.altitude]]; [fltPosition setLatitude:[[NSNumber alloc] initWithFloat:newLocation.coordinate.latitude]]; [fltPosition setLongitude:[[NSNumber alloc] initWithFloat:newLocation.coordinate.longitude]]; //发送数据 @[ result ?: [NSNull null] ] [channelLocation success:@[ (fltPosition.latitude ?: [NSNull null]), (fltPosition.longitude ?: [NSNull null]), (fltPosition.altitude ?: [NSNull null]), (fltPosition.bearing ?: [NSNull null]), (fltPosition.accuracy ?: [NSNull null]), (fltPosition.speed ?: [NSNull null]), ]]; } /** CoreBluetooth协议 */ - (void)centralManagerDidUpdateState:(CBCentralManager *)central { NSString *message = nil; switch (central.state) { case 1: message = @"该设备不支持蓝牙功能,请检查系统设置"; break; case 2: message = @"该设备蓝牙未授权,请检查系统设置"; break; case 3: message = @"该设备蓝牙未授权,请检查系统设置"; break; case 4: isBLOpen = false; message = @"该设备尚未打开蓝牙,请在设置中打开"; break; case 5: isBLOpen = true; message = @"蓝牙已经成功开启,请稍后再试"; break; default: break; } if(message!=nil&&message.length!=0) { NSLog(@"message == %@",message); } } /** 心率SDK相关 PROTOCAL */ // 心率带是否连接 - (void)isConnected:(BOOL)isConnected withDevice:(nonnull HeartBLEDevice *)device { // NSLog(@"isConnected%@ ",device.DeviceName); // 给连接成功的心率带设置代理 [device setDelegate:self]; // 赋值BLEDevice引用 BleDevice = device; } // 断开心率带 - (void)disconnected:(nonnull HeartBLEDevice *)device { // NSLog(@"disconnected"); BleDevice = NULL; } // 设备扫描回调 - (void)onDeviceFound:(nonnull NSArray *)deviceArray { // NSLog(@"onDeviceFound:%lu",(unsigned long)deviceArray.count); ListPeripheral = [NSArray arrayWithArray:deviceArray]; for(int i =0;i 10){ [ListFLTHr removeAllObjects]; } [ListFLTHr addObject:realHr]; } //设备电量回调 - (void)SDKDianciStr:(NSString *_Nullable)DianStr { // NSLog(@"SDKDianciStr:%@",[[NSString alloc] initWithFormat:@"%@已连接 电量 %@%%", BleDevice.DeviceName,DianStr]); BleDevice.PowerLevel = DianStr; } @end