iOS

iOS,蓝牙

2019-11-04  本文已影响0人  若风_412d

我们的项目是中心设备开发

1.在git上找代码。星星多,就这个了


截屏2019-11-04下午2.40.39.png

BabyBluetooth
点上面的连接👇滑动

截屏2019-11-13下午3.54.42.png

2.报错
This app has crashed because it attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an NSBluetoothAlwaysUsageDescription key with a string value explaining to the user how the app uses this data.
解决:
plist文件添加:
Privacy - Bluetooth Peripheral Usage Description
Privacy - Bluetooth Always Usage Description


截屏2019-11-04下午3.01.06.png

蓝牙后台运行

是上面的那个Privacy - Bluetooth Peripheral Usage Description

3.调试,打开下面,两个代码一个mac,一个真机。运行配对成功。

下面那个是中心设备开发

截屏2019-11-04下午3.34.06.png

4.搜索蓝牙基础词汇知识:
Central(中心设备);
Peripheral(外围设备);
advertising(广告);
Services(服务);
Characteristic(特征)
CoreBluetooth介绍
等———————
5.我们项目app是中心设备

6.向硬件传数据:(这里要配合硬件)

截屏2019-11-13下午3.49.00.png

写数据包括3个步骤:1.数据类型转化,2数据拼接3.异或运算

1.数据类型转化:
data 或 byte 类型的长度
    Byte *bytes2 = (Byte *)[data bytes];
      NSLog(@"%ld",[data length]);

ascii类型(在 iOS中就是 Byte 类型)<->data

//data类型转byte类型
    Byte *bytes2 = (Byte *)[data bytes];
//byte数组转data类型
Byte bytes[]={0x01,0x02,0x03};
    [data appendBytes:bytes length:3];
//byte字节转data类型
Byte byteLon =0;
    [data appendBytes:&byteLon length:1];

byte->16进制的打印字符串。

//开发过程中要和硬件比对数据是否正确,并不做传输使用。
//打印16进制的byte字符串
-(NSString*)get16StrFromBtyea:(Byte[])byte lenth:(NSUInteger)lenth{
    NSMutableString *str16 = [NSMutableString stringWithFormat:@""];

    for (int i = 0; i< lenth ; i++) {
           NSString *strOne= [NSString stringWithFormat:@"%x",byte[i]];
                  if (strOne.length==1) {
                      strOne = [NSString stringWithFormat:@"0%@",strOne];
                      
                  }
       // NSLog(@"比特数组打印结果%@",strOne);
        
                  str16=   [NSMutableString stringWithFormat:@"%@%@",str16,strOne];
          }
    NSLog(@"比特数组打印链接结果%@",str16);

    return str16;
}

字符串 <->16进制字符串


//普通字符串转换为十六进制的。

- (NSString *)hexStringFromString:(NSString *)string{
    NSData *myD = [string dataUsingEncoding:NSUTF8StringEncoding];
    Byte *bytes = (Byte *)[myD bytes];
    //下面是Byte 转换为16进制。
    NSString *hexStr=@"";
    for(int i=0;i<[myD length];i++)
    {
        NSString *newHexStr = [NSString stringWithFormat:@"%x",bytes[i]&0xff];///16进制数
        if([newHexStr length]==1)
            hexStr = [NSString stringWithFormat:@"%@0%@",hexStr,newHexStr];
        else
            hexStr = [NSString stringWithFormat:@"%@%@",hexStr,newHexStr]; 
    } 
    return hexStr; 
}


// 十六进制转换为普通字符串的。
- (NSString *)stringFromHexString:(NSString *)hexString { 
    
    char *myBuffer = (char *)malloc((int)[hexString length] / 2 + 1);
    bzero(myBuffer, [hexString length] / 2 + 1);
    for (int i = 0; i < [hexString length] - 1; i += 2) {
        unsigned int anInt;
        NSString * hexCharStr = [hexString substringWithRange:NSMakeRange(i, 2)];
        NSScanner * scanner = [[NSScanner alloc] initWithString:hexCharStr];
        [scanner scanHexInt:&anInt];
        myBuffer[i / 2] = (char)anInt;
    }
    NSString *unicodeString = [NSString stringWithCString:myBuffer encoding:4];
    NSLog(@"------字符串=======%@",unicodeString);
    return unicodeString;
}

