// // ShiCaoPeriodVC.m // jiaPei // // Created by apple on 2017/2/7. // Copyright © 2017年 JCZ. All rights reserved. // #define SCReenBRIGHTTIME 300 #define SCREENBRIGHTLOWST 0.3 #import "ShiCaoPeriodVC.h" #import "ScanVC.h" #import #import "Evaluation.h" //#import "APViewController.h" #import "AllLightImagePickerController.h" #import "ShiCaotableView.h" #import //引入地图功能所有的头文件 #import //引入定位功能所有的头文件 #import //bd计算相关 //蓝牙 #import @interface ShiCaoPeriodVC () { NSMutableArray *detailLabArr; UILabel *timeLabel; UIButton *on_offBtn; UIView *backView;//计时结束弹框 NSTimer *timer; //trainview UIView *trainView; UITableView *mainTableView;//trainview addsubview maintableview NSMutableArray *trainViewLabs; UILabel *bgLabel; //注意事项 UIView *noticeView; UIButton *isForeverBtn; NSMutableDictionary *minuteTrainDic;//分钟学时用参数 签到和断线重连时候初始化 分钟学时发送之前更新字典 NSMutableDictionary *gatherTrainDic;//汇总学时用参数 签到和断线重连时候初始化 分钟学时发送之前更新字典 并存本地 短线重连用来恢复计时 NSArray *minuteTrainArray;//分钟学时数组 用于汇总学时时候 获取本地库未上传的分钟学时 NSDictionary *scanDic;//扫描二维码获取到的数据 NSArray *coachdataArray;//教练数据 NSMutableArray *gpsArray; NSString *classId; //课堂ID NSString *classCode; //课程编码 NSString *trainNum; //学时编号 NSString *trainOrderNum;//学时编号用序列 每天置0 BOOL isPlanPeriod; //是否是计划计时 NSString *orderId; //订单ID NSInteger seconds; //定时器时间 NSDictionary *finishDataDic; //汇总完毕 服务器返回数据 BOOL isVoice; //是否开启语音提醒 默认开启 NSMutableArray *dataSourceArray; //表的数据源 组成部分:颜色数字+提示字 1为红色失败 2为绿色成功 BOOL isImitate; //是否正在模拟计时 BOOL isTerminal; //是否是终端实操计时 BOOL isForceKeYi; //是否集中理论学习 //拍照倒计时 UIButton *countDownBtn; UIView *countDownView; NSInteger photoTime; BOOL isSubjectTwoSignIn; //签到拍照 NSTimer *signInTimer; //地图定位 BMKLocationManager *baiduLocationMan; CLLocationCoordinate2D myCoordinate; NSMutableDictionary *gpsDic; //某个点的信息 NSDictionary *lastGPSDic; //上个点的信息 用于计算累加里程 CGFloat mileageFloat;//累加里程 每分钟置为0.0000 CLLocationManager *locationManager;//系统gps //系统参数 NSInteger startPhotoTime;//拍照开始时间 NSInteger endPhotoTime;//拍照结束时间 NSInteger systemMaxSpeed;//最大速度限制 //计时省电相关 CGFloat _scrStartBright;//记录屏幕初始亮度 NSInteger _scrBrtTime;//进入省电模式前的时间 BOOL _flag;//判断是否是非学员操作(代码修改)变化的屏幕亮度 //蓝牙相关 NSString *peripheralName;//蓝牙名称 BOOL dataIsLack;//如果为yes代表数据不完整 需要下次接收到的数据拼接 NSString *lastData;//接收蓝牙数据时 一个数据包分次返回时 之前的数据 NSString *blueToothOrder;//最新的蓝牙命令 用于蓝牙未回应重新作操作 NSInteger reOrderCount;//蓝牙重新请求的次数 如果大于三次 不继续请求 接收到回应就重置 防治无限请求蓝牙 NSInteger bTRequestTime;//蓝牙响应时间 主要用于拍照相关命令 如果超过三秒 没回应 重新发拍照命令 NSInteger orderNum;//图片分包数 NSString *imageData;//图片数据 NSInteger imgLongth;//图片的总长度 或者每个包的长度 NSInteger lastLongth;//最后一个包的长度 BOOL isLastOrder;//是否是获取最后一个包的命令 BOOL isConnectBlueTooth;//是否与蓝牙连接状态 NSInteger disconnectSeconds;//蓝牙断开的时长 NSInteger heartSeconds;//心跳包间隔时间 每次心跳命令清零 如果大于180 则视为非法蓝牙连接 BOOL isNeedSignIn; //蓝牙心跳包验证中是否需要签到 只有在扫描完二维码的时候 将该值设置为YES yes的时候需要签到 BOOL stopReplyHeart;//停止回复心跳包验证 获取OBD数据和拍照前三秒置为yes 不与心跳包交互 NSInteger takePhotoFailCount;//人脸比对失败次数 超过三次会停止计时 BOOL isNotPlayAudio; } //蓝牙 @property (nonatomic, strong) CBCentralManager *cbcManager; /** 已连接的外设*/ @property (nonatomic, strong) CBPeripheral *peripheral; /** 要写入的特征值*/ @property (nonatomic, strong) CBCharacteristic *writeCharacteristic; /** 要读的特征值*/ @property (nonatomic, strong) CBCharacteristic *readCharacteristic; @property (nonatomic, strong) UILabel *blueToothLabel; @property (nonatomic, strong) UIImageView *photoImg; @end @implementation ShiCaoPeriodVC - (void)viewDidLoad { [super viewDidLoad]; self.title = @"实操计时"; self.view.backgroundColor = backGroundColor; _haveBlueTooth = NO; isForceKeYi = NO; isImitate = NO; isTerminal = NO; gatherTrainDic = nil; coachdataArray = [NSArray new];//初始化教练数据 isSubjectTwoSignIn = NO; isNeedSignIn = NO; isConnectBlueTooth = NO; isNotPlayAudio = NO; //屏幕亮度相关 _scrStartBright = [[UIScreen mainScreen] brightness]; _scrBrtTime = SCReenBRIGHTTIME; _flag = NO; UIBarButtonItem* backBbi = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"backIcon.png"] style:UIBarButtonItemStylePlain target:self action:@selector(goBackByNavigation)]; [self.navigationItem setLeftBarButtonItem:backBbi]; CGFloat varY = 0; detailLabArr = [NSMutableArray new]; for (int i=0; i<3; i++) { CGFloat wid = kSize.width-50; UILabel *detailLab; detailLab = [[UILabel alloc]initWithFrame:CGRectMake(25+wid*(0.4+(i-1)*0.3), varY, wid*0.3, 40)]; [detailLab setText:@"" Font:FontTitle TextColor:kTitleColor Alignment:NSTextAlignmentCenter]; if (i==0) { detailLab = [[UILabel alloc]initWithFrame:CGRectMake(25, varY, wid*0.4, 40)]; [detailLab setText:@"" Font:FontTitle TextColor:kTitleColor Alignment:NSTextAlignmentLeft]; } [self.view addSubview:detailLab]; [detailLabArr addObject:detailLab]; } varY += 10 + 40; timeLabel = [[UILabel alloc] initWithFrame:CGRectMake(25, varY, kSize.width - 50, kSize.width/3.0)]; timeLabel.backgroundColor = [UIColor whiteColor]; [timeLabel borderColor:RQlineColor width:2 cornorRadius:10]; [timeLabel setText:@"00:00:00" Font:44 TextColor:kTitleColor Alignment:NSTextAlignmentCenter]; [self.view addSubview:timeLabel]; //开启关闭语音 isVoice = YES; dataSourceArray = [NSMutableArray array]; varY += 20+kSize.width/3.0; trainView = [[UIView alloc] initWithFrame:CGRectMake(0, varY, kSize.width, kSize.height - varY - kNavOffSet - 50 - kSafeAreaBottomHeight)]; trainView.backgroundColor = backGroundColor; [self.view addSubview:trainView]; trainView.hidden = YES; varY = 0; // trainViewLabs = [NSMutableArray new]; // NSArray * labtitles = @[@"当前计时时长",@"总时长",@"需要时长"]; // CGFloat labWid = (kSize.width-30)/3; // for (int i=0; i 0?NO:YES];//屏幕常亮 } if (locationManager) { [locationManager startUpdatingLocation]; }else{ [baiduLocationMan startUpdatingLocation]; } //取消右滑「只针对拍照(present相机,再返回)有效,其它情况需走myuinavigation里限制」 self.navigationController.interactivePopGestureRecognizer.enabled = NO; } -(void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; if (signInTimer) { [signInTimer invalidate]; signInTimer = nil; } if (peripheralName.length < 1) { if (locationManager) { [locationManager stopUpdatingLocation]; }else{ [baiduLocationMan stopUpdatingLocation]; } } [[UIApplication sharedApplication] setIdleTimerDisabled:NO];//关闭屏幕常亮 } - (void)goBackByNavigation { [self setScreenBright]; if (timer) { [RQ_SHARE_FUNCTION showAlertWithTitle:@"温馨提示" message:@"警告:退出当前页面将暂停实操计时,是否退出" alertControllerStyle:UIAlertControllerStyleAlert cancelButtonTitle:@"取消" otherButtonTitles:@[@"确定"] otherButtonStyles:nil showInWindow:NO completion:^(NSUInteger selectedOtherButtonIndex) { if (selectedOtherButtonIndex == 0) { [[UIApplication sharedApplication] setIdleTimerDisabled:NO];//关闭屏幕常亮 timer.fireDate = [NSDate distantFuture]; [self.view endEditing:1]; [self.navigationController popViewControllerAnimated:YES]; } }]; }else{ [self.view endEditing:1]; [self.navigationController popViewControllerAnimated:YES]; } } - (void)showAlertForBeginOrEndPeriodWithString:(NSString *)aString { [RQ_SHARE_FUNCTION showAlertWithTitle:@"温馨提示" message:aString alertControllerStyle:UIAlertControllerStyleAlert cancelButtonTitle:@"取消" otherButtonTitles:@[@"确定"] otherButtonStyles:nil showInWindow:NO completion:^(NSUInteger selectedOtherButtonIndex) { [self setScreenBright]; if (selectedOtherButtonIndex == 0) { //调取相机扫描二维码 ScanVC *scan = [[ScanVC alloc] init]; scan.type = 1; [scan scanBlock:^(NSDictionary *dic) { scanDic = dic; _haveBlueTooth = NO; NSArray *dataArray = [dic[@"dataString"] componentsSeparatedByString:@";"]; if (dataArray.count < 8) {//不开启蓝牙判断 peripheralName = @""; [self startPeriod]; }else { NSString *blueToothName = dataArray[6]; if ([blueToothName isEqualToString:@"NONAME"]) {//不开启蓝牙判断 peripheralName = @""; [self startPeriod]; }else {//开启蓝牙判断 _haveBlueTooth = YES; isNeedSignIn = YES; peripheralName = dataArray[6]; [self searchBlueTooth]; } } // NSLog(@"peripheralName----><>%@",peripheralName); }]; [self navPushHideTabbarToVC:scan]; } }]; } - (void)btnClick:(UIButton *)sender { [self setScreenBright]; if (sender.tag == 1) { //开始计时 if (myCoordinate.latitude < 1) { ShowMsg(@"正在获取您的位置,请稍后再试!"); return; } if (myDelegate.timer || isImitate) { ShowMsg(@"请先关闭其他计时"); return; } if (isForceKeYi) { ShowMsg(@"当前账户正在进行集中理论学习,无法进行此操作"); return; } if (isTerminal) { ShowMsg(@"当前账户正在终端实操计时,无法进行此操作"); return; } [self showAlertForBeginOrEndPeriodWithString:@"请扫描教练手机二维码开始计时"]; return; } if (sender.tag == 2) { //结束计时 查本地数据库有没有未上传的数据 有的话 全部上传 结束成功 更改按钮状态和tag [RQ_SHARE_FUNCTION showAlertWithTitle:@"温馨提示" message:@"请扫描教练手机二维码结束计时" alertControllerStyle:UIAlertControllerStyleAlert cancelButtonTitle:@"取消" otherButtonTitles:@[@"确定"] otherButtonStyles:nil showInWindow:NO completion:^(NSUInteger selectedOtherButtonIndex) { if (selectedOtherButtonIndex == 0) { [self scanQrCode]; } }]; if (peripheralName.length == 0) { if ([gatherTrainDic.allKeys containsObject:@"comparisonPhoto"]) { NSArray *photoArray = gatherTrainDic[@"comparisonPhoto"]; if ([photoArray isKindOfClass:[NSArray class]]) { NSString *method = @"comparisonPhoto"; [jiaPeiManager requestAnythingWithURL:method array:photoArray data:nil completion:^(NSDictionary * root) { if (!root) { return ; } if ([root[@"code"] isEqualToString:@"0"]) { [gatherTrainDic removeObjectForKey:@"comparisonPhoto"]; [self saveGatherTrainDic]; } }]; } } } return; } //结束失败 重新汇总学时 if (sender.tag == 3) { minuteTrainArray = [DB_Helper quearySCTrainWithClassId:gatherTrainDic[@"classId"]]; if (minuteTrainArray.count > 0) { //去上传未上传的学时 上传完调 uploadSignOutOrClassRecord [self uploadAppTrainPl]; }else{ [self uploadSignOutOrClassRecord]; } if (peripheralName.length == 0) { if ([gatherTrainDic.allKeys containsObject:@"comparisonPhoto"]) { NSArray *photoArray = gatherTrainDic[@"comparisonPhoto"]; if ([photoArray isKindOfClass:[NSArray class]]) { NSString *method = @"comparisonPhoto"; [jiaPeiManager requestAnythingWithURL:method array:photoArray data:nil completion:^(NSDictionary * root) { if (!root) { return ; } if ([root[@"code"] isEqualToString:@"0"]) { [gatherTrainDic removeObjectForKey:@"comparisonPhoto"]; [self saveGatherTrainDic]; } }]; } } } return; } //点击拍照 弹出提醒 if (sender.tag == 7) { countDownBtn.selected = !countDownBtn.selected; if (countDownBtn.selected) { //弹出弹窗assign_btn countDownView = [[UIView alloc] initWithFrame:countDownBtn.frame]; [countDownView setRound]; [self.view addSubview:countDownView]; UIImageView *imageView = [[UIImageView alloc] initWithFrame:countDownView.bounds]; //拉伸图片 UIImage * image = [UIImage imageNamed:@"assign_btn"]; //计算左边端盖 NSInteger leftCap = image.size.width * 0.5f; //计算顶部端盖 NSInteger topCap = image.size.height * 0.5f; //拉伸imageView的大小 需要传入两个值 左端盖 和上端盖 image = [image stretchableImageWithLeftCapWidth:leftCap topCapHeight:topCap]; imageView.image = image; [countDownView addSubview:imageView]; UILabel *label = [[UILabel alloc] initWithFrame:countDownView.bounds]; label.backgroundColor = [UIColor clearColor]; NSString * str = @"提示:拍照验证期间,实操计时将暂停直到完成拍照,退出拍照将结束计时"; [label setText:str Font:Font17 TextColor:kTitleColor]; label.numberOfLines = 0; [countDownView addSubview:label]; [self.view bringSubviewToFront:countDownBtn]; [UIView animateWithDuration:.3 animations:^{ CGFloat labHeight = [str heightForWid:kSize.width - 110 -40 Font:Font17]; countDownView.frame = CGRectMake(20, countDownBtn.y + countDownBtn.height - labHeight -20, kSize.width - 110, labHeight+20); imageView.frame = countDownView.bounds; label.frame = CGRectMake(20, 10, countDownView.bounds.size.width - 40, labHeight); } completion:nil]; }else{ //关闭弹窗 [UIView animateWithDuration:.3 animations:^{ countDownView.frame = countDownBtn.frame; } completion:^(BOOL finished) { [countDownView removeFromSuperview]; }]; } return; } if (sender.tag == 8) {//暂不支付 不评论 [backView removeFromSuperview]; return; } // if (sender.tag == 9) {//立即支付 // // [backView removeFromSuperview]; // // NSDictionary *dic = @{@"RO_START_TIME":finishDataDic[@"startTime"], // @"RO_END_TIME":finishDataDic[@"endTime"], // @"MINUTE":finishDataDic[@"validTime"], // @"RO_COACH_NAME":gatherTrainDic[@"coachName"], // @"PRICE":gatherTrainDic[@"price"], // @"RO_MONEY":finishDataDic[@"currentMoney"]}; // // APViewController *ap = [[APViewController alloc] init]; // ap.orderDic = dic; // [self navPushHideTabbarToVC:ap]; // // return; // } if (sender.tag == 10) {//发起评价 计划订单评价 非计划学时评价 [backView removeFromSuperview]; NSMutableDictionary * dic = [NSMutableDictionary new]; [dic setValue:gatherTrainDic[@"subject"] forKey:@"kmStr"]; [dic setValue:gatherTrainDic[@"coachId"] forKey:@"coachId"]; [dic setValue:gatherTrainDic[@"classId"] forKey:@"classId"]; [dic setValue:gatherTrainDic[@"coachName"] forKey:@"coachName"]; Evaluation * evVC = [[Evaluation alloc]init]; if ([gatherTrainDic[@"isPlan"] isEqualToString:@"1"]) { //计划 evVC.orderDic = dic; }else{//非计划 evVC.xsDic = dic; } [self navPushHideTabbarToVC:evVC]; return; } if (sender.tag == 20) {//是否还要显示 sender.selected = !sender.selected; if (sender.selected) { sender.backgroundColor = RQ_MAIN_COLOR; }else{ sender.backgroundColor = [UIColor clearColor]; } } if (sender.tag == 21) { [noticeView removeFromSuperview]; [self.view endEditing:1]; [self.navigationController popViewControllerAnimated:YES]; } if (sender.tag == 22) { if (isForeverBtn.selected) { //不在显示 本地存个字段 [[NSUserDefaults standardUserDefaults] setValue:@"doNotShowNotice" forKey:@"isShowNotice"]; } [noticeView removeFromSuperview]; } } -(void)switchAction:(id)sender { [self setScreenBright]; UISwitch *switchButton = (UISwitch*)sender; BOOL isButtonOn = [switchButton isOn]; if (isButtonOn) { //showSwitchValue.text = @"是"; isVoice = YES; }else { isVoice = NO; } } - (void)isUploadLocation { on_offBtn.hidden = NO; [self getGatherTrainDic]; if ([gatherTrainDic isKindOfClass:[NSMutableDictionary class]]) { if ([gatherTrainDic[@"isOver"] isEqualToString:@"0"]) { //表明之前的计时没有结束。恢复计时吧 //蓝牙 peripheralName = gatherTrainDic[@"blueName"]; if (peripheralName.length > 0) { //如果之前有蓝牙 现在也要重新开启起来 self.haveBlueTooth = YES; [self searchBlueTooth]; [self goToBackgroundTask]; } minuteTrainDic = [NSMutableDictionary dictionary]; [minuteTrainDic setValue:gatherTrainDic[@"classId"] forKey:@"classId"]; [minuteTrainDic setValue:gatherTrainDic[@"classCode"] forKey:@"classCode"]; [minuteTrainDic setValue:gatherTrainDic[@"trainNum"] forKey:@"trainNum"]; [minuteTrainDic setValue:@"0.0000" forKey:@"obdMileage"]; [minuteTrainDic setValue:@"0" forKey:@"obdRotationSpeed"]; trainNum = gatherTrainDic[@"trainNum"]; gpsArray = [NSMutableArray array]; seconds = [gatherTrainDic[@"allTime"] integerValue]; photoTime = [gatherTrainDic[@"photoTime"] integerValue]; timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerRun) userInfo:nil repeats:YES]; trainView.hidden = NO; myDelegate.timer = timer; [on_offBtn setTitle:@"结束计时" forState:UIControlStateNormal]; on_offBtn.tag = 2; myDelegate.scPeriodVC = self; [[UIApplication sharedApplication] setIdleTimerDisabled:peripheralName.length > 0?NO:YES];//屏幕常亮 [Tools playAudioWithString:@"断线虫连成功,已恢复计时"]; [self reloadDetailLab]; } if ([gatherTrainDic[@"isOver"] isEqualToString:@"2"]) { //表明之前的计时结束 但是上传失败 peripheralName = gatherTrainDic[@"blueName"]; [self reloadDetailLab]; minuteTrainDic = [NSMutableDictionary dictionary]; seconds = [gatherTrainDic[@"allTime"] integerValue]; int hour = (int)seconds / 3600; int min = (int)seconds % 3600 / 60; int second = (int)seconds % 3600 % 60; NSString *min_s; NSString *second_s; if (min<10) { min_s=[NSString stringWithFormat:@"0%d",min]; }else{ min_s=[NSString stringWithFormat:@"%d",min]; } if (second<10) { second_s=[NSString stringWithFormat:@"0%d",second]; }else{ second_s=[NSString stringWithFormat:@"%d",second]; } timeLabel.text = [NSString stringWithFormat:@"0%d:%@:%@",hour,min_s,second_s]; [on_offBtn setTitle:@"汇总学时" forState:UIControlStateNormal]; on_offBtn.tag = 3; } } } #pragma mark 蓝牙连接通过 去签到计时 - (void)startPeriod { //@"scanType":@"scPeriod",@"dataString":@"" if ([scanDic[@"scanType"] isEqualToString:@"scPeriod"]) { //非计划实操计时 isPlanPeriod = NO; coachdataArray = [scanDic[@"dataString"] componentsSeparatedByString:@";"]; if (coachdataArray.count < 6) { ShowMsg(@"教练信息获取失败!请重试"); return; } // 教练outID 教练姓名 价格 科目 电话号码 终端设备号 蓝牙名称 有效时间 gatherTrainDic = [NSMutableDictionary dictionary]; [gatherTrainDic setValue:coachdataArray[0] forKey:@"coachId"]; [gatherTrainDic setValue:coachdataArray[1] forKey:@"coachName"]; [gatherTrainDic setValue:coachdataArray[2] forKey:@"price"]; [gatherTrainDic setValue:coachdataArray[3] forKey:@"subject"]; [gatherTrainDic setValue:coachdataArray[4] forKey:@"coachSim"]; [gatherTrainDic setValue:coachdataArray[5] forKey:@"deviceNum"]; [gatherTrainDic setValue:peripheralName forKey:@"blueName"]; //生成各种编码 签到 生成定时器 改变按钮状态 然后上传分钟学时 然后做断网处理 [self getClassIdAndSoOn]; [self uploadStuSign]; }else if ([scanDic[@"scanType"] isEqualToString:@"jhPeriod"]){ //计划实操计时 isPlanPeriod = YES; //参数分别是 教练outID 教练姓名 学生ID 预约ID 电话号码 终端设备号 蓝牙名称 有效时间 coachdataArray = [scanDic[@"dataString"] componentsSeparatedByString:@";"]; if (coachdataArray.count < 6) { ShowMsg(@"教练信息获取失败!请重试"); return; } //计划的要先生成各种ID 需要用到deviceNum这个参数 gatherTrainDic = [NSMutableDictionary dictionary]; [gatherTrainDic setValue:coachdataArray[0] forKey:@"coachId"]; [gatherTrainDic setValue:coachdataArray[1] forKey:@"coachName"]; [gatherTrainDic setValue:coachdataArray[2] forKey:@"studentId"]; [gatherTrainDic setValue:coachdataArray[3] forKey:@"reserveId"]; [gatherTrainDic setValue:coachdataArray[4] forKey:@"coachSim"]; [gatherTrainDic setValue:coachdataArray[5] forKey:@"deviceNum"]; [gatherTrainDic setValue:peripheralName forKey:@"blueName"]; [self getClassIdAndSoOn]; //生成订单 [self uploadReserveOrder]; }else if ([scanDic[@"scanType"] isEqualToString:@"allSignOut"]) { //先关闭定时器 [timer invalidate]; timer = nil; myDelegate.timer = nil; myDelegate.scPeriodVC = nil; [[UIApplication sharedApplication] setIdleTimerDisabled:NO];//关闭屏幕常亮 on_offBtn.tag = 3;//表明点了结束计时 但没结束成功的情况 [gatherTrainDic setValue:@"2" forKey:@"isOver"]; [self saveGatherTrainDic]; minuteTrainArray = [DB_Helper quearySCTrainWithClassId:gatherTrainDic[@"classId"]]; if (minuteTrainArray.count > 0) { [self uploadAppTrainPl]; }else{ [self uploadSignOutOrClassRecord]; } } } #pragma mark gps定位相关 //断网情况开启gps定位 -(void)setGPSLocationService{ //实例化manager locationManager=[[CLLocationManager alloc]init]; //设置代理 locationManager.delegate=self; //设置定位精度 //定位要求的精度越高、属性distanceFilter的值越小,应用程序的耗电量就越大。 locationManager.desiredAccuracy=kCLLocationAccuracyBest; //定位距离 locationManager.distanceFilter=kCLDistanceFilterNone;//一起燃烧 //申请定位许可,iOS8以后特有 /** 由于IOS8中定位的授权机制改变 需要进行手动授权 * 获取授权认证,两个方法: * [self.locationManager requestWhenInUseAuthorization]; * [self.locationManager requestAlwaysAuthorization]; */ if([locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) { [locationManager requestAlwaysAuthorization]; } //开始定位 [locationManager startUpdatingLocation]; } - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(nonnull NSArray *)locations { CLLocation *loctaion = [locations firstObject]; //打印出经度和纬度 CLLocationCoordinate2D coordinate = loctaion.coordinate; //解密加密后的坐标字典 CLLocationCoordinate2D baiduCoor = BMKCoordTrans(coordinate, BMK_COORDTYPE_GPS, BMK_COORDTYPE_BD09LL);//转换GPS坐标至百度坐标(加密后的坐标) myCoordinate = baiduCoor; NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; NSString *strDate = [dateFormatter stringFromDate:loctaion.timestamp]; NSString *courseString = [NSString stringWithFormat:@"%.0f",loctaion.course]; if ([courseString containsString:@"-"]) { courseString = [[courseString componentsSeparatedByString:@"-"] lastObject]; if ([courseString containsString:@"."]) { courseString = [[courseString componentsSeparatedByString:@"."] firstObject]; } } gpsDic = [NSMutableDictionary dictionaryWithDictionary:@{ @"latitude":[NSString stringWithFormat:@"%f",baiduCoor.latitude], @"longitude":[NSString stringWithFormat:@"%f",baiduCoor.longitude], @"altitude":[NSString stringWithFormat:@"%.2f",loctaion.altitude], @"course":courseString, @"timestamp":strDate, @"speed":[NSString stringWithFormat:@"%.4f",loctaion.speed*3.6 > 0.0000 ? loctaion.speed*3.6 : 0.0000] }]; if (loctaion.speed*3.6 > systemMaxSpeed) { [Tools playAudioWithString:[NSString stringWithFormat:@"当前车速为%.1f,您已超速,请注意控制车速",[gpsDic[@"speed"] floatValue]]]; } //距离累加 // if (lastGPSDic) { // mileageFloat += [self getDistance]; // } // // lastGPSDic = gpsDic; // NSLog(@"系统定位--\n经度(对应百度坐标系):%f \n纬度(对应百度坐标系):%f \n海拔:%f \n方向(<0无效):%f \n时间:%@ \n速度(<0无效): %f", // baiduCoor.latitude,//经度Stringlon // baiduCoor.longitude,//纬度Stringlat // newLocation.altitude,//海拔Integerelevation // newLocation.course,//方向Integerdirection // strDate,//信息时间StringreceiveTimeGPS // newLocation.speed/3.6//卫星定位速度速度doublelocationSpeed // ); } #pragma mark 百度地图 /** * @brief 当定位发生错误时,会调用代理的此方法。 * @param manager 定位 BMKLocationManager 类。 * @param error 返回的错误,参考 CLError 。 */ - (void)BMKLocationManager:(BMKLocationManager * _Nonnull)manager didFailWithError:(NSError * _Nullable)error{ ShowMsg([NSString stringWithFormat:@"获取位置错误:%@",error.description]); } /** * @brief 连续定位回调函数。 * @param manager 定位 BMKLocationManager 类。 * @param location 定位结果,参考BMKLocation。 * @param error 错误信息。 */ - (void)BMKLocationManager:(BMKLocationManager * _Nonnull)manager didUpdateLocation:(BMKLocation * _Nullable)location orError:(NSError * _Nullable)error{ if (location) { myCoordinate = location.location.coordinate; NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; NSString *strDate = [dateFormatter stringFromDate:location.location.timestamp]; CLLocationCoordinate2D baiduCoor = location.location.coordinate; NSString *courseString = [NSString stringWithFormat:@"%.0f",location.location.course]; if ([courseString containsString:@"-"]) { courseString = [[courseString componentsSeparatedByString:@"-"] lastObject]; if ([courseString containsString:@"."]) { courseString = [[courseString componentsSeparatedByString:@"."] firstObject]; } } gpsDic = [NSMutableDictionary dictionaryWithDictionary:@{ @"latitude":[NSString stringWithFormat:@"%f",baiduCoor.latitude], @"longitude":[NSString stringWithFormat:@"%f",baiduCoor.longitude], @"altitude":[NSString stringWithFormat:@"%.2f",location.location.altitude], @"course":courseString? : @"", @"timestamp":strDate? : @"", @"speed":[NSString stringWithFormat:@"%.4f",location.location.speed*3.6 > 0.0000 ? location.location.speed*3.6 : 0.0000] }]; if (location.location.speed*3.6 > systemMaxSpeed) { [Tools playAudioWithString:[NSString stringWithFormat:@"当前车速为%.1f,您已超速,请注意控制车速",[gpsDic[@"speed"] floatValue]]]; } //距离累加 // if (lastGPSDic) { // mileageFloat += [self getDistance]; // } // // lastGPSDic = gpsDic; // NSLog(@"BMKdidUpdateUserLocation \nlat %f,\nlong %f \n海拔 %f \n方向(<0无效):%f \n时间:%@ \n速度(<0无效): %f", // userLocation.location.coordinate.latitude,//经度Stringlon // userLocation.location.coordinate.longitude,//纬度Stringlat // userLocation.location.altitude,//海拔Integerelevation // userLocation.location.course,//方向Integerdirection // strDate,//信息时间StringreceiveTimeGPS // userLocation.location.speed*60*60/1000//卫星定位速度速度doublelocationSpeed // ); } } -(CGFloat)getDistance { CLLocation *newLocation = [[CLLocation alloc] initWithLatitude:[gpsDic[@"latitude"] floatValue] longitude:[gpsDic[@"longitude"] floatValue]]; CLLocation *lastLocation = [[CLLocation alloc] initWithLatitude:[lastGPSDic[@"latitude"] floatValue] longitude:[lastGPSDic[@"longitude"] floatValue]]; CLLocationDistance kilometers=[newLocation distanceFromLocation:lastLocation]/1000; return kilometers; } #pragma mark 拍照 - (void)takePhoto { if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]){ //创建pickerVC AllLightImagePickerController * pickerVC=[[AllLightImagePickerController alloc]init]; //设置图片来源类型:可以是相机/相册 /*UIImagePickerControllerSourceTypePhotoLibrary;相册 UIImagePickerControllerSourceTypeCamera;相机 */ pickerVC.sourceType=UIImagePickerControllerSourceTypeCamera; //是否可编辑。 //pickerVC.allowsEditing=NO; //设置代理 pickerVC.delegate=self; //前置摄像头 pickerVC.cameraDevice = UIImagePickerControllerCameraDeviceFront; //拍照模式 pickerVC.cameraCaptureMode = UIImagePickerControllerCameraCaptureModePhoto; //弹出pickerVC [self presentViewController:pickerVC animated:YES completion:^{ nil; //只要这个pickerVC没有释放你的屏幕常亮都自动设:no }]; //ShowMsg(@"三秒后自动拍照"); [Tools playAudioWithString:@"三秒后自动拍照"]; //延迟三秒自动拍照 [pickerVC performSelector:@selector(takePicture) withObject:nil afterDelay:4]; }else{ //打开相机失败 特殊情况比如相机硬件损坏 这里无法解决 UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:@"相机打开失败,请在“设置-极速驾培”中打开相机权限,否则将结束计时" preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:@"打开相机" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { [self takePhoto]; }]]; [alert addAction:[UIAlertAction actionWithTitle:@"结束计时" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { //结束计时 [RQ_SHARE_FUNCTION showAlertWithTitle:@"温馨提示" message:@"拍照失败,请扫描教练手机二维码结束计时" alertControllerStyle:UIAlertControllerStyleAlert cancelButtonTitle:@"确定" otherButtonTitles:nil otherButtonStyles:nil showInWindow:NO completion:^(NSUInteger selectedOtherButtonIndex) { [self scanQrCode]; }]; }]]; [self presentViewController:alert animated:true completion:nil]; } } -(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{ [picker dismissViewControllerAnimated:YES completion:^{ if ([[info objectForKey:UIImagePickerControllerMediaType] isEqualToString:@"public.image"]) { photoTime = 0; [gatherTrainDic setValue:[NSString stringWithFormat:@"%d",(int)photoTime] forKey:@"photoTime"]; [self saveGatherTrainDic]; //如果前面的allowediting设置为No的话,这里直接用originalImage好了 UIImage * image = info[UIImagePickerControllerEditedImage]; if (!image) { image = info[UIImagePickerControllerOriginalImage]; } //上传照片 开启定时 [timer setFireDate:[NSDate distantPast]]; [self upLoadPhotoWithImage:image]; } }]; } - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker { UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:@"警告:取消拍照将结束本次实操计时," preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:@"返回" style:UIAlertActionStyleCancel handler:nil]]; [alert addAction:[UIAlertAction actionWithTitle:@"结束计时" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { [picker dismissViewControllerAnimated:YES completion:^{ //结束计时 [RQ_SHARE_FUNCTION showAlertWithTitle:@"温馨提示" message:@"拍照失败,请扫描教练手机二维码结束计时" alertControllerStyle:UIAlertControllerStyleAlert cancelButtonTitle:@"确定" otherButtonTitles:nil otherButtonStyles:nil showInWindow:NO completion:^(NSUInteger selectedOtherButtonIndex) { [self scanQrCode]; }]; }]; }]]; [picker presentViewController:alert animated:true completion:nil]; } #pragma mark tableview -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return dataSourceArray.count; } -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"]; if (cell == nil) { cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cell"]; cell.selectionStyle = UITableViewCellSelectionStyleNone; } [cell.textLabel setText:[dataSourceArray[dataSourceArray.count - indexPath.row - 1] substringFromIndex:1] Font:Font17 TextColor:[[dataSourceArray[dataSourceArray.count - indexPath.row - 1] substringToIndex:1] isEqualToString:@"1"]?[UIColor redColor]:[UIColor blackColor]]; [cell.textLabel setNumberOfLines:0]; return cell; } #pragma mark 屏幕变暗相关 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ [super touchesBegan:touches withEvent:event]; [self setScreenBright]; } -(void)setScreenBright{ _scrBrtTime = SCReenBRIGHTTIME;//有交互就要重新设置时间 //如果是代码修改的屏幕亮度,并且记录值大于当前屏幕亮度 if (_flag == YES && _scrStartBright > [[UIScreen mainScreen] brightness]) { [[UIScreen mainScreen] setBrightness: _scrStartBright]; } } #pragma mark 教学信息更新 -(void)reloadDetailLab{ int i=0; for (UILabel * detailLab in detailLabArr) { if (i == 0) { detailLab.text = [NSString stringWithFormat:@"教练:%@",gatherTrainDic[@"coachName"]]; }else if (i == 1){ detailLab.text = [NSString stringWithFormat:@"科目:科%@",[gatherTrainDic[@"subject"] isEqualToString:@"2"]?@"二":@"三"]; }else{ if ([gatherTrainDic[@"price"] isEqualToString:@"免费"]) { detailLab.text = [NSString stringWithFormat:@"单价:%@",gatherTrainDic[@"price"]]; }else{ detailLab.text = [NSString stringWithFormat:@"单价:%@元",gatherTrainDic[@"price"]]; } } i++; } // [self refreshTrainViewLables]; } //-(void)refreshTrainViewLables{ // NSArray *values = [gatherTrainDic valueForKey:@"timesValue"]; // int i=0; // for (UILabel *lab in trainViewLabs) { // lab.text = values[i++]; // } //} #pragma mark 数据请求 //学员签到 - (void)uploadStuSign { [LoadingView showHUD]; if (![Util connectedToNetWork]) { showMsgUnconnect(); [self closeBlueTooth]; return; } //dataString: 教练outID 教练姓名 价格 科目 教练手机 终端编号 有效时间 NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; NSString *timeString = [dateFormatter stringFromDate:[NSDate date]]; NSMutableArray *arr=[NSMutableArray array]; [arr addPro:@"userId" Value:RQ_USER_MANAGER.currentUser._id]; [arr addPro:@"stuId" Value:RQ_USER_MANAGER.currentUser.outId]; [arr addPro:@"subject" Value:gatherTrainDic[@"subject"]]; [arr addPro:@"classId" Value:classId]; [arr addPro:@"dqbh" Value:RQ_USER_MANAGER.currentUser.city]; [arr addPro:@"coachId" Value:[coachdataArray firstObject]]; [arr addPro:@"sim" Value:RQ_USER_MANAGER.currentUser.telphone]; [arr addPro:@"gps" Value:[NSString stringWithFormat:@"%f,%f,%@,3",myCoordinate.longitude,myCoordinate.latitude,timeString]]; NSString* method = @"uploadStuSign"; [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) { RemoveHUD(); // NSDictionary * dic = root[@"body"]; //NSArray * values = @[dic[@"CURRENTTIME"],dic[@"TOTALTIME"],dic[@"NEEDTIME"]]; //存本地 //[gatherTrainDic setValue:values forKey:@"timesValue"]; // [self saveGatherTrainDic]; if (!root) { ShowMsg(@"签到失败!"); [Tools playAudioWithString:@"学员签到失败,请重试"]; if (isPlanPeriod) { [self delReserveOrder]; } [self closeBlueTooth]; gatherTrainDic = nil; [self saveGatherTrainDic]; return ; } if ([root[@"code"] isEqualToString:@"1"]) { ShowMsg(root[@"body"]); [Tools playAudioWithString:root[@"body"]]; if (isPlanPeriod) { [self delReserveOrder]; } [self closeBlueTooth]; return; } if (peripheralName.length > 0 && [gatherTrainDic[@"subject"] integerValue] == 2) { //OBD科二签到 要先拍照验证 [Tools playAudioWithString:@"签到成功,请面向摄像头进行人脸验证"]; UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:@"签到成功,点击“确认”按钮开始拍照,请面向摄像头" preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:@"确认" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { isSubjectTwoSignIn = YES; [self performSelector:@selector(takePhotoByBlueTooth) withObject:nil afterDelay:3]; signInTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(signInTimerRun) userInfo:nil repeats:YES]; }]]; [self presentViewController:alert animated:NO completion:nil]; }else { ShowMsg(@"签到成功!"); [Tools playAudioWithString:@"签到成功,开始实操计时,请系好安全带"]; isSubjectTwoSignIn = NO; [self beginTimer]; } }]; } - (void)beginTimer { //将之前的学时全部清空 [DB_Helper deleteAllSCTrain]; //刷新学时显示 [self reloadDetailLab]; [gatherTrainDic setValue:classId forKey:@"classId"]; [gatherTrainDic setValue:classCode forKey:@"classCode"]; [gatherTrainDic setValue:trainNum forKey:@"trainNum"]; [gatherTrainDic setValue:@"0" forKey:@"allPrice"]; [gatherTrainDic setValue:@"0.0000" forKey:@"allMileage"]; [gatherTrainDic setValue:@"0.0000" forKey:@"obdMileage"]; [gatherTrainDic setValue:@"0" forKey:@"allTime"];//秒 [gatherTrainDic setValue:isPlanPeriod == YES?@"1":@"2" forKey:@"isPlan"]; [gatherTrainDic setValue:@"0" forKey:@"isOver"]; //classId , classCode , trainNum , maxSpeed , mileage , gps , obdMileage , obdRotationSpeed minuteTrainDic = [NSMutableDictionary dictionary]; [minuteTrainDic setValue:classId forKey:@"classId"]; [minuteTrainDic setValue:classCode forKey:@"classCode"]; [minuteTrainDic setValue:trainNum forKey:@"trainNum"]; [minuteTrainDic setValue:@"0.0000" forKey:@"obdMileage"]; [minuteTrainDic setValue:@"0" forKey:@"obdRotationSpeed"]; [self saveGatherTrainDic];//保存至本地 可以用于断线重连 gpsArray = [NSMutableArray array]; mileageFloat = 0.0000; seconds = 0; disconnectSeconds = 0; photoTime = 0; timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerRun) userInfo:nil repeats:YES]; trainView.hidden = NO; myDelegate.timer = timer; myDelegate.scPeriodVC = self; [[UIApplication sharedApplication] setIdleTimerDisabled:peripheralName.length > 0?NO:YES];//屏幕常亮 if (peripheralName.length > 0) { [self goToBackgroundTask]; } [on_offBtn setTitle:@"结束计时" forState:UIControlStateNormal]; on_offBtn.tag = 2; } - (void)saveGatherTrainDic { NSString *filePath = [Tools getPathWithFileName:@"gatherTrainDic.plist"]; [gatherTrainDic writeToFile:filePath atomically:YES]; } - (void)getGatherTrainDic { NSString *filePath = [Tools getPathWithFileName:@"gatherTrainDic.plist"]; if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) { gatherTrainDic = [NSMutableDictionary dictionaryWithContentsOfFile:filePath]; } } - (void)getClassIdAndSoOn { //classId NSTimeInterval timeInterval = [[NSDate date] timeIntervalSince1970]*1000; NSString *timeString = [[[[NSString stringWithFormat:@"%f",timeInterval] substringFromIndex:1] componentsSeparatedByString:@"."] firstObject]; NSInteger redomNum = arc4random()%8999 + 1000; //NSInteger time = [[timeString substringToIndex:7] integerValue] - redomNum; //classId = [NSString stringWithFormat:@"%d%@",(int)time,[timeString substringFromIndex:7]]; classId = [NSString stringWithFormat:@"%d%@",(int)redomNum,timeString]; //课程编码 NSString *carTypeString = @"21"; if ([RQ_USER_MANAGER.currentUser.carType isEqualToString:@"A1"]) { carTypeString = @"01"; } if ([RQ_USER_MANAGER.currentUser.carType isEqualToString:@"A2"]) { carTypeString = @"02"; } if ([RQ_USER_MANAGER.currentUser.carType isEqualToString:@"A3"]) { carTypeString = @"03"; } if ([RQ_USER_MANAGER.currentUser.carType isEqualToString:@"B1"]) { carTypeString = @"11"; } if ([RQ_USER_MANAGER.currentUser.carType isEqualToString:@"B2"]) { carTypeString = @"12"; } if ([RQ_USER_MANAGER.currentUser.carType isEqualToString:@"C1"]) { carTypeString = @"21"; } if ([RQ_USER_MANAGER.currentUser.carType isEqualToString:@"C2"]) { carTypeString = @"22"; } if ([RQ_USER_MANAGER.currentUser.carType isEqualToString:@"C3"]) { carTypeString = @"23"; } if ([RQ_USER_MANAGER.currentUser.carType isEqualToString:@"C4"]) { carTypeString = @"24"; } if ([RQ_USER_MANAGER.currentUser.carType isEqualToString:@"C5"]) { carTypeString = @"25"; } if ([RQ_USER_MANAGER.currentUser.carType isEqualToString:@"D"]) { carTypeString = @"31"; } if ([RQ_USER_MANAGER.currentUser.carType isEqualToString:@"E"]) { carTypeString = @"32"; } if ([RQ_USER_MANAGER.currentUser.carType isEqualToString:@"F"]) { carTypeString = @"33"; } if ([RQ_USER_MANAGER.currentUser.carType isEqualToString:@"M"]) { carTypeString = @"41"; } if ([RQ_USER_MANAGER.currentUser.carType isEqualToString:@"N"]) { carTypeString = @"42"; } if ([RQ_USER_MANAGER.currentUser.carType isEqualToString:@"P"]) { carTypeString = @"43"; } classCode = [NSString stringWithFormat:@"1%@%@120000",carTypeString,coachdataArray[3]]; //学时编号 NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; [formatter setDateFormat:@"yyMMdd"]; NSString *dateString = [formatter stringFromDate:[NSDate date]]; NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; trainOrderNum = [userDefaults valueForKey:@"trainOrderNum"]; //17-02-09,20 //![trainOrderNum isKindOfClass:[NSString class]] if (trainOrderNum == nil || ![[[trainOrderNum componentsSeparatedByString:@","] firstObject] isEqualToString:dateString]) { [userDefaults setValue:[NSString stringWithFormat:@"%@,0",dateString] forKey:@"trainOrderNum"]; } trainOrderNum = [userDefaults valueForKey:@"trainOrderNum"]; NSString *trainString = @""; int trainInt = [[[trainOrderNum componentsSeparatedByString:@","] lastObject] intValue]; if (trainInt < 10) { trainString = [NSString stringWithFormat:@"000%d",trainInt]; }else if (trainInt < 100){ trainString = [NSString stringWithFormat:@"00%d",trainInt]; }else if (trainInt < 1000){ trainString = [NSString stringWithFormat:@"0%d",trainInt]; }else{ trainString = [NSString stringWithFormat:@"%d",trainInt]; } trainNum = [NSString stringWithFormat:@"%@%@%@",RQ_USER_MANAGER.currentUser.stuDevNum,dateString,trainString]; } - (void)signInTimerRun { if (isConnectBlueTooth) { //验证蓝牙拍照是否响应 if ([blueToothOrder containsString:@"AA2F"]) { if ([blueToothOrder isEqualToString:@"AA2FWAIT"]) { //代表拍照成功 但是没有比对完成 return; } bTRequestTime ++; //蓝牙没响应 重新发送命令 并且重发计时+1 if (bTRequestTime > 5) { bTRequestTime = 0; reOrderCount ++; if (reOrderCount < 3) { [self writeCharacteristic:self.peripheral characteristic:self.writeCharacteristic value:[self convertHexStrToData:blueToothOrder]]; }else { reOrderCount = 0; [self removeBlueToothLabel]; [Tools playAudioWithString:@"拍照失败!"]; [self showAlertTakePhotoFail]; } } } } } - (void)timerRun { if (!isConnectBlueTooth && peripheralName.length > 0) {//计时过程中蓝牙断开连接 disconnectSeconds ++; if (disconnectSeconds%5 == 0) { if (_cbcManager && self.peripheral) { [_cbcManager connectPeripheral:self.peripheral options:nil]; } } return; } if (isConnectBlueTooth) { //心跳包验证 如果没有心跳包交互 就关闭计时 if (![blueToothOrder containsString:@"AA2F"]) { heartSeconds ++; if (heartSeconds > 180) {//该蓝牙没有发送心跳包验证 视为非法蓝牙 [Tools playAudioWithString:@"当前蓝牙连接为非法连接,系统将结束计时"]; if (heartSeconds > 183) { //先关闭定时器 [timer invalidate]; timer = nil; myDelegate.timer = nil; //关闭蓝牙连接 [self closeBlueTooth]; on_offBtn.tag = 3;//表明点了结束计时 但没结束成功的情况 [gatherTrainDic setValue:@"2" forKey:@"isOver"]; [self saveGatherTrainDic]; minuteTrainArray = [DB_Helper quearySCTrainWithClassId:gatherTrainDic[@"classId"]]; if (minuteTrainArray.count > 0) { [self uploadAppTrainPl]; }else{ [self uploadSignOutOrClassRecord]; } } return; } } //验证蓝牙拍照是否响应 if ([blueToothOrder containsString:@"AA2F"]) { if ([blueToothOrder isEqualToString:@"AA2FWAIT"]) { //代表拍照成功 但是没有比对完成 return; } bTRequestTime ++; //蓝牙没响应 重新发送命令 并且重发计时+1 if (bTRequestTime > 4) { bTRequestTime = 0; reOrderCount ++; if (reOrderCount < 3) { [self writeCharacteristic:self.peripheral characteristic:self.writeCharacteristic value:[self convertHexStrToData:blueToothOrder]]; }else { reOrderCount = 0; [self removeBlueToothLabel]; blueToothOrder = @""; //失败次数超过3 重新拍照 或初始化拍照模块 if ([blueToothOrder isEqualToString:@"AA2F03040509"]) {//不能响应拍照命令 执行初始化 初始化完 继续拍照 //danson 这里不做初始化摄像头的操作了 这里直接恢复计时好了 //[Tools playAudioWithString:@"摄像头拍照失败,请报修"]; if (seconds > photoTime) { int num = (int)(seconds - photoTime)/60 + 10; photoTime += 60 * num; } }else {//获取数据失败 更改拍照时间 过一会继续尝试拍照 if (seconds > photoTime) { int num = (int)(seconds - photoTime)/60 + 10; photoTime += 60 * num; } } } } //拍照期间 暂停计时 这样就不用关闭定时器了 return; } } //计时器 seconds++; // NSLog(@"%d---->%d---->%@",seconds,photoTime,blueToothOrder); if (peripheralName.length > 0) { //------------蓝牙拍照--------------- if (seconds%3600 == 5) { //随机出来一个拍照的时间点 取余5开始选点可以避免和获取OBD的命令冲突 加60 是为了不是第一分钟拍照命令 photoTime = seconds + (arc4random()%(endPhotoTime - startPhotoTime) + startPhotoTime)*60 + 60; [gatherTrainDic setValue:[NSString stringWithFormat:@"%d",(int)photoTime] forKey:@"photoTime"]; [self saveGatherTrainDic]; } //测试 两分钟抓拍一次 // if (seconds%120 == 5) { // photoTime = seconds + 60; // [gatherTrainDic setValue:[NSString stringWithFormat:@"%d",(int)photoTime] forKey:@"photoTime"]; // [self saveGatherTrainDic]; // } if (seconds == photoTime - 120) { //拍照提示 [Tools playAudioWithString:@"两分钟后进行随机拍照,请准备"]; } if (seconds == photoTime - 10) { //拍照提示 if (myDelegate.isBackgroundTask) { [self addLocalNotificationWithAudio:@"takePhotoWarn.mp3"]; }else { [Tools playAudioWithString:@"五秒后进行拍照,请准备"]; } } if (seconds == photoTime - 3) { //停止心跳包的交互 stopReplyHeart = YES; } if (photoTime == seconds) {//拍照 [self takePhotoByBlueTooth]; //发起拍照命令 先将拍照时间加上60S 如果验证成功 置为0。防止拍照崩溃导致一重连就拍照 photoTime += 60; [gatherTrainDic setValue:[NSString stringWithFormat:@"%d",(int)photoTime] forKey:@"photoTime"]; [self saveGatherTrainDic]; } }else { //------------手机拍照--------------- if (seconds%3600 == 5) { //随机出来一个拍照的时间点 //photoTime = seconds + (arc4random()%30 + 30)*60; photoTime = seconds + (arc4random()%(endPhotoTime - startPhotoTime) + startPhotoTime)*60 + 25; [gatherTrainDic setValue:[NSString stringWithFormat:@"%d",(int)photoTime + 125] forKey:@"photoTime"]; [self saveGatherTrainDic]; } if (seconds == photoTime - 120) { //拍照提示 [Tools playAudioWithString:@"两分钟后将进行拍照检测,请准备"]; countDownBtn = [[UIButton alloc] initWithFrame:CGRectMake(kSize.width - 70, on_offBtn.y - 60, 50, 50)]; [countDownBtn borderColor:RQ_MAIN_COLOR width:1.0 cornorRadius:25.0]; [countDownBtn setTitle:@"120" textColor:RQ_MAIN_COLOR Font:FontLarger fotState:UIControlStateNormal]; [countDownBtn target:self tag:7]; [self.view addSubview:countDownBtn]; } if (countDownBtn) { [countDownBtn setTitle:[NSString stringWithFormat:@"%d",(int)(photoTime - seconds)] forState:UIControlStateNormal]; if (seconds == photoTime - 10){ [Tools playAudioWithString:@"十秒钟后将进入拍照页面"]; } if (photoTime == seconds) { [countDownBtn removeFromSuperview]; if (countDownView) { [countDownView removeFromSuperview]; } countDownBtn = nil; //暂停计时 [timer setFireDate:[NSDate distantFuture]]; //进入拍照页面哈 [self takePhoto]; } } } if (seconds%10 == 0) { //这个点要采集的时候的时间 所以用这个 NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; NSString *dateString = [dateFormatter stringFromDate:[NSDate date]]; [gpsDic setValue:dateString forKey:@"timestamp"]; NSDictionary *dict = [NSDictionary dictionaryWithDictionary:gpsDic]; [gpsArray addObject:dict]; [[UIApplication sharedApplication] setIdleTimerDisabled:NO]; [[UIApplication sharedApplication] setIdleTimerDisabled:peripheralName.length > 0?NO:YES];//屏幕常亮 } int remainder = (int)seconds%60; if (remainder == 57) { //停止心跳包的交互 stopReplyHeart = YES; } if (remainder == 0) { //每1分钟保存一次 然后上传分钟学时 动态数据从GPSDic中获取 然后处理 NSString *maxSpeed = @"0.0000"; NSString *gpsString = @""; NSDictionary *lastDic = nil; CGFloat tenSecondMileage = 0.0000; for (NSDictionary *dic in gpsArray) { if (lastDic) { CLLocation *newLocation = [[CLLocation alloc] initWithLatitude:[dic[@"latitude"] floatValue] longitude:[dic[@"longitude"] floatValue]]; CLLocation *lastLocation = [[CLLocation alloc] initWithLatitude:[lastDic[@"latitude"] floatValue] longitude:[lastDic[@"longitude"] floatValue]]; CLLocationDistance kilometers = [newLocation distanceFromLocation:lastLocation]/1000; tenSecondMileage = kilometers; mileageFloat += tenSecondMileage; } //最大速度 maxSpeed = [maxSpeed floatValue] > [dic[@"speed"] floatValue] ? maxSpeed : dic[@"speed"] ; gpsString = [gpsString stringByAppendingString:[NSString stringWithFormat:@"%@,%@,%@,%@,%@,%@,0,%@,%@;",dic[@"longitude"],dic[@"latitude"],dic[@"altitude"],dic[@"course"],dic[@"timestamp"],[dic[@"speed"] floatValue] > systemMaxSpeed ? @"1" : @"0" ,dic[@"speed"],[NSString stringWithFormat:@"%.4f",tenSecondMileage]]]; lastDic = dic; } if (gpsString.length > 0) { [gpsString substringToIndex:gpsString.length - 1]; } //生成新的trainNum 先取之前的(签到时候的或者上一分钟的) 后四位序列码+1。顺便存入userDefault NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; int OrderNum = [[[[userDefaults valueForKey:@"trainOrderNum"] componentsSeparatedByString:@","] lastObject] intValue] + 1; NSString *trainString = @""; if (OrderNum < 10) { trainString = [NSString stringWithFormat:@"000%d",OrderNum]; }else if (OrderNum < 100){ trainString = [NSString stringWithFormat:@"00%d",OrderNum]; }else if (OrderNum < 1000){ trainString = [NSString stringWithFormat:@"0%d",OrderNum]; }else{ trainString = [NSString stringWithFormat:@"%d",OrderNum]; } trainNum = [NSString stringWithFormat:@"%@%@",[trainNum substringToIndex:trainNum.length - 4],trainString]; //将trainOrderNum写入NSUserDefaults trainOrderNum = [NSString stringWithFormat:@"%@,%d",[[[userDefaults valueForKey:@"trainOrderNum"] componentsSeparatedByString:@","] firstObject],OrderNum]; [userDefaults setValue:trainOrderNum forKey:@"trainOrderNum"]; [minuteTrainDic setValue:maxSpeed forKey:@"maxSpeed"]; [minuteTrainDic setValue:[NSString stringWithFormat:@"%.4f",mileageFloat] forKey:@"mileage"]; [minuteTrainDic setValue:gpsString forKey:@"gps"]; [minuteTrainDic setValue:trainNum forKey:@"trainNum"]; //更新gatherTrainDic数据 并存入本地 CGFloat allMileage = [gatherTrainDic[@"allMileage"] floatValue]; allMileage += mileageFloat; [gatherTrainDic setValue:[NSString stringWithFormat:@"%.4f",allMileage] forKey:@"allMileage"]; [gatherTrainDic setValue:[NSString stringWithFormat:@"%d",(int)seconds] forKey:@"allTime"]; [gatherTrainDic setValue:trainNum forKey:@"trainNum"]; [self saveGatherTrainDic]; NSDictionary *dict = [NSDictionary dictionaryWithDictionary:minuteTrainDic]; [DB_Helper saveSCTrainWithDic:dict]; if (peripheralName.length < 1) { [self uploadAppTrainSingle]; }else { [self getCarInfo]; } //将可变参数置0 为下一分钟做准备 [gpsArray removeAllObjects]; mileageFloat = 0.0000; lastDic = nil; } //手机拍的照片 十分钟补传一次 if (seconds%600 == 0) { if (peripheralName.length == 0) { if ([gatherTrainDic.allKeys containsObject:@"comparisonPhoto"]) { NSArray *photoArray = gatherTrainDic[@"comparisonPhoto"]; if ([photoArray isKindOfClass:[NSArray class]]) { NSString *method = @"comparisonPhoto"; [jiaPeiManager requestAnythingWithURL:method array:photoArray data:nil completion:^(NSDictionary * root) { if (!root) { return ; } if ([root[@"code"] isEqualToString:@"0"]) { [gatherTrainDic removeObjectForKey:@"comparisonPhoto"]; [self saveGatherTrainDic]; } }]; } } } } //屏幕太亮 //这里存在一个0.300000012 > 0.3的问题,所以。。(尽管你设置它为0.3,但是获取到的就是略大0.3的) CGFloat count = [[UIScreen mainScreen] brightness] - SCREENBRIGHTLOWST; if (count >= 0.1) { _scrBrtTime--; _flag = NO;//这里再次进来说明有人设置了屏幕亮度 if (_scrBrtTime == 0) { _scrStartBright = [[UIScreen mainScreen] brightness];//记录 _flag = YES; [[UIScreen mainScreen] setBrightness: SCREENBRIGHTLOWST]; _scrBrtTime = SCReenBRIGHTTIME; } }else{ _scrBrtTime = SCReenBRIGHTTIME; _flag = NO; //>0 && <0.1 说明相等(0.3000001 == 0.3,也说明“没有”人为设置屏幕亮度 if (count > 0) { _flag = YES; } } //更新UI上的时间 int hour = (int)seconds / 3600; int min = (int)seconds % 3600 / 60; int second = (int)seconds % 3600 % 60; NSString *min_s; NSString *second_s; if (min<10) { min_s=[NSString stringWithFormat:@"0%d",min]; }else{ min_s=[NSString stringWithFormat:@"%d",min]; } if (second<10) { second_s=[NSString stringWithFormat:@"0%d",second]; }else{ second_s=[NSString stringWithFormat:@"%d",second]; } timeLabel.text = [NSString stringWithFormat:@"0%d:%@:%@",hour,min_s,second_s]; } //上传分钟学时 - (void)uploadAppTrainSingle { if (![Util connectedToNetWork]) { RemoveHUD(); if (isVoice) { [Tools playAudioWithString:@"无网络连接,学时上传失败,分钟学时已保存至本地!"]; } NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; [formatter setDateFormat:@"HH:mm"]; NSString *timeString = [formatter stringFromDate:[NSDate date]]; [dataSourceArray addObject:[NSString stringWithFormat:@"1%@ 速度%@km/h 里程%.0f米 分钟学时上传失败!",timeString,minuteTrainDic[@"maxSpeed"],[minuteTrainDic[@"obdMileage"] floatValue]*1000]]; [mainTableView reloadData]; //开启gps定位 if (!locationManager) { [self setGPSLocationService]; [baiduLocationMan stopUpdatingLocation]; } return; }else{ if (locationManager) { [locationManager stopUpdatingLocation]; locationManager.delegate = nil; locationManager = nil; [baiduLocationMan startUpdatingLocation]; } } //classId , classCode , trainNum , maxSpeed , mileage , gps , obdRotationSpeed , obdMileage NSMutableArray *arr=[NSMutableArray array]; [arr addPro:@"stuId" Value:RQ_USER_MANAGER.currentUser.outId]; [arr addPro:@"dqbh" Value:RQ_USER_MANAGER.currentUser.city]; [arr addPro:@"coachId" Value:gatherTrainDic[@"coachId"]]; [arr addPro:@"sim" Value:RQ_USER_MANAGER.currentUser.telphone]; [arr addPro:@"subject" Value:gatherTrainDic[@"subject"]]; [arr addPro:@"classId" Value:minuteTrainDic[@"classId"]]; [arr addPro:@"subjcode" Value:minuteTrainDic[@"classCode"]]; [arr addPro:@"trainNo" Value:minuteTrainDic[@"trainNum"]]; [arr addPro:@"maxSpeed" Value:minuteTrainDic[@"maxSpeed"]]; [arr addPro:@"mileAge" Value:minuteTrainDic[@"mileage"]]; [arr addPro:@"gps" Value:minuteTrainDic[@"gps"]]; [arr addPro:@"upType" Value:@"1"]; [arr addPro:@"imei" Value:[Tools getIDFV]]; //obd信息 [arr addPro:@"openObd" Value:peripheralName.length == 0 ? @"0" : @"1"]; [arr addPro:@"engineSpeed" Value:minuteTrainDic[@"obdRotationSpeed"]]; [arr addPro:@"obdMile" Value:minuteTrainDic[@"obdMileage"]]; NSString* method = @"uploadAppTrainSingle"; [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) { NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; [formatter setDateFormat:@"HH:mm"]; NSString *timeString = [formatter stringFromDate:[NSDate date]]; if (!root) { if (isVoice) { [Tools playAudioWithString:@"分钟学时上传失败!"]; } [dataSourceArray addObject:[NSString stringWithFormat:@"1%@ 速度%@km/h 里程%.0f米 分钟学时上传失败!",timeString,minuteTrainDic[@"maxSpeed"],[minuteTrainDic[@"obdMileage"] floatValue]*1000]]; [mainTableView reloadData]; return ; } if ([root[@"code"] isEqualToString:@"1"]) { if (isVoice) { [Tools playAudioWithString:[NSString stringWithFormat:@"%@,分钟学时上传失败!",root[@"body"]]]; } [dataSourceArray addObject:[NSString stringWithFormat:@"1%@ 速度%@km/h 里程%.0f米 分钟学时上传失败!",timeString,minuteTrainDic[@"maxSpeed"],[minuteTrainDic[@"obdMileage"] floatValue]*1000]]; [mainTableView reloadData]; return; } if ([root[@"code"] isEqualToString:@"2"]) { [DB_Helper deleteSCTrainWithTrainNum:trainNum]; if (isVoice) { [Tools playAudioWithString:[NSString stringWithFormat:@"%@,分钟学时上传失败!",root[@"body"]]]; } [dataSourceArray addObject:[NSString stringWithFormat:@"1%@ 速度%@km/h 里程%.0f米 分钟学时上传失败!",timeString,minuteTrainDic[@"maxSpeed"],[minuteTrainDic[@"obdMileage"] floatValue]*1000]]; [mainTableView reloadData]; return; } if (isVoice) { [Tools playAudioWithString:@"分钟学时上传成功!"]; } [dataSourceArray addObject:[NSString stringWithFormat:@"0%@ 速度%@km/h 里程%.0f米 分钟学时上传成功!",timeString,minuteTrainDic[@"maxSpeed"],[minuteTrainDic[@"obdMileage"] floatValue]*1000]]; [mainTableView reloadData]; [DB_Helper deleteSCTrainWithTrainNum:trainNum]; }]; } //上传分钟学时(批量) - (void)uploadAppTrainPl { if (![Util connectedToNetWork]) { if (isVoice) { [Tools playAudioWithString:@"分钟学时批量上传失败!"]; } NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; [formatter setDateFormat:@"HH:mm"]; NSString *timeString = [formatter stringFromDate:[NSDate date]]; [dataSourceArray addObject:[NSString stringWithFormat:@"1%@ 分钟学时批量上传失败!",timeString]]; return; } [self.view setUserInteractionEnabled:NO]; bgLabel = [[UILabel alloc] initWithFrame:CGRectMake(30, (kSize.height - 80)/2.0, kSize.width - 60, 70)]; bgLabel.backgroundColor = backGroundColor; [bgLabel setBoardWid:5 Color:contentTextColor CornerRadius:6]; [bgLabel setText:@"分钟学时批量上传中..." Font:24 TextColor:kTitleColor Alignment:NSTextAlignmentCenter]; [[UIApplication sharedApplication].keyWindow addSubview:bgLabel]; NSMutableArray *mArr = [NSMutableArray new];; for (NSDictionary *dic in minuteTrainArray) { NSMutableDictionary * csDic = [NSMutableDictionary new]; [csDic setValue:gatherTrainDic[@"subject"] forKey:@"subject"]; [csDic setValue:dic[@"trainNum"] forKey:@"trainNo"]; [csDic setValue:dic[@"mileage"] forKey:@"mileAge"]; [csDic setValue:@"1" forKey:@"upType"]; [csDic setValue:RQ_USER_MANAGER.currentUser.city forKey:@"dqbh"]; [csDic setValue:gatherTrainDic[@"coachId"] forKey:@"coachId"]; [csDic setValue:dic[@"maxSpeed"] forKey:@"maxSpeed"]; [csDic setValue:dic[@"classId"] forKey:@"classId"]; [csDic setValue:dic[@"classCode"] forKey:@"subjcode"]; [csDic setValue:dic[@"gps"] forKey:@"gps"]; [csDic setValue:RQ_USER_MANAGER.currentUser.telphone forKey:@"sim"]; [csDic setValue:RQ_USER_MANAGER.currentUser.outId forKey:@"stuId"]; NSString *openObd = peripheralName.length == 0 ? @"0" : @"1"; [csDic setValue:openObd forKey:@"openObd"]; [csDic setValue:dic[@"engineSpeed"] forKey:@"engineSpeed"]; [csDic setValue:dic[@"obdMile"] forKey:@"obdMile"]; [mArr addObject:csDic]; } NSError *error = nil; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:mArr options:NSJSONWritingPrettyPrinted error:&error]; NSString *jsonString = nil; if ([jsonData length] != 0 && error == nil){ // 使用这个方法的返回,我们就可以得到想要的JSON串 jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; }else{ ShowMsg(@"数据错误,请重试!"); } NSMutableArray *arr=[NSMutableArray array]; [arr addPro:@"trains" Value:jsonString]; [arr addPro:@"imei" Value:[Tools getIDFV]]; NSString* method = @"uploadAppTrainPl"; [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) { if (bgLabel) { [bgLabel removeFromSuperview]; bgLabel = nil; } [self.view setUserInteractionEnabled:YES]; NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; [formatter setDateFormat:@"HH:mm"]; NSString *timeString = [formatter stringFromDate:[NSDate date]]; if (!root) { if (isVoice) { [Tools playAudioWithString:@"分钟学时批量上传失败!"]; } [dataSourceArray addObject:[NSString stringWithFormat:@"1%@ 分钟学时批量上传失败!",timeString]]; return ; } if ([root[@"code"] isEqualToString:@"1"]) { if (isVoice) { [Tools playAudioWithString:[NSString stringWithFormat:@"%@,分钟学时批量上传失败!",root[@"body"]]]; } [dataSourceArray addObject:[NSString stringWithFormat:@"1%@ 分钟学时批量上传失败!",timeString]]; return; } if ([root[@"code"] isEqualToString:@"2"]) { for (NSDictionary *dic in minuteTrainArray){ NSInteger trainNumber = [[dic[@"trainNum"] substringFromIndex:[dic[@"trainNum"] length] - 4] intValue]; int OrderNum = [[[[[NSUserDefaults standardUserDefaults] valueForKey:@"trainOrderNum"] componentsSeparatedByString:@","] lastObject] intValue]; if (trainNumber < OrderNum) { [DB_Helper deleteSCTrainWithTrainNum:dic[@"trainNum"]]; } } if (isVoice) { [Tools playAudioWithString:@"分钟学时批量上传失败!"]; } [dataSourceArray addObject:[NSString stringWithFormat:@"1%@ 分钟学时批量上传失败!",timeString]]; return; } if (isVoice) { [Tools playAudioWithString:@"分钟学时批量上传成功!"]; } [dataSourceArray addObject:[NSString stringWithFormat:@"0%@ 分钟学时批量上传成功!",timeString]]; [DB_Helper deleteSCTrainWithClassId:gatherTrainDic[@"classId"]]; [self uploadSignOutOrClassRecord]; }]; } - (void)showStopFailAlertWithTag:(NSInteger)tag { [RQ_SHARE_FUNCTION showAlertWithTitle:@"温馨提示" message:@"结束计时失败,请重试!" alertControllerStyle:UIAlertControllerStyleAlert cancelButtonTitle:@"取消" otherButtonTitles:@[@"确定"] otherButtonStyles:nil showInWindow:NO completion:^(NSUInteger selectedOtherButtonIndex) { if (selectedOtherButtonIndex == 0) { [self scanQrCode]; } }]; } //调取相机扫描二维码 - (void)scanQrCode { [self setScreenBright]; ScanVC *scan = [[ScanVC alloc] init]; scan.type = 1; [scan scanBlock:^(NSDictionary *dic) { if ([dic[@"scanType"] isEqualToString:@"allSignOut"]) { //先关闭定时器 [timer invalidate]; timer = nil; myDelegate.timer = nil; //关闭蓝牙连接 [self closeBlueTooth]; //关闭后台任务 [self finishBackgroundTask];//如果没开启也可以调这个方法 [[UIApplication sharedApplication] setIdleTimerDisabled:NO];//关闭屏幕常亮 on_offBtn.tag = 3;//表明点了结束计时 但没结束成功的情况 [gatherTrainDic setValue:@"2" forKey:@"isOver"]; [self saveGatherTrainDic]; minuteTrainArray = [DB_Helper quearySCTrainWithClassId:gatherTrainDic[@"classId"]]; if (minuteTrainArray.count > 0) { [self uploadAppTrainPl]; } else { [self uploadSignOutOrClassRecord]; } } else { [RQ_SHARE_FUNCTION showAlertWithTitle:@"温馨提示" message:@"请扫描结束计时二维码" alertControllerStyle:UIAlertControllerStyleAlert cancelButtonTitle:@"确定" otherButtonTitles:nil otherButtonStyles:nil showInWindow:NO completion:^(NSUInteger selectedOtherButtonIndex) { [self scanQrCode]; }]; } }]; [self navPushHideTabbarToVC:scan]; } //结束计时并上传学时汇总 - (void)uploadSignOutOrClassRecord { if (![Util connectedToNetWork]) { showMsgUnconnect(); return; } [self.view setUserInteractionEnabled:NO]; bgLabel = [[UILabel alloc] initWithFrame:CGRectMake(30, (kSize.height - 80)/2.0, kSize.width - 60, 70)]; bgLabel.backgroundColor = backGroundColor; [bgLabel setBoardWid:5 Color:contentTextColor CornerRadius:6]; [bgLabel setText:@"学时汇总中..." Font:24 TextColor:kTitleColor Alignment:NSTextAlignmentCenter]; [[UIApplication sharedApplication].keyWindow addSubview:bgLabel]; NSMutableArray *arr=[NSMutableArray array]; [arr addPro:@"userId" Value:RQ_USER_MANAGER.currentUser._id]; [arr addPro:@"dqbh" Value:RQ_USER_MANAGER.currentUser.city]; [arr addPro:@"coachId" Value:gatherTrainDic[@"coachId"]]; [arr addPro:@"coachSim" Value:gatherTrainDic[@"coachSim"]]; [arr addPro:@"sim" Value:RQ_USER_MANAGER.currentUser.telphone]; [arr addPro:@"subjcode" Value:gatherTrainDic[@"classCode"]]; [arr addPro:@"trainTime" Value:[NSString stringWithFormat:@"%d",[gatherTrainDic[@"allTime"] intValue]/60]]; [arr addPro:@"trainMileage" Value:gatherTrainDic[@"allMileage"]]; [arr addPro:@"aveveLocity" Value:[NSString stringWithFormat:@"%.4f",[gatherTrainDic[@"allMileage"] floatValue]/[gatherTrainDic[@"allTime"] intValue]*3600.0]]; [arr addPro:@"classNo" Value:gatherTrainDic[@"classId"]]; [arr addPro:@"isPlan" Value:gatherTrainDic[@"isPlan"]]; [arr addPro:@"orderId" Value:gatherTrainDic[@"orderId"]]; [arr addPro:@"isBill" Value:[gatherTrainDic[@"price"] intValue] == 0?@"0":@"1"]; [arr addPro:@"money" Value:gatherTrainDic[@"price"]]; [arr addPro:@"gps" Value:[NSString stringWithFormat:@"%f,%f,%@,3",myCoordinate.longitude,myCoordinate.latitude,gpsDic[@"timestamp"]]]; [arr addPro:@"openObd" Value:peripheralName.length == 0 ? @"0" : @"1"]; [arr addPro:@"obdMile" Value:gatherTrainDic[@"obdMileage"]]; NSString* method = @"uploadSignOutOrClassRecord"; [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) { if (bgLabel) { [bgLabel removeFromSuperview]; bgLabel = nil; } [self.view setUserInteractionEnabled:YES]; if (!root) { ShowMsg(@"学时汇总失败"); [Tools playAudioWithString:@"学时汇总失败,无法结束计时"]; return ; } if ([root[@"code"] isEqualToString:@"1"]) { ShowMsg(root[@"body"]); [Tools playAudioWithString:root[@"body"]]; if ([root[@"body"] isEqualToString:@"您还未签到"]) { [on_offBtn setTitle:@"开始计时" forState:UIControlStateNormal]; on_offBtn.tag = 1; } return; } if ([gatherTrainDic[@"allTime"] intValue] > 59) { ShowMsg(@"学时汇总成功!"); //清除上传位置信息 [dataSourceArray removeAllObjects]; } //将本地状态置为结束 [gatherTrainDic setValue:@"1" forKey:@"isOver"]; [gatherTrainDic removeObjectForKey:@"classId"]; [self saveGatherTrainDic]; [dataSourceArray removeAllObjects]; trainView.hidden = YES; //关闭学时状态显示 [on_offBtn setTitle:@"开始计时" forState:UIControlStateNormal]; on_offBtn.tag = 1; [timeLabel setText:@"00:00:00" Font:44 TextColor:kTitleColor Alignment:NSTextAlignmentCenter]; if (countDownBtn) { [countDownBtn removeFromSuperview]; countDownBtn = nil; if (countDownView) { [countDownView removeFromSuperview]; } } myDelegate.scPeriodVC = nil; if (seconds < 60) { //计时小于一分钟 学时无效 [Tools playAudioWithString:@"本次计时小于一分钟,计时无效"]; }else{ [Tools playAudioWithString:@"本次计时结束"]; finishDataDic = root[@"body"]; [self setNotifiViewWithDic:root[@"body"]]; } //清空detailLab(top) for (UILabel *detailLab in detailLabArr) { detailLab.text = @""; } }]; } -(void)setNotifiViewWithDic:(NSDictionary *)dicBody{ NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; NSDate *startDate = [dateFormatter dateFromString:dicBody[@"startTime"]]; NSDate *endeDate = [dateFormatter dateFromString:dicBody[@"endTime"]]; NSTimeInterval value = [endeDate timeIntervalSinceDate:startDate]; int allHour = (int)value /3600; int allMin = (int)value /60%60; backView = [[UIView alloc] initWithFrame:kFrame]; backView.backgroundColor = [UIColor colorWithWhite:.01 alpha:.4]; //用window添加才能遮盖住导航栏 // [[UIApplication sharedApplication].keyWindow addSubview:backView]; [self.view addSubview:backView]; UIView *informationView = [[UIView alloc] initWithFrame:CGRectMake(20, kSize.height/2.0 - 200, kSize.width - 40, 270)]; informationView.backgroundColor = backGroundColor; [informationView borderColor:RQlineColor width:1 cornorRadius:10]; [backView addSubview:informationView]; CGFloat x,y,w,h,wid; wid = kSize.width - 40; #if 0 NSString * str = [NSString stringWithFormat:@"本次实操练习起始时间为%@至%@,总时长%d时%d分,有效学时为%d时%d分, 应付金额为%@元",dicBody[@"startTime"],dicBody[@"endTime"],allHour,allMin,validHour,validMin,dicBody[@"currentMoney"]]; x = 30; y = 50; w = wid-60; h = 90; UILabel *label = [[UILabel alloc] setxywh]; [label setText:str Font:FontLarger TextColor:kTitleColor Alignment:NSTextAlignmentLeft]; label.numberOfLines = 0; [informationView addSubview:label]; #else x = 0; y = 10; w = wid; h = 30; UILabel *label = [[UILabel alloc] setxywh]; [label setText:@"计时结束" Font:FontTitle TextColor:kTitleColor Alignment:NSTextAlignmentCenter]; [informationView addSubview:label]; x = 20; y = 20+h; w = wid-40; label = [[UILabel alloc] setxywh]; [label setText:[NSString stringWithFormat:@"开始时间: %@", dicBody[@"startTime"]] Font:NormalFont TextColor:kTitleColor Alignment:NSTextAlignmentLeft]; [informationView addSubview:label]; y += h; label = [[UILabel alloc] setxywh]; [label setText:[NSString stringWithFormat:@"结束时间: %@", dicBody[@"endTime"]] Font:NormalFont TextColor:kTitleColor Alignment:NSTextAlignmentLeft]; [informationView addSubview:label]; y += h; label = [[UILabel alloc] setxywh]; [label setText:[NSString stringWithFormat:@"练车时长: %d时%d分", allHour,allMin] Font:NormalFont TextColor:kTitleColor Alignment:NSTextAlignmentLeft]; [informationView addSubview:label]; y += h; label = [[UILabel alloc] setxywh]; [label setText:[NSString stringWithFormat:@"学时有效性: %@",[dicBody[@"validTime"] integerValue] == 0?@"本次计时无效":@"本次计时有效"] Font:NormalFont TextColor:kTitleColor Alignment:NSTextAlignmentLeft]; [informationView addSubview:label]; y += 10+h; label = [[UILabel alloc] setxywh]; CGFloat money = [dicBody[@"currentMoney"] floatValue]; NSMutableAttributedString *abs = [[NSMutableAttributedString alloc]initWithString:[NSString stringWithFormat:@"应付金额: %.2f元",money]]; [abs beginEditing]; //字体大小 [abs addAttribute:NSFontAttributeName value:[UIFont scaleSize:17] range:NSMakeRange(10, abs.length-10)]; [abs addAttribute:NSFontAttributeName value:[UIFont scaleSize:15] range:NSMakeRange(0, 10)]; //字体颜色 [abs addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:NSMakeRange(10, abs.length-10)]; [abs addAttribute:NSForegroundColorAttributeName value:kTitleColor range:NSMakeRange(0,10)]; label.attributedText = abs; label.textAlignment = NSTextAlignmentLeft; [informationView addSubview:label]; #endif if ([dicBody[@"currentMoney"] floatValue] > 0) {//有钱 支付 x = 20; y += h + 10; w = wid - 40; h = 50; UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom]; button.frame = setDIYFrame; [button setTitle:@"确定" textColor:kTitleColor Font:FontLarger fotState:UIControlStateNormal]; [button target:self tag:8]; [informationView addSubview:button]; [button addViewWithRect:CGRectMake(0, y - 1, wid, 1)]; // x = 0; // y += h+10; // w = wid/2.0; // h = 50; // UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom]; // button.frame = setDIYFrame; // [button setTitle:@"暂不支付" textColor:kTitleColor Font:FontLarger fotState:UIControlStateNormal]; // [button target:self tag:8]; // [informationView addSubview:button]; // // x = w; // button = [UIButton buttonWithType:UIButtonTypeCustom]; // button.frame = setDIYFrame; // [button setTitle:@"立即支付" textColor:RQ_MAIN_COLOR Font:FontLarger fotState:UIControlStateNormal]; // [button target:self tag:9]; // [informationView addSubview:button]; // [button addViewWithRect:CGRectMake(0, y - 1, wid, 1)]; // [button addViewWithRect:CGRectMake(x - .5, y, 1, h)]; }else{//没钱 评论 x = 0; y += h+10; w = wid/2.0; h = 50; UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom]; button.frame = setDIYFrame; [button setTitle:@"暂不评论" textColor:kTitleColor Font:FontLarger fotState:UIControlStateNormal]; [button target:self tag:8]; [informationView addSubview:button]; x = w; button = [UIButton buttonWithType:UIButtonTypeCustom]; button.frame = setDIYFrame; [button setTitle:@"评论" textColor:RQ_MAIN_COLOR Font:FontLarger fotState:UIControlStateNormal]; [button target:self tag:10]; [informationView addSubview:button]; [button addViewWithRect:CGRectMake(0, y - 1, wid, 1)]; [button addViewWithRect:CGRectMake(x - .5, y, 1, h)]; } } - (void)upLoadPhotoWithImage:(UIImage *)image{ //配置水印数组 NSDictionary *dic = @{@"up1":[NSString stringWithFormat:@"教练设备号:%@",gatherTrainDic[@"coachSim"]],@"up2":[NSString stringWithFormat:@"学员设备号:%@",RQ_USER_MANAGER.currentUser.telphone],@"down1":[NSString stringWithFormat:@"%.4f %.4f",myCoordinate.longitude,myCoordinate.latitude],@"down2":[NSString stringWithFormat:@"%@Km/h",gpsDic[@"speed"]],@"down3":gpsDic[@"timestamp"]}; //蓝牙照片不作处理 UIImage *cutImg; if (peripheralName.length > 0) { cutImg = image; }else { //剪切 然后压缩图片 NSData *data = UIImageJPEGRepresentation([image scaledAndCutToSize:CGSizeMake(240, 320)],0.5); cutImg = [UIImage imageWithData:data]; } //添加水印 UIImage *waterImage = [Tools watermarkImage:cutImg withDic:dic]; if (!myDelegate.isBackgroundTask) { if (!_photoImg) { _photoImg = [[UIImageView alloc] initWithFrame:CGRectMake(0, kSize.height - 264, 200, 150)]; _photoImg.userInteractionEnabled = YES; UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 40)]; [label setText:@"点击移除照片" Font:Font17 TextColor:[UIColor orangeColor] Alignment:NSTextAlignmentCenter]; [_photoImg addSubview:label]; UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(removeImage)]; [_photoImg addGestureRecognizer:tap]; } [self.view addSubview:_photoImg]; _photoImg.image = cutImg; [self performSelector:@selector(removeImage) withObject:nil afterDelay:15]; } //转化为data 再用base64加密 NSData *data = UIImageJPEGRepresentation(waterImage,1.0); NSString *pictureDataString = [data base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]; [LoadingView showHUD]; NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; [formatter setDateFormat:@"yyyyMMddHHmmss"]; NSString *dateString = [formatter stringFromDate:[NSDate date]]; NSMutableArray *arr=[NSMutableArray array]; [arr addPro:@"loginFlag" Value:isSubjectTwoSignIn?@"1":@"3"]; [arr addPro:@"content" Value:pictureDataString];//带水印的照片 [arr addPro:@"photo" Value:[UIImageJPEGRepresentation(cutImg,1.0) base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]];//不带水印照片 [arr addPro:@"subjcode" Value:isSubjectTwoSignIn?classCode:gatherTrainDic[@"classCode"]]; [arr addPro:@"classId" Value:isSubjectTwoSignIn?classId:gatherTrainDic[@"classId"]]; [arr addPro:@"ptime" Value:dateString]; [arr addPro:@"stuId" Value:RQ_USER_MANAGER.currentUser.outId]; [arr addPro:@"dqbh" Value:RQ_USER_MANAGER.currentUser.city]; [arr addPro:@"coachId" Value:gatherTrainDic[@"coachId"] ]; [arr addPro:@"sim" Value:RQ_USER_MANAGER.currentUser.telphone]; [arr addPro:@"gps" Value:[NSString stringWithFormat:@"%f,%f,%@,4",myCoordinate.latitude,myCoordinate.longitude,gpsDic[@"timestamp"]]]; if (![Util connectedToNetWork]) { showMsgUnconnect(); if (isSubjectTwoSignIn) { blueToothOrder = @""; [Tools playAudioWithString:@"网络未连接,请检查手机网络"]; [self showAlertTakePhotoFail]; }else { if (peripheralName.length < 1) { [gatherTrainDic setValue:arr forKey:@"comparisonPhoto"]; [self saveGatherTrainDic]; }else { if (myDelegate.isBackgroundTask) { [self addLocalNotificationWithAudio:@"takePhotoNoNet.mp3"]; }else { [Tools playAudioWithString:@"网络未连接,请检查手机网络,二十秒后重传照片"]; } [self performSelector:@selector(upLoadPhotoWithImage:) withObject:image afterDelay:20]; } } return; } NSString *method = @"comparisonPhoto"; [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) { RemoveHUD(); //NSLog(@"comparisonPhoto--->>>>%@",root); if (!root) { if (isSubjectTwoSignIn) { [Tools playAudioWithString:@"人脸验证失败"]; [self showAlertTakePhotoFail]; }else { if (peripheralName.length < 1) { ShowMsg(@"上传照片失败,请重试!"); [gatherTrainDic setValue:arr forKey:@"comparisonPhoto"]; [self saveGatherTrainDic]; }else { if (myDelegate.isBackgroundTask) { [self addLocalNotificationWithAudio:@"takePhotoNoRespond.mp3"]; }else { [Tools playAudioWithString:@"照片上传失败"]; } if ([blueToothOrder containsString:@"AA2F"] ) { [self upLoadPhotoWithImage:image]; }else { photoTime = seconds + 600; photoTime = photoTime + 65 - photoTime%60; [gatherTrainDic setValue:[NSString stringWithFormat:@"%d",(int)photoTime] forKey:@"photoTime"]; [self saveGatherTrainDic]; } blueToothOrder = @""; } } return; } if ([root[@"code"] isEqualToString:@"1"]) { if (isSubjectTwoSignIn) { [Tools playAudioWithString:root[@"body"]]; [self showAlertTakePhotoFail]; return; } if (peripheralName.length < 1) { [gatherTrainDic setValue:arr forKey:@"comparisonPhoto"]; [self saveGatherTrainDic]; }else { //失败三次之内 发送本地通知 提示重新拍照 否则 停止计时 if (takePhotoFailCount > 2) { takePhotoFailCount = 0; //先关闭定时器 if (timer) { [timer invalidate]; timer = nil; } myDelegate.timer = nil; //关闭蓝牙连接 [self closeBlueTooth]; //关闭后台任务 [self finishBackgroundTask];//如果没开启也可以调这个方法 [[UIApplication sharedApplication] setIdleTimerDisabled:NO];//关闭屏幕常亮 on_offBtn.tag = 3;//表明点了结束计时 但没结束成功的情况 [gatherTrainDic setValue:@"2" forKey:@"isOver"]; [self saveGatherTrainDic]; minuteTrainArray = [DB_Helper quearySCTrainWithClassId:gatherTrainDic[@"classId"]]; if (minuteTrainArray.count > 0) { [self uploadAppTrainPl]; }else{ [self uploadSignOutOrClassRecord]; } if (myDelegate.isBackgroundTask) { [self addLocalNotificationWithAudio:@"takePhotoFail.mp3"]; }else { [Tools playAudioWithString:@"拍照失败三次,计时结束"]; } }else { takePhotoFailCount += 1; //人脸比对失败,10秒后将重新拍照,请面向摄像头 if (myDelegate.isBackgroundTask) { [self addLocalNotificationWithAudio:@"FaceRecongrise.mp3"]; }else { [Tools playAudioWithString:[NSString stringWithFormat:@"%@,十秒后重新拍照,请面向摄像头",root[@"body"]]]; } [self performSelector:@selector(takePhotoByBlueTooth) withObject:nil afterDelay:12]; photoTime = seconds + 120; photoTime = photoTime + 65 - photoTime%60; [gatherTrainDic setValue:[NSString stringWithFormat:@"%d",(int)photoTime] forKey:@"photoTime"]; [self saveGatherTrainDic]; } } return; } //重新拍照次数置零 blueToothOrder = @""; takePhotoFailCount = 0; if (isSubjectTwoSignIn) { ShowMsg(@"人脸验证成功,开始计时!"); [Tools playAudioWithString:@"人脸验证成功,开始计时,请系好安全带"]; isSubjectTwoSignIn = NO; [self beginTimer]; return; } //将拍照时间置为0 photoTime = 0; [gatherTrainDic setValue:[NSString stringWithFormat:@"%d",(int)photoTime] forKey:@"photoTime"]; [self saveGatherTrainDic]; if (myDelegate.isBackgroundTask) { [self addLocalNotificationWithAudio:@"takePhotoSucess.mp3"]; }else { [Tools playAudioWithString:root[@"body"]]; } }]; } - (void)showAlertTakePhotoFail { blueToothOrder = @""; UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:@"人脸验证失败,是否重新采集照片" preferredStyle:UIAlertControllerStyleAlert]; [alert addAction:[UIAlertAction actionWithTitle:@"结束计时" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { //关闭定时器 if (signInTimer) { [signInTimer invalidate]; signInTimer = nil; } //关闭蓝牙连接 [self closeBlueTooth]; [self forceSignOutWithDic:[NSDictionary dictionaryWithObject:classId forKey:@"classid"]]; }]]; [alert addAction:[UIAlertAction actionWithTitle:@"重新拍照" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { [self performSelector:@selector(takePhotoByBlueTooth) withObject:nil afterDelay:3]; }]]; [self presentViewController:alert animated:NO completion:nil]; } #pragma mark - 添加本地通知 -(void)addLocalNotificationWithAudio:(NSString *)audioName{ //定义本地通知对象 UILocalNotification *notification = [[UILocalNotification alloc]init]; //设置调用时间 notification.fireDate = [NSDate date]; //设置通知属性 NSString *bodyString = @"极速驾培提醒您"; if ([audioName isEqualToString:@"takePhotoWarn.mp3"]) { bodyString = @"5秒后进行人脸比对"; }else if ([audioName isEqualToString:@"takePhotoColloctPic.mp3"]) { bodyString = @"拍照已完成,正在采集照片数据"; }else if ([audioName isEqualToString:@"takePhotoSucess.mp3"]) { bodyString = @"人脸验证成功,继续计时"; }else if ([audioName isEqualToString:@"FaceRecongrise.mp3"]) { bodyString = @"人脸验证失败,10秒后重新拍照"; }else if ([audioName isEqualToString:@"takePhotoFail.mp3"]) { bodyString = @"人脸验证失败三次,计时结束"; }else if ([audioName isEqualToString:@"takePhotoNoNet.mp3"]) { bodyString = @"网络未连接"; }else if ([audioName isEqualToString:@"takePhotoNoRespond.mp3"]) { bodyString = @"照片上传失败"; }else if ([audioName isEqualToString:@"blueToothConnect.mp3"]) { bodyString = @"车载设备连接成功"; }else if ([audioName isEqualToString:@"blueToothDisconnect.mp3"]) { bodyString = @"车载设备已断开,计时暂停,正在尝试重新连接"; } notification.alertBody = bodyString; //通知主体 notification.applicationIconBadgeNumber = 1;//应用程序图标右上角显示的消息数 notification.alertAction = @"打开应用"; //待机界面的滑动动作提示 notification.soundName = audioName;//收到通知时播放的声音,默认消息声音 // 通知参数 NSDictionary *userDict = [NSDictionary dictionaryWithObjectsAndKeys:@"nothing",@"ShiCaoPeriodVC_reTakePhoto", nil]; notification.userInfo = userDict; //调用通知 [[UIApplication sharedApplication] scheduleLocalNotification:notification]; } -(void)removeAllTheoryNotify{ NSArray *notifiArray = [[UIApplication sharedApplication] scheduledLocalNotifications]; for (UILocalNotification *local in notifiArray) { if (local.userInfo[@"ShiCaoPeriodVC_reTakePhoto"]) { //删除单个通知 [[UIApplication sharedApplication]cancelLocalNotification:local]; } } } - (void)removeImage { if (_photoImg) { [_photoImg removeFromSuperview]; } } //生成订单 -(void)uploadReserveOrder { [LoadingView showHUD]; if (![Util connectedToNetWork]) { showMsgUnconnect(); return; } NSMutableArray *arr=[NSMutableArray array]; [arr addPro:@"reserveId" Value:gatherTrainDic[@"reserveId"]]; [arr addPro:@"userId" Value:RQ_USER_MANAGER.currentUser._id]; [arr addPro:@"dqbh" Value:RQ_USER_MANAGER.currentUser.city]; [arr addPro:@"coachId" Value:gatherTrainDic[@"coachId"]]; [arr addPro:@"sim" Value:RQ_USER_MANAGER.currentUser.telphone]; [arr addPro:@"classId" Value:classId]; NSString* method = @"uploadReserveOrder"; [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) { RemoveHUD(); if (!root) { ShowMsg(@"开始计时失败,请重试!"); [Tools playAudioWithString:@"开始计时失败,请虫试!"]; return; } if ([root[@"code"] isEqualToString:@"1"]) { ShowMsg(root[@"body"]); [Tools playAudioWithString:root[@"body"]]; return; } orderId = [root[@"body"] objectForKey:@"id"]; [gatherTrainDic setValue:orderId forKey:@"orderId"]; [gatherTrainDic setValue:[root[@"body"] objectForKey:@"subject"] forKey:@"subject"]; [gatherTrainDic setValue:[root[@"body"] objectForKey:@"price"] forKey:@"price"]; classCode = [NSString stringWithFormat:@"%@%@%@",[classCode substringToIndex:3],gatherTrainDic[@"subject"],[classCode substringFromIndex:classCode.length - 6]]; //订单正常生成 调签到接口 [self uploadStuSign]; }]; } //删除订单 -(void)delReserveOrder { [LoadingView showHUD]; if (![Util connectedToNetWork]) { showMsgUnconnect(); return; } NSMutableArray *arr=[NSMutableArray array]; [arr addPro:@"orderId" Value:orderId]; NSString* method = @"delReserveOrder"; [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) { RemoveHUD(); if (!root) { } if ([root[@"code"] isEqualToString:@"1"]) { return; } }]; } //获取当前学员签到状态 - (void)getStuSignFlag { if (![Util connectedToNetWork]) { [self isUploadLocation]; return; } NSMutableArray *arr=[NSMutableArray array]; [arr addPro:@"stuId" Value:RQ_USER_MANAGER.currentUser.outId]; [arr addPro:@"dqbh" Value:RQ_USER_MANAGER.currentUser.city]; NSString* method = @"getStuSignFlag"; [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) { if (!root || [root[@"code"] isEqualToString:@"1"]) { [self isUploadLocation]; return; } //这个地方要根据服务器返回的学时序列 同步本地的 谁大用谁0.0 int trainNumber = [[root[@"body"] objectForKey:@"seq"] intValue]; NSString *trainNumberString = [[NSUserDefaults standardUserDefaults] valueForKey:@"trainOrderNum"]; //17-02-09,20 NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; formatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; [formatter setDateFormat:@"yyMMdd"]; NSString *dateString = [formatter stringFromDate:[NSDate date]]; if (trainNumberString.length > 0) { int oldTrainNumber = [[[trainNumberString componentsSeparatedByString:@","] lastObject] intValue]; if (trainNumber > oldTrainNumber) { //本地有重复 需要重置 [[NSUserDefaults standardUserDefaults] setValue:[NSString stringWithFormat:@"%@,%d",dateString,trainNumber] forKey:@"trainOrderNum"]; } }else{//本地卸载数据丢失或者今天第一次计时 [[NSUserDefaults standardUserDefaults] setValue:[NSString stringWithFormat:@"%@,%d",dateString,trainNumber] forKey:@"trainOrderNum"]; } //本地状态 [self getGatherTrainDic]; //这里接收服务器返回状态 当前训练培训训练状态 0 实操签退或模拟签退 1 实操签到 2 模拟签到 3 隔日训练 4集中理论 5终端实操 switch ([[root[@"body"] objectForKey:@"status"] integerValue]) { case 0: //代表签退状态 看本地是否是签退状态 如果不是 置为签退状态 if ([gatherTrainDic isKindOfClass:[NSMutableDictionary class]]) { if (![gatherTrainDic[@"isOver"] isEqualToString:@"1"]) { [gatherTrainDic setValue:@"1" forKey:@"isOver"]; [self saveGatherTrainDic]; } } break; case 1: //实操计时中 看本地是否有数据 有数据直接isUploadLocation 没有数据去调签退汇总 if (![gatherTrainDic isKindOfClass:[NSMutableDictionary class]]) { //本地无数据调签退汇总 [Tools playAudioWithString:@"数据错误,系统将汇总学时,请重新实操计时"]; [self forceSignOutWithDic:root[@"body"]]; }else { //NSLog(@"gatherTrainDic--><>%@",gatherTrainDic); if (!gatherTrainDic[@"classId"]) { //本地无数据调签退汇总 [self closeBlueTooth]; [Tools playAudioWithString:@"系统检测到您上次人脸验证未成功,请重新实操计时"]; [self forceSignOutWithDic:root[@"body"]]; peripheralName = @""; [gatherTrainDic setValue:peripheralName forKey:@"blueName"]; [self saveGatherTrainDic]; }else { if ([gatherTrainDic[@"isOver"] isEqualToString:@"1"]) { [gatherTrainDic setValue:@"2" forKey:@"isOver"]; [self saveGatherTrainDic]; } } } break; case 2: //模拟计时中 不能开始实操计时 并且本地不为实操计时中 isImitate = YES; if ([gatherTrainDic isKindOfClass:[NSMutableDictionary class]]) { if (![gatherTrainDic[@"isOver"] isEqualToString:@"1"]) { [gatherTrainDic setValue:@"1" forKey:@"isOver"]; [self saveGatherTrainDic]; } } break; case 3: //隔日签到 if ([gatherTrainDic isKindOfClass:[NSMutableDictionary class]]) { [gatherTrainDic setValue:@"2" forKey:@"isOver"]; [self saveGatherTrainDic]; [RQ_SHARE_FUNCTION showAlertWithTitle:@"温馨提示" message:@"您昨天还未汇总学时,请汇总后再开始新的实操学习" alertControllerStyle:UIAlertControllerStyleAlert cancelButtonTitle:@"确定" otherButtonTitles:nil otherButtonStyles:nil showInWindow:NO completion:nil]; }else{ [Tools playAudioWithString:@"您昨天还未汇总学时,系统将汇总学时,请重新实操计时"]; [self forceSignOutWithDic:root[@"body"]]; } break; case 4: //集中理论 isForceKeYi = YES; break; case 5: //终端实操计时 不能开始实操计时 并且本地不为实操计时中 isTerminal = YES; break; default: break; } [self isUploadLocation]; }]; } - (void)forceSignOutWithDic:(NSDictionary *)dic { if (![Util connectedToNetWork]) { return; } NSMutableArray *arr=[NSMutableArray array]; [arr addPro:@"classId" Value:dic[@"classid"]]; [arr addPro:@"stuId" Value:RQ_USER_MANAGER.currentUser.outId]; [arr addPro:@"dqbh" Value:RQ_USER_MANAGER.currentUser.city]; NSString* method = @"forceSignOut"; [jiaPeiManager requestAnythingWithURL:method array:arr data:nil completion:^(NSDictionary * root) { //删除学时 if (!root || [root[@"code"] isEqualToString:@"1"]) { [RQ_SHARE_FUNCTION showAlertWithTitle:@"温馨提示" message:@"汇总失败,请重试!" alertControllerStyle:UIAlertControllerStyleAlert cancelButtonTitle:@"取消" otherButtonTitles:@[@"再试一次"] otherButtonStyles:nil showInWindow:NO completion:^(NSUInteger selectedOtherButtonIndex) { if (selectedOtherButtonIndex == 0) { [self getStuSignFlag]; } }]; if (isSubjectTwoSignIn) { on_offBtn.tag = 3;//表明点了结束计时 但没结束成功的情况 [gatherTrainDic setValue:@"2" forKey:@"isOver"]; [self saveGatherTrainDic]; [on_offBtn setTitle:@"结束计时" forState:UIControlStateNormal]; } }else { [dataSourceArray removeAllObjects]; if (isSubjectTwoSignIn) { [Tools playAudioWithString:@"操作成功!"]; } } [DB_Helper deleteAllSCTrain]; }]; } #pragma mark 蓝牙相关 - (void)searchBlueTooth { dataIsLack = NO; lastData = @""; blueToothOrder = @""; reOrderCount = 0; orderNum = 0; imageData = @""; imgLongth = 0; lastLongth = 0; isLastOrder = NO; heartSeconds = 0; bTRequestTime = 0; stopReplyHeart = NO; takePhotoFailCount = 0; //初始化蓝牙 并搜索 [self getCBCmanager]; } //获取发动机转速、速度、里程 - (void)getCarInfo { if (self.writeCharacteristic) { NSString *orderString = @"BE0184"; blueToothOrder = orderString; [self writeCharacteristic:self.peripheral characteristic:self.writeCharacteristic value:[self convertHexStrToData:orderString]]; } } //发送拍照命令 - (void)takePhotoByBlueTooth { imageData = @""; isLastOrder = NO; dataIsLack = NO; lastData = @""; imgLongth = 0; lastLongth = 0; orderNum = 0; blueToothOrder = @"AA2F03040509"; [self writeCharacteristic:self.peripheral characteristic:self.writeCharacteristic value:[self convertHexStrToData:blueToothOrder]]; } - (void)closeBlueTooth { if (peripheralName.length > 0) { //断开连接 isNotPlayAudio = YES; _haveBlueTooth = NO; if (self.peripheral) { [self.cbcManager cancelPeripheralConnection:self.peripheral]; } self.peripheral.delegate = nil; self.peripheral = nil; self.writeCharacteristic = nil; self.readCharacteristic = nil; self.cbcManager = nil; } } //建立一个Central Manager实例进行蓝牙管理 -(CBCentralManager *)getCBCmanager { if (!_cbcManager) { _cbcManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil]; } return _cbcManager; } //只要中心管理者初始化 就会触发此代理方法 判断手机蓝牙状态 - (void)centralManagerDidUpdateState:(CBCentralManager *)central { switch (central.state) { case 0: //状态未知 //NSLog(@"CBCentralManagerStateUnknown"); break; case 1: //连接断开 即将重置 //NSLog(@"CBCentralManagerStateResetting"); break; case 2: //该平台不支持蓝牙 //NSLog(@"CBCentralManagerStateUnsupported"); break; case 3: //未授权蓝牙使用 hovertree.com //NSLog(@"CBCentralManagerStateUnauthorized"); { [self removeBlueToothLabel]; [RQ_SHARE_FUNCTION showAlertWithTitle:@"温馨提示" message:@"请在“设置”中打开蓝牙访问权限" alertControllerStyle:UIAlertControllerStyleAlert cancelButtonTitle:@"确定" otherButtonTitles:nil otherButtonStyles:nil showInWindow:NO completion:nil]; } break; case 4: { //蓝牙未开启 //NSLog(@"CBCentralManagerStatePoweredOff"); if (peripheralName.length > 0) { ShowMsg(@"请打开手机蓝牙"); [Tools playAudioWithString:@"请打开手机蓝牙"]; } } break; case 5: { //蓝牙已开启 //NSLog(@"CBCentralManagerStatePoweredOn"); if (peripheralName.length < 1) { return; } // 搜索外设 if (self.peripheral) { return; } // 搜索成功之后,会调用找到外设的代理方法 [self addBlueToothLabelWithContent:[NSString stringWithFormat:@"正在连接车载设备 %@ 请稍候",peripheralName]]; [self.cbcManager scanForPeripheralsWithServices:nil // 通过某些服务筛选外设 options:nil]; // dict,条件 } break; default: break; } } // 发现外设后调用的方法 - (void)centralManager:(CBCentralManager *)central // 中心管理者 didDiscoverPeripheral:(CBPeripheral *)peripheral // 外设 advertisementData:(NSDictionary *)advertisementData // 外设携带的数据 RSSI:(NSNumber *)RSSI // 外设发出的蓝牙信号强度 { NSLog(@"搜索到的外设----><>%@----><>%@",peripheral.name,peripheralName); //如果蓝牙名称和二维码中的一致 就可以连接了 最好能关闭蓝牙的扫描 if ([peripheral.name isEqualToString:peripheralName]) { self.peripheral = peripheral; [self.cbcManager stopScan]; [_cbcManager connectPeripheral:self.peripheral options:nil]; } } // 中心管理者连接外设成功 - (void)centralManager:(CBCentralManager *)central // 中心管理者 didConnectPeripheral:(CBPeripheral *)peripheral // 外设 { NSLog(@"%s, line = %d, %@=连接成功", __FUNCTION__, __LINE__, peripheral.name); [self removeBlueToothLabel]; // 连接成功之后,可以进行服务和特征的发现 // 设置外设的代理 self.peripheral.delegate = self; // 外设发现服务,传nil代表不过滤 [self.peripheral discoverServices:nil]; isConnectBlueTooth = YES; disconnectSeconds = 0; if (myDelegate.isBackgroundTask) { [self addLocalNotificationWithAudio:@"blueToothConnect.mp3"]; }else { [Tools playAudioWithString:@"已成功连接车宰设备"]; } } // 外设连接失败 - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { isConnectBlueTooth = NO; NSLog(@"%s, line = %d, %@=连接失败", __FUNCTION__, __LINE__, peripheral.name); NSString *showString = @"车载设备连接失败!请重试"; NSString *audioString = @"车宰设备连接失败!请重试"; if ([gatherTrainDic isKindOfClass:[NSMutableDictionary class]]) { if ([gatherTrainDic[@"isOver"] isEqualToString:@"0"]) { //表明之前的计时没有结束。是恢复计时 ShowMsg(@"车载设备连接失败,计时暂停,正在尝试重新连接"); [Tools playAudioWithString:@"车宰设备连接失败,计时暂停,正在尝试重新连接"]; } } ShowMsg(showString); [Tools playAudioWithString:audioString]; if (self.peripheral) { [_cbcManager connectPeripheral:self.peripheral options:nil]; } } // 丢失连接 - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { isConnectBlueTooth = NO; if ([blueToothOrder containsString:@"AA2F"]) {//还在执行拍照命令 if (seconds >= photoTime) { photoTime += 60; } [gatherTrainDic setValue:[NSString stringWithFormat:@"%d",(int)photoTime] forKey:@"photoTime"]; [self saveGatherTrainDic]; } NSLog(@"%s, line = %d, %@=断开连接", __FUNCTION__, __LINE__, peripheral.name); if (self.cbcManager && self.peripheral) { [self.cbcManager connectPeripheral:self.peripheral options:nil]; } if (timer) { ShowMsg(@"车载设备已断开,计时暂停,蓝牙重新连接中...."); if (myDelegate.isBackgroundTask) { [self addLocalNotificationWithAudio:@"blueToothDisconnect.mp3"]; }else { [Tools playAudioWithString:@"车宰设备已断开,计时暂停,正在尝试重新连接"]; } } } //查找服务的所有特征 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error { if (error) { //NSLog(@"Discovered services for %@ with error: %@", peripheral.name, [error localizedDescription]); return; } //NSLog(@"services---><>%@",peripheral.services); //服务并不是我们的目标,也没有实际意义。我们需要用的是服务下的特征,查询(每一个服务下的若干)特征 for (CBService *service in peripheral.services) { [peripheral discoverCharacteristics:nil forService:service]; } } // 发现外设服务里的特征的时候调用的代理方法(这个是比较重要的方法,你在这里可以通过事先知道UUID找到你需要的特征,订阅特征,或者这里写入数据给特征也可以) - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error { /* 这里经过测试 读写全用UUID为FFE1的特征 这样收到的蓝牙回复 没有很多的多余的数据 */ for (CBCharacteristic *cha in service.characteristics) { if ([cha.UUID isEqual:[CBUUID UUIDWithString:@"6E400003-B5A3-F393-E0A9-E50E24DCCA9E"]]) { NSLog(@"读取特征-->>>%@",cha); self.readCharacteristic = cha; [peripheral setNotifyValue:YES forCharacteristic:cha]; // [peripheral readValueForCharacteristic:cha]; } if ([cha.UUID isEqual:[CBUUID UUIDWithString:@"6E400002-B5A3-F393-E0A9-E50E24DCCA9E"]]) { NSLog(@"写入特征-->>>%@",cha); self.writeCharacteristic = cha; } } } - (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error { if (error) { [peripheral setNotifyValue:YES forCharacteristic:self.readCharacteristic]; } } // 更新特征的value的时候会调用 (凡是从蓝牙传过来的数据都要经过这个回调,简单的说这个方法就是你拿数据的唯一方法) - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { if ([characteristic isEqual:self.readCharacteristic] ) { NSString *hexString = [self convertDataToHexStr:characteristic.value]; NSLog(@"hexString---><>%@",hexString); //与摄像头交互 if ([blueToothOrder containsString:@"AA2F"]) { [self getDataForPictureWithString:hexString]; return; } //数据完整性检测 if ([hexString containsString:@"be"]) { //数据首包 lastData = [[hexString componentsSeparatedByString:@"be"] lastObject]; if (lastData.length < 2) { return; } int dataLength = [self getHexNumWithString:[lastData substringToIndex:2]]; if (lastData.length < dataLength*2 + 2) { dataIsLack = YES; return; } }else { if (dataIsLack) {//上个包数据不够 hexString = [lastData stringByAppendingString:hexString]; lastData = hexString; int dataLength = [self getHexNumWithString:[lastData substringToIndex:2]]; if (lastData.length < dataLength*2 + 2) { return; }else { dataIsLack = NO; hexString = [@"dsbe" stringByAppendingString:hexString]; } } } //NSLog(@"检测完数据的完整性----><>%@",hexString); // 心跳包验证 if ([hexString containsString:@"be0501"]) {//心跳包命令 执行验证然后回复 heartSeconds = 0;//得到心跳包 将这个值置零 if (stopReplyHeart) {//停止交互心跳包 (要拍照或者获取OBD数据) return; } //得到数据 hexString = [[hexString componentsSeparatedByString:@"be0501"] lastObject]; if (hexString.length > 8) { hexString = [hexString substringToIndex:8]; } //计算数据 hexString = [self getResultWithHexString:hexString]; if (hexString.length < 14) { NSString *OString = @"0000"; hexString = [OString stringByAppendingString:hexString]; } //验证数据 hexString = [NSString stringWithFormat:@"be0381%@",[hexString substringFromIndex:hexString.length - 4]]; blueToothOrder = hexString; [self writeCharacteristic:self.peripheral characteristic:self.writeCharacteristic value:[self convertHexStrToData:hexString]]; //调接口签到 if (isNeedSignIn) { isNeedSignIn = NO; [self startPeriod]; } return; } if ([hexString containsString:@"be0604"]) {//获取发动机转速、车速、里程 //停止回复心跳包 stopReplyHeart = NO; hexString = [[hexString componentsSeparatedByString:@"be"] lastObject]; //获取有效字节长度 - 标示长度的字节 int stringLength = [self getHexNumWithString:[hexString substringToIndex:2]] - 1; //获取有效的字节 hexString = [hexString substringWithRange:NSMakeRange(4, stringLength*2)]; //NSLog(@"hexString--><>%@",hexString); NSString *obdRotationSpeed = [NSString stringWithFormat:@"%d",[self getHexNumWithString:[hexString substringWithRange:NSMakeRange(0, 4)]]]; NSString *maxSpeed = [NSString stringWithFormat:@"%d",[self getHexNumWithString:[hexString substringWithRange:NSMakeRange(4, 2)]]]; NSString *obdMileage = [NSString stringWithFormat:@"%.4f",[self getHexNumWithString:[hexString substringWithRange:NSMakeRange(6, 4)]]/1000.0]; if (!obdRotationSpeed) { obdRotationSpeed = @"0"; } if (!maxSpeed) { maxSpeed = @"0"; } if (!obdMileage) { obdMileage = @"0"; } //NSLog(@"obd数据--%@-%@-%@",obdRotationSpeed,maxSpeed,obdMileage); [minuteTrainDic setValue:obdRotationSpeed forKey:@"obdRotationSpeed"]; [minuteTrainDic setValue:maxSpeed forKey:@"maxSpeed"]; [minuteTrainDic setValue:obdMileage forKey:@"obdMileage"]; [DB_Helper changeSCTrainWithTrainNum:trainNum RotationSpeed:obdRotationSpeed Speed:maxSpeed Mileage:obdMileage]; //更新obdMileage数据 并存入本地 CGFloat allMileage = [gatherTrainDic[@"obdMileage"] floatValue]; allMileage += [obdMileage floatValue]; [gatherTrainDic setValue:[NSString stringWithFormat:@"%.4f",allMileage] forKey:@"obdMileage"]; [self saveGatherTrainDic]; [self uploadAppTrainSingle];//上传分钟学时 return; } } } - (void)getDataForPictureWithString:(NSString *)hexString { //取到数据 重置状态时间 reOrderCount = 0; bTRequestTime = 0; //允许回复心跳包 if ([hexString containsString:@"aa2f"]) { if (stopReplyHeart) { stopReplyHeart = NO; } } //取相片 if ([blueToothOrder containsString:@"AA2F042E"]) { NSString *orderStr = [blueToothOrder substringWithRange:NSMakeRange(8, 4)]; if (isLastOrder) { //接收最后一个包 if (lastData.length > 0) { lastData = [lastData stringByAppendingString:hexString]; if (lastData.length >= lastLongth * 2) { isLastOrder = NO; imageData = [imageData stringByAppendingString:[lastData substringToIndex:lastLongth *2]];//将一帧的数据放在图片数据中 //NSLog(@"最后一帧%@帧的数据---><>%@------long----->%d",orderStr,[lastData substringToIndex:lastLongth *2],(int)lastData.length); //照片数据全取出 显示照片 NSData *image = [self convertHexStrToData:imageData]; //获取到照片 上传服务器 if (image) { [self removeBlueToothLabel]; blueToothOrder = @"AA2FWAIT"; [self upLoadPhotoWithImage:[UIImage imageWithData:image]]; } } }else { if ([hexString containsString:orderStr]) { lastData = [[hexString componentsSeparatedByString:orderStr] lastObject]; if (lastData.length > 4) { lastData = [lastData substringFromIndex:4];//数据 } } } return; } if ([hexString containsString:[NSString stringWithFormat:@"%@fa01",orderStr]]) { lastData = [[hexString componentsSeparatedByString:[NSString stringWithFormat:@"%@fa01",orderStr]] lastObject]; }else { lastData = [lastData stringByAppendingString:hexString]; if (lastData.length >= imgLongth * 2) { imageData = [imageData stringByAppendingString:[lastData substringToIndex:imgLongth *2]];//将一帧的数据放在图片数据中 //NSLog(@"%@帧的数据---><>%@",orderStr,[lastData substringToIndex:imgLongth *2]); lastData = @""; orderStr = [NSString stringWithFormat:@"%@%@",[orderStr substringFromIndex:2],[orderStr substringToIndex:2]]; if ([self getHexNumWithString:orderStr] < orderNum) {//循环发送命令 if ([self getHexNumWithString:orderStr] == orderNum - 1) { if (lastLongth > 0) {//还有一个不完整的包 isLastOrder = YES; }else {//刚刚好 没有剩余的数据 return; } } orderStr = [NSString stringWithFormat:@"%4x",[self getHexNumWithString:orderStr] + 1];////命令+1 然后转为16进制 不足4位 前边补空格 orderStr = [orderStr stringByReplacingOccurrencesOfString:@" " withString:@"0"];//将空格转换为0 orderStr = [NSString stringWithFormat:@"%@%@",[orderStr substringFromIndex:2],[orderStr substringToIndex:2]];//命令字节调换高低端 blueToothOrder = [NSString stringWithFormat:@"AA2F042E%@2F",orderStr]; //NSLog(@"自动下发命令-->>%@==----==%@",blueToothOrder,[self convertHexStrToData:blueToothOrder]); [self writeCharacteristic:self.peripheral characteristic:self.writeCharacteristic value:[self convertHexStrToData:blueToothOrder]]; } } } return; } //数据完整性检测 if ([hexString containsString:@"aa2f"]) { //数据首包 lastData = [[hexString componentsSeparatedByString:@"aa2f"] lastObject]; if (lastData.length > 0) { if (lastData.length < 2) { return; } int dataLength = [self getHexNumWithString:[lastData substringToIndex:2]]; if (lastData.length < dataLength*2 + 2) { dataIsLack = YES; return; } }else { dataIsLack = YES; return; } }else { if (dataIsLack) {//上个包数据不够 hexString = [lastData stringByAppendingString:hexString]; lastData = hexString; int dataLength = [self getHexNumWithString:[lastData substringToIndex:2]]; if (lastData.length < dataLength*2 + 2) { return; }else { dataIsLack = NO; hexString = [@"aa2f" stringByAppendingString:hexString]; } } } //NSLog(@"检测完数据的完整性----><>%@",hexString); if ([blueToothOrder isEqualToString:@"AA2F03040509"] && [hexString containsString:@"aa2f060a05"]) { if (myDelegate.isBackgroundTask) { //本地通知 [self addLocalNotificationWithAudio:@"takePhotoColloctPic.mp3"]; }else { [Tools playAudioWithString:@"拍照已完成,正在采集照片信息,请稍后"]; } [self addBlueToothLabelWithContent:@"正在采集照片信息..."]; NSString *str = [[hexString componentsSeparatedByString:@"2f060a05"] lastObject]; if (str.length > 6) { str = [NSString stringWithFormat:@"%@%@%@",[str substringWithRange:NSMakeRange(4, 2)],[str substringWithRange:NSMakeRange(2, 2)],[str substringToIndex:2]]; } imgLongth = [self getHexNumWithString:str]; //暂定一帧的大小为 01fa (506) orderNum = imgLongth/506; lastLongth = imgLongth%506; //NSLog(@"图片总大小-----><>%d-----总帧数--->%d----最后一帧大小---->%d",(int)imgLongth,(int)orderNum,(int)lastLongth); imgLongth = 506;//506是字节数 //拍照成功 发指令获取数据 isLastOrder = NO; imageData = @"";//每次发起拍照命令前 将图片数据清空 blueToothOrder = @"AA2F042E00002E";//获取指定图像包 [self writeCharacteristic:self.peripheral characteristic:self.writeCharacteristic value:[self convertHexStrToData:blueToothOrder]]; } } //写数据 -(void)writeCharacteristic:(CBPeripheral *)peripheral characteristic:(CBCharacteristic *)characteristic value:(NSData *)value { //NSLog(@"写入数据-->%@",value); [peripheral writeValue:value forCharacteristic:characteristic type:CBCharacteristicWriteWithoutResponse]; } // 需要注意的是特征的属性是否支持写数据 - (void)yf_peripheral:(CBPeripheral *)peripheral didWriteData:(NSData *)data forCharacteristic:(nonnull CBCharacteristic *)characteristic { //NSLog(@"写入特征值-->%@",data); /* 打印出特征的权限(characteristic.properties),可以看到有很多种,这是一个NS_OPTIONS的枚举,可以是多个值 常见的又read,write,noitfy,indicate.知道这几个基本够用了,前俩是读写权限,后俩都是通知,俩不同的通知方式 */ // 此时由于枚举属性是NS_OPTIONS,所以一个枚举可能对应多个类型,所以判断不能用 = ,而应该用包含& } #pragma mark 16进制与NSData之间的转化 及验证算法计算 //data转换为16进制 - (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; } //16进制转换为data - (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; } return hexData; } - (NSString *)getResultWithHexString:(NSString *)hexString { if (hexString.length < 8) { //NSLog(@"验证算法输入数据错误"); return @"erroe"; } int x = [self getHexNumWithString:[hexString substringToIndex:4]]; int y = [self getHexNumWithString:[hexString substringFromIndex:4]]; int z = 0x1323; hexString = [NSString stringWithFormat:@"%x",(x*z+y)^z]; // //NSLog(@"%d,%d,%d,%x,%x,%x<---->%@",x,y,z,x,y,z,hexString); return hexString; } /** 将原本是16进制数字的字符串转换成计算机可以识别的int型10进制数据 */ - (int)getHexNumWithString:(NSString *)string { int number = 0; for (int i = 0; i < string.length; i ++) { NSString *letterOrNumber = [string substringWithRange:NSMakeRange(string.length - i - 1, 1)]; int a = 0; if ([letterOrNumber isEqualToString:@"a"] || [letterOrNumber isEqualToString:@"A"]) { a = 10; }else if ([letterOrNumber isEqualToString:@"b"] || [letterOrNumber isEqualToString:@"B"]){ a = 11; }else if ([letterOrNumber isEqualToString:@"c"] || [letterOrNumber isEqualToString:@"C"]){ a = 12; }else if ([letterOrNumber isEqualToString:@"d"] || [letterOrNumber isEqualToString:@"D"]){ a = 13; }else if ([letterOrNumber isEqualToString:@"e"] || [letterOrNumber isEqualToString:@"E"]){ a = 14; }else if ([letterOrNumber isEqualToString:@"f"] || [letterOrNumber isEqualToString:@"F"]){ a = 15; }else { a = [letterOrNumber intValue]; } a = a * pow(16, i); number += a; } return number; } //将十六进制的字符串转换成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; } #pragma mark 后台 //结束后台任务 - (void)finishBackgroundTask { if (myDelegate.locationUpdateTimer) { [myDelegate.locationUpdateTimer invalidate]; myDelegate.locationUpdateTimer = nil; } if (myDelegate.locationTracker) { [myDelegate.locationTracker stopLocationTracking]; myDelegate.locationTracker = nil; } } //进入后台任务 -(void)goToBackgroundTask { if([[UIApplication sharedApplication] backgroundRefreshStatus] == UIBackgroundRefreshStatusRestricted){ [RQ_SHARE_FUNCTION showAlertWithTitle:nil message:@"设备无法定位" alertControllerStyle:UIAlertControllerStyleAlert cancelButtonTitle:@"确定" otherButtonTitles:nil otherButtonStyles:nil showInWindow:NO completion:nil]; } else{ myDelegate.locationTracker = [[LocationTracker alloc]init]; [myDelegate.locationTracker startLocationTracking]; //Send the best location to server every 60 seconds //You may adjust the time interval depends on the need of your app. NSTimeInterval time = 60.0; myDelegate.locationUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:time target:self selector:@selector(updateLocation) userInfo:nil repeats:YES]; } } //更新位置 -(void)updateLocation { // //NSLog(@"updateLocation"); [myDelegate.locationTracker updateLocationToServer]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } @end