You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

533 lines
20 KiB

//
// Bluetooth.m
// tongxin
//
// Created by ecell on 2022/11/3.
// Copyright © 2022 xTT. All rights reserved.
//
#import "Bluetooth.h"
#import <CoreBluetooth/CoreBluetooth.h>
#import "BLEModel.h"
#import "BLEConst.h"
#import "GCDTimerManager.h"
#import <objc/runtime.h>
#import <AVFoundation/AVFoundation.h>
// 超时间隔
#define TimeOutNumber 5
NSString *const sDeviceKey = @"sDeviceModel";
@interface Bluetooth ()<CBPeripheralDelegate,CBCentralManagerDelegate,AVAudioPlayerDelegate>
@property (strong, nonatomic) CBPeripheral *bleCurrentPeripheral;
@property (strong, nonatomic) NSString *selectedOtaFilePath;
@property (strong, nonatomic) CBCentralManager *bleManager;
@property (strong, nonatomic) NSMutableArray<BLEModel *> *blePeripheralArr;
/// 计时器
@property (nonatomic ,assign) NSInteger timeNumber;
/// 自动重连次数
@property (nonatomic ,assign) NSInteger ljNumber;
@property (nonatomic, strong) AVAudioPlayer *audioPlayer;
@end
@implementation Bluetooth
+ (instancetype)shareInstance
{
static Bluetooth *share;
static dispatch_once_t oneToken;
dispatch_once(&oneToken, ^{
share = [[self alloc] init];
share.cache = [YYCache cacheWithName:@"lksh_cache_data"];
if ([share.cache containsObjectForKey:sDeviceKey])
{
id object = [share.cache objectForKey:sDeviceKey];
if ([object isKindOfClass:BLEModel.class])
{
share.currenModel = object;
}
}
});
return share;
}
- (instancetype)init
{
self = [super init];
if (self)
{
self.timeNumber = 0;
self.ljNumber = 0;
_bleManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
return self;
}
#pragma mark - 扫描设备相关
#pragma mark 开始扫描
- (void)startScanBLE
{
NSLog(@"BLE ---> startScanBLE.");
_blePeripheralArr = [NSMutableArray new];
if (_bleManager) {
NSArray *uuids = @[[CBUUID UUIDWithString:BraceletServicesUUID]];
if (_bleManager.state == CBManagerStatePoweredOn)
{
[_bleManager scanForPeripheralsWithServices:uuids options:nil];
}
else
{
__weak typeof(self) weakSelf = self;
dispatch_after(0.5, dispatch_get_main_queue(), ^{
if (weakSelf.bleManager.state == CBManagerStatePoweredOn)
{
[weakSelf.bleManager scanForPeripheralsWithServices:uuids options:nil];
}
});
}
}
}
#pragma mark 停止扫描
- (void)stopScanBLE
{
if (_bleManager) [_bleManager stopScan];
}
#pragma mark - 蓝牙设备连接相关
#pragma mark 断开当前蓝牙设备连接
- (void)disconnectBLE
{
if (_bleCurrentPeripheral)
{
NSLog(@"BLE --->To disconnectBLE.");
[_bleManager cancelPeripheralConnection:_bleCurrentPeripheral];
[GCDTimerManager.sharedInstance cancelTimerWithName:@"Zhendong"];
AudioServicesRemoveSystemSoundCompletion(kSystemSoundID_Vibrate);
[GCDTimerManager.sharedInstance cancelTimerWithName:@"BLELJ"];
}
}
#pragma mark 连接蓝牙设备
- (void)connectBLE:(BLEModel*)bleModel
{
_bleCurrentPeripheral = bleModel.peripheral;
self.currenModel = bleModel;
[_bleCurrentPeripheral setDelegate:self];
[_bleManager connectPeripheral:_bleCurrentPeripheral options:@{CBConnectPeripheralOptionNotifyOnDisconnectionKey:@(YES)}];
[_bleManager stopScan];
NSLog(@"BLE Connecting... Name ---> %@", bleModel.peripheral.name);
//[self jisjiqi:0 bleModel:bleModel];
}
- (void)jisjiqi:(NSInteger)type bleModel:(BLEModel*)bleModel
{
self.timeNumber = 0;
[GCDTimerManager.sharedInstance cancelTimerWithName:@"BLELJ"];
[GCDTimerManager.sharedInstance scheduleGCDTimerWithName:@"BLELJ" interval:1 queue:dispatch_get_main_queue() repeats:YES option:CancelPreviousTimerAction action:^{
self.timeNumber++;
NSLog(@"%ld",self.timeNumber);
[[NSNotificationCenter defaultCenter] postNotificationName:@"LIANJIEZ" object:self.timeNumber%2 == 0 ? @"连接中..." : @"连接中.."];
if (self.timeNumber == 15)
{
self.ljNumber ++;
[GCDTimerManager.sharedInstance cancelTimerWithName:@"BLELJ"];
if (self.ljNumber < 2)
{
if (type == 1)
[self connectPeripheralWithUUID];
else
[self connectBLE:bleModel];
}
else
{
[[NSNotificationCenter defaultCenter] postNotificationName:BluetoothNotificationAtConnectFail object:nil];
self.isConnected = NO;
self.ljNumber = 0;
NSString *switchNum = [[NSUserDefaults standardUserDefaults] objectForKey:@"WARNINGSWITCH"];
if ([switchNum boolValue])
{
NSURL *fileURL = [[NSBundle mainBundle]URLForResource:@"alarm_sound" withExtension:@".caf"];
self.audioPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:fileURL error:nil];
self.audioPlayer.delegate = self;
self.audioPlayer.numberOfLoops = 10;
[self.audioPlayer play];
[GCDTimerManager.sharedInstance scheduleGCDTimerWithName:@"Zhendong" interval:1 queue:dispatch_get_main_queue() repeats:YES option:CancelPreviousTimerAction action:^{
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
}];
}
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"防丢警告" message:@"您已经和您的设备远离,请确认设备是否还在您附近!!!" preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
[self.audioPlayer stop];
[GCDTimerManager.sharedInstance cancelTimerWithName:@"Zhendong"];
AudioServicesRemoveSystemSoundCompletion(kSystemSoundID_Vibrate);
}]];
[[Bluetooth currentVC] presentViewController:alert animated:YES completion:nil];
}
}
}];
}
#pragma mark AVAudioPlayerDelegate
/// 音频播放完成时
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
[GCDTimerManager.sharedInstance cancelTimerWithName:@"Zhendong"];
AudioServicesRemoveSystemSoundCompletion(kSystemSoundID_Vibrate);
}
#pragma mark 通过UDID重连
- (void)connectPeripheralWithUUID
{
NSString *uuid = [[NSUserDefaults standardUserDefaults] objectForKey:AutomaticReconnectionDevice];
if (!uuid) return;
NSArray *uuidArr = @[[[NSUUID alloc] initWithUUIDString:uuid]];
NSArray *phArr = [_bleManager retrievePeripheralsWithIdentifiers:uuidArr];//serviceUUID就是你首次连接配对的蓝牙
if (phArr.count == 0)
{
return;
}
CBPeripheral* peripheral = phArr[0];
if (phArr.firstObject
// && [phArr.firstObject state] != CBPeripheralStateConnected
// && [phArr.firstObject state] != CBPeripheralStateConnecting
)
{
NSString *ble_name = peripheral.name;
NSString *ble_uuid = peripheral.identifier.UUIDString;
NSLog(@"FLT Connecting(Last)... Name ---> %@ UUID:%@",ble_name,ble_uuid);
_bleCurrentPeripheral = peripheral;
[_bleCurrentPeripheral setDelegate:self];
[_bleManager connectPeripheral:_bleCurrentPeripheral options:@{CBConnectPeripheralOptionNotifyOnDisconnectionKey:@(YES)}];
[self jisjiqi:1 bleModel:nil];
}
}
/// 移除设备
- (void)disConnectedCurrenDevice
{
[self disconnectBLE];
[Bluetooth.shareInstance.cache containsObjectForKey:sDeviceKey withBlock:^(NSString * _Nonnull key, BOOL contains) {
[self.cache removeObjectForKey:sDeviceKey withBlock:^(NSString * _Nonnull key) {
}];
}];
[self.audioPlayer stop];
[[NSNotificationCenter defaultCenter] postNotificationName:DISConnectedCurrenDevice object:nil];
[GCDTimerManager.sharedInstance cancelTimerWithName:@"Zhendong"];
AudioServicesRemoveSystemSoundCompletion(kSystemSoundID_Vibrate);
[GCDTimerManager.sharedInstance cancelTimerWithName:@"BLELJ"];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:AutomaticReconnectionDevice];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"WARNINGSWITCH"];
}
#pragma mark - coreBlueTooth --系统代理
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
_mBleManagerState = central.state;
if (central.state == CBManagerStatePoweredOn)
{
// 蓝牙开始重连
[self connectPeripheralWithUUID];
}
else if (central.state == CBManagerStatePoweredOff)
{
[[NSNotificationCenter defaultCenter] postNotificationName:BluetoothNotificationAtPowerOff object:@"PowerOff"];
CGFloat systemVision = DEVICEVERSION;
if (systemVision <10 || systemVision >= 11) {
if (self.isConnected) {
// 连接断开发出通知
self.isConnected = NO;
[[NSNotificationCenter defaultCenter] postNotificationName:BluetoothNotificationAtDisconnect object:nil];
// 清空所有
self.writecharacteristic = nil;
}
}
[self connectPeripheralWithUUID];
}
}
//搜索蓝牙设备
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral
advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI
{
NSLog(@"搜索到了设备:%@ 标示:%@ advertisementData:%@",peripheral.name,peripheral.identifier.UUIDString,advertisementData);
NSLog(@"搜索到的设备UUID:%@",peripheral.identifier.UUIDString);
NSLog(@"%@",[advertisementData objectForKey:@"kCBAdvDataServiceData"]);
NSString *ble_name = advertisementData[@"kCBAdvDataLocalName"];
NSString *MACString = [[NSString alloc] init];
NSData *manufacturerData = [advertisementData objectForKey:@"kCBAdvDataManufacturerData"];
if (manufacturerData && manufacturerData.length >= 8)
{
NSData *MACData = [[advertisementData objectForKey:@"kCBAdvDataManufacturerData"] subdataWithRange:NSMakeRange(2, 6)];
MACString = [BluetoothTool getPositiveSequenceMacWithData:MACData];
}
BLEModel *bleModel = [BLEModel new];
bleModel.central = central;
bleModel.peripheral = peripheral;
bleModel.advertisementData = advertisementData;
bleModel.RSSI = RSSI;
bleModel.UUIDString = peripheral.identifier.UUIDString;
bleModel.MACString = MACString;
bleModel.DeName = peripheral.name;
if (ble_name.length > 0)
[self.blePeripheralArr addObject:bleModel];
[[NSNotificationCenter defaultCenter] postNotificationName:@"BLEUPDATA" object:self.blePeripheralArr];
}
#pragma mark 连接外设--成功
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
NSLog(@"BLE Connected ---> Device %@", peripheral.name);
[GCDTimerManager.sharedInstance cancelTimerWithName:@"BLELJ"];
[peripheral discoverServices:nil];
[self stopScanBLE];
NSLog(@"连接成功!!!!!!");
// 连接成功保存UUID,做重连使用
[[NSUserDefaults standardUserDefaults] setObject:peripheral.identifier.UUIDString forKey:AutomaticReconnectionDevice];
// 订阅了读数据才发出连接成功通知
self.isConnected = YES;
self.currenModel.peripheral = peripheral;
self.bleCurrentPeripheral = peripheral;
[self.bleCurrentPeripheral setDelegate:self];
if (self.currenModel != nil)
{
NSMutableDictionary *dic = [NSMutableDictionary dictionary];
//[dic setObject:self.currenModel.central forKey:@"central"];
// [dic setObject:peripheral forKey:@"peripheral"];
// [dic setObject:self.currenModel.advertisementData forKey:@"advertisementData"];
[dic setObject:self.currenModel.RSSI forKey:@"RSSI"];
[dic setObject:self.currenModel.UUIDString forKey:@"UUIDString"];
[dic setObject:self.currenModel.MACString forKey:@"MACString"];
[dic setObject:peripheral.name forKey:@"DeName"];
BLEModel *model = [BLEModel yy_modelWithJSON:[self dictToJsonStr:dic]];
self.currenModel = model;
[self.cache setObject:model forKey:sDeviceKey];
}
[[NSNotificationCenter defaultCenter] postNotificationName:BluetoothNotificationAtConnectSuccess object:self.currenModel];
}
#pragma mark 连接外设——失败
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(@"设备:%@--连接失败",peripheral.name);
[SVProgressHUD showInfoWithStatus:NSLocalizedString(@"连接失败", nil)];
// 连接失败发出通知
[[NSNotificationCenter defaultCenter] postNotificationName:BluetoothNotificationAtConnectFail object:peripheral.name];
self.isConnected = NO;
}
#pragma mark 取消或已经断开连接回调
- (void) centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
NSLog(@"设备:%@--断开连接",peripheral.name);
// 连接断开发出通知
self.isConnected = NO;
[[NSNotificationCenter defaultCenter] postNotificationName:BluetoothNotificationAtDisconnect object:peripheral.name];
// 清空所有
self.writecharacteristic = nil;
[self connectPeripheralWithUUID];
}
#pragma mark - 中心读取外设实时数据
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error
{
if (error){NSLog(@"订阅失败");}
if (characteristic.isNotifying) {NSLog(@"订阅成功");} else {NSLog(@"取消订阅");}
// 判断是否监听设备广播通知成功 -->成功才发送连接成功通知
if (characteristic.isNotifying && [characteristic.UUID isEqual:[CBUUID UUIDWithString:NotifycharacteristicUUIDString]])
{
NSLog(@"连接成功!!!!!!");
// 连接成功保存UUID,做重连使用
[[NSUserDefaults standardUserDefaults] setObject:peripheral.identifier.UUIDString forKey:AutomaticReconnectionDevice];
// 订阅了读数据才发出连接成功通知
self.isConnected = YES;
self.currenModel.peripheral = peripheral;
self.bleCurrentPeripheral = peripheral;
[self.bleCurrentPeripheral setDelegate:self];
if (self.currenModel != nil)
{
NSMutableDictionary *dic = [NSMutableDictionary dictionary];
//[dic setObject:self.currenModel.central forKey:@"central"];
// [dic setObject:peripheral forKey:@"peripheral"];
// [dic setObject:self.currenModel.advertisementData forKey:@"advertisementData"];
[dic setObject:self.currenModel.RSSI forKey:@"RSSI"];
[dic setObject:self.currenModel.UUIDString forKey:@"UUIDString"];
[dic setObject:self.currenModel.MACString forKey:@"MACString"];
[dic setObject:peripheral.name forKey:@"DeName"];
BLEModel *model = [BLEModel yy_modelWithJSON:[self dictToJsonStr:dic]];
self.currenModel = model;
[self.cache setObject:model forKey:sDeviceKey];
}
[[NSNotificationCenter defaultCenter] postNotificationName:BluetoothNotificationAtConnectSuccess object:self.currenModel];
}
}
#pragma mark - 从外围设备读取数据
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
NSLog(@" 设备发过来的 characteristic name:%@ value is:%@",characteristic.UUID,characteristic.value);
}
#pragma mark 发现服务回调
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
for (CBService *service in peripheral.services) {
NSLog(@"BLE Service ---> %@", service);
[peripheral discoverCharacteristics:nil forService:service];
}
}
#pragma mark 发现特征回调
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
if ([service.UUID.UUIDString isEqualToString:@"1802"]
|| [service.UUID.UUIDString isEqualToString:@"1803"])
{
NSLog(@"服务-->%@",service.UUID.UUIDString);
for (CBCharacteristic *characteristic in service.characteristics )
{
NSLog(@"特征---->%@",characteristic.UUID.UUIDString);
if ([characteristic.UUID.UUIDString isEqualToString:@"2A06"] && [service.UUID.UUIDString isEqualToString:@"1802"])
{
[peripheral setNotifyValue:true forCharacteristic:characteristic];
self.writecharacteristic = characteristic;
}
if ([characteristic.UUID.UUIDString isEqualToString:@"2A06"] && [service.UUID.UUIDString isEqualToString:@"1803"])
{
[peripheral setNotifyValue:true forCharacteristic:characteristic];
self.writecharacteristicq = characteristic;
}
}
}
}
//写入值的监听
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error
{
NSLog(@"写入成功");
}
/// 发送指令
/// - Parameter cmd: 查找设备:0x00,取消查找:0x01,断开后报警:0x02/0xFF
- (void)writeCheckBleWithBle:(NSString *)cmd
{
NSData *data = [cmd dataUsingEncoding:NSUTF8StringEncoding];
[self.bleCurrentPeripheral writeValue:data forCharacteristic:self.writecharacteristic type:CBCharacteristicWriteWithResponse];
}
- (NSString *)dictToJsonStr:(NSMutableDictionary *)dict
{
NSError *error = nil;
NSData *jsonData = nil;
if (!self) {
return nil;
}
[dict enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
NSString *keyString = nil;
NSString *valueString = nil;
if ([key isKindOfClass:[NSString class]]) {
keyString = key;
}else{
keyString = [NSString stringWithFormat:@"%@",key];
}
if ([obj isKindOfClass:[NSString class]]) {
valueString = obj;
}else{
valueString = [NSString stringWithFormat:@"%@",obj];
}
[dict setObject:valueString forKey:keyString];
}];
jsonData = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:&error];
if ([jsonData length] == 0 || error != nil) {
return nil;
}
NSString *jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
return jsonString;
}
+ (UIViewController *)currentVC
{
UIWindow * window = [[UIApplication sharedApplication] keyWindow];
if (window.windowLevel != UIWindowLevelNormal)
{
NSArray *windows = [[UIApplication sharedApplication] windows];
for(UIWindow * tmpWin in windows)
{
if (tmpWin.windowLevel == UIWindowLevelNormal)
{
window = tmpWin;
break;
}
}
}
UIViewController *result = window.rootViewController;
while (result.presentedViewController)
{
result = result.presentedViewController;
}
if ([result isKindOfClass:[UITabBarController class]])
{
result = [(UITabBarController *)result selectedViewController];
}
if ([result isKindOfClass:[UINavigationController class]])
{
result = [(UINavigationController *)result topViewController];
}
return result;
}
@end