16进制字符串 <->NSData

// 16进制转NSData
- (NSData *)convertHexStrToData:(NSString *)str
{
    if (!str || [str length] == 0) {
        return nil;
    }
    
    NSMutableData *hexData = [[NSMutableData alloc] initWithCapacity:20];
    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;
}

 // NSData转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;
}

// NSData转16进制 第二种
-(NSString *)hexStringFormData:(NSData *)data
{
    return [[[[NSString stringWithFormat:@"%@",data]
            stringByReplacingOccurrencesOfString:@"<" withString:@""]
            stringByReplacingOccurrencesOfString:@">" withString:@""]
            stringByReplacingOccurrencesOfString:@" " withString:@""];
    
    

}


字符串<->data

//字符串转data 

-(NSData*) strToDataWithString :(NSString *)te{
    NSMutableData* data = [NSMutableData data];
    int idx;
    for (idx = 0; idx+2 <= te.length; idx+=2) {
        NSRange range = NSMakeRange(idx, 2);
        NSString* hexStr = [te substringWithRange:range];
        NSScanner* scanner = [NSScanner scannerWithString:hexStr];
        unsigned int intValue;
        [scanner scanHexInt:&intValue];

        [data appendBytes:&intValue length:1];
    }
    return data;
}

data数据的拼接/截取

data 或 byte 类型的长度
    Byte *bytes2 = (Byte *)[data bytes];
      NSLog(@"%ld",[data length]);
ascii类型:在 iOS中就是 Byte 类型, (例如:Byte byt[]={0x01,0x02,0x03};)最终传给硬件的是data类型,
截屏2019-11-13下午4.50.36.png

NSMutableData* data=[NSMutableData data];

1.data拼接Byte 数组类型

      Byte bytes[]={0x01,0x02,0x03};
    [data appendBytes:bytes length:3];

2.data拼接Byte 单个字节

       Byte byteLon =0;
    [data appendBytes:&byteLon length:1];

3.data拼接data类型

            [data appendData:data2];

4.data 截取

    NSData*subData =[data subdataWithRange:NSMakeRange(0,3)];//截取从索引0开的3个数据

异或运算

我们要对bytes进行异或运算

//data类型数据的长度
[data length]
//异或
      Byte bytes[]={0x01,0x02,0x03};
        Byte sum =0;
        for (int i = 0; i < 3; i++) {
           sum^=bytes[i];
        }
//sum 就是异或运算的结果,是一个byte类型

7.接收硬件传输数据的反馈

//所有从蓝牙传到app的数据都会走这个方法

- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {

注册通知

截屏2019-11-13下午5.27.33.png

获取数据


截屏2019-11-13下午5.24.50.png
截屏2019-11-13下午5.26.11.png

接收不到数据FISH00016ffd--Reading is not permitted.

1.找到原因
我这里git上又找了原生代码,(这个三方找问题太难了)

//判断有没有通知权限,如果没有那是铁定收不到数据的。
 if (self.characteristic.properties & CBCharacteristicPropertyNotify ||  self.characteristic.properties & CBCharacteristicPropertyIndicate) {
          
      }else{
          NSLog(@"这个characteristic没有nofity的权限");
      }

//注册通知
                    [ self.selectedPeripheral setNotifyValue:YES forCharacteristic:characteristic];



/**
* 数据更新的回调(但是有人硬是注册了通知,硬是要写入数据,就会报下面的错)
*/


- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
  if (error) {
      
      NSLog(@"%@--%@",peripheral.name,[error localizedDescription]);
      
  }

打印报错:FISH00016ffd--Reading is not permitted.

2.appstore 搜索:蓝牙助手,下载


IMG_0590.PNG

3.打开,左边是我们项目,右边是别人的。可以发现别人的有一个特征是可读,可写。我们的特征只有一个可读性,或可写。😓😓


截屏2019-12-02下午1.26.41.png
4.baby的代码里有获取特征属性的方法:
截屏2019-12-04上午11.57.26.png

我们的特征没有读取的属性所以注事readValueForCharacteristic这个方法就不会报:Reading is not permitted.这个错了

截屏2019-12-04下午1.50.46.png

取消配对弹窗,我们取消了这个操作。

//让硬件改安全等级

蓝牙提示框

截屏2019-12-13下午5.06.12.png 截屏2019-12-13下午5.08.45.png
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
    // 蓝牙状态可用
  //  if (central.state == CBCentralManagerStatePoweredOn) {
        
        // 如果蓝牙支持后台模式,一定要指定服务,否则在后台断开连接不上,如果不支持,可设为nil, option里的CBCentralManagerScanOptionAllowDuplicatesKey默认为NO, 如果设置为YES,允许搜索到重名,会很耗电
     //   [self.centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:kServiceUUID]] options:nil];
      //     [self.centralManager scanForPeripheralsWithServices:nil options:nil];
        
//    }
//    else {
//        NSLog(@"蓝牙状态异常, 请检查后重试");
//    }
    NSString *strMessage = @"";
     NSString *buttonTitle = nil;
     switch (central.state) {
         case CBManagerStatePoweredOn: {
             NSLog(@"蓝牙开启且可用");
                  [self.centralManager scanForPeripheralsWithServices:nil options:nil];

             return;
         }
             break;
     case CBManagerStateUnknown: {
            strMessage = @"手机没有识别到蓝牙,请检查手机。";
            buttonTitle = @"前往设置";
        }
            break;
        case CBManagerStateResetting: {
            strMessage = @"手机蓝牙已断开连接,重置中...";
            buttonTitle = @"前往设置";
        }
            break;
        case CBManagerStateUnsupported: {
            strMessage = @"手机不支持蓝牙功能,请更换手机。";
        }
            break;
        case CBManagerStatePoweredOff: {
            strMessage = @"手机蓝牙功能关闭,请前往设置打开蓝牙及控制中心打开蓝牙。";
            buttonTitle = @"前往设置";
        }
            break;
        case CBManagerStateUnauthorized: {
            strMessage = @"手机蓝牙功能没有权限,请前往设置。";
            buttonTitle = @"前往设置";
        }
            break;
        default: { }
            break;
    }
   
    NSLog(@"%@%@",strMessage,buttonTitle);
}

系统蓝牙弹窗控制,app蓝牙权限第一次会弹系统的没办法自定义,后续可以自定义。

    //没打开蓝牙的时候,总是提示。
    //  self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
        //没打开蓝牙的时候,不提示。

    self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:@{CBCentralManagerOptionShowPowerAlertKey:[NSNumber numberWithBool:NO]}];

跳转到蓝牙设置界面


截屏2019-12-16上午10.27.53.png

跳转到了应用的设置界面


截屏2019-12-16上午9.41.13.png
    NSString* phoneVersion = [[UIDevice currentDevice] systemVersion];
    NSLog(@"手机系统版本: %@", phoneVersion);
    
    NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
      if ([phoneVersion floatValue] > 10.0) {
          if ([[UIApplication sharedApplication] canOpenURL:url]) {
              [[UIApplication sharedApplication] openURL:url];
          }
      } else {
          if ([[UIApplication sharedApplication] canOpenURL:url]) {
              [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
          }
      }

iOS蓝牙后台运行
https://www.jianshu.com/p/da9e5237f8b8

上一篇 下一篇

猜你喜欢

热点阅读