iOS藍芽開發:藍芽的連線和資料的讀寫
藍芽開發說簡單也簡單,說不簡單也有點難,開發人員在首次開發藍芽前首先需要搞清楚藍芽開發的概念,還要了解掌握藍芽開發的一整套流程,這樣才能快速上手開發藍芽。
藍芽開發分為兩種模式:管理者模式和中心者模式。管理者模式基本很少用到,相當於iPhone手機作為外設,自己建立服務和特性,然後用其他裝置連線iPhone手機;中心者模式一般是大部分情況下都會使用的,使用中心者模式開發相當於iPhone手機作為主機,連線藍芽外設,下面介紹藍芽開發的例子就是使用的中心者模式來講解的。
一、關於藍芽開發的一些重要的理論概念:
1、服務(services):藍芽外設對外廣播的時候一定會有一個服務,有些時候也可以是有多個服務,服務下面包含一些特性,服務可以理解成一個模組的視窗;2、特徵(characteristic):特徵存在於服務下面的,一個服務下面可以有多個特徵,特徵可以理解成具體實現功能的視窗,一般的特性都會有value,也就是特徵值,是特徵和外界互動的最小單位;
3、UUID:藍芽上的唯一標示符,為了區分不同服務和特徵,就用UUID來表示。
二、藍芽連線的主要步驟
1、建立一個CBCentralManager例項來進行藍芽管理;
2、搜尋掃描外圍裝置;
3、連線外圍裝置;
4、獲得外圍裝置的服務;
5、獲得服務的特徵;
6、從外圍裝置讀取資料;
7、給外圍裝置傳送(寫入)資料。
三、藍芽連線和資料讀寫的具體步驟
1、匯入蘋果系統藍芽框架
#import <CoreBluetooth/CoreBluetooth.h>
2、遵循兩個藍芽框架相關的協議
<CBCentralManagerDelegate,CBPeripheralDelegate>
3、新建兩個例項屬性,一個特徵屬性
@property (nonatomic, strong) CBCentralManager *centralManager; //中心管理者
@property (nonatomic, strong) CBPeripheral *peripheral; //連線到的外設
@property (nonatomic, strong) CBCharacteristic *characteristic; //特徵
4、初始化CBCentralManager,進行藍芽管理
- (void)viewDidLoad {
[super viewDidLoad];
self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()]; //建立例項進行藍芽管理
}
//若中心管理者初始化之後 就會觸發下面這個代理方法 該代理方法是用來判斷手機藍芽的狀態的
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
// 藍芽可用,開始掃描外設
if (central.state == CBManagerStatePoweredOn) {
NSLog(@"藍芽可用");
//在中心管理者成功開啟之後再進行一些操作
//搜尋掃描外設
// 根據SERVICE_UUID來掃描外設,如果不設定SERVICE_UUID,則掃描所有藍芽裝置
// [self.centralManager startAdvertising:@{CBAdvertisementDataServiceUUIDsKey:@[[CBUUID UUIDWithString:SERVICE_UUID]]}];
[central scanForPeripheralsWithServices:nil options:nil];
}
if(central.state == CBManagerStateUnsupported) {
NSLog(@"該裝置不支援藍芽");
}
if (central.state == CBManagerStatePoweredOff) {
NSLog(@"藍芽已關閉");
}
if (central.state == CBManagerStateUnknown) {
NSLog(@"藍芽當前狀態不明確");
}
if (central.state == CBManagerStateUnauthorized) {
NSLog(@"藍芽未被授權");
}
}
5、搜尋外圍裝置
//執行掃描動作之後,如果掃描到外設了,就會自動回撥下面的協議方法
/** 發現符合要求的外設,回撥 */
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *, id> *)advertisementData RSSI:(NSNumber *)RSSI {
NSLog(@"%@====",peripheral.name);
//根據外設名字有選擇性的篩選連線藍芽裝置
if ([peripheral.name hasPrefix:@"TEAMOSA"]) {
//在這裡對外設攜帶的廣播資料進行進一步的處理
if ([self.peripheraNames containsObject:peripheral.name]) {
//如果陣列中包含了就不再新增
return;
}
//新增到外設名字陣列中
[self.peripheraNames addObject:peripheral.name];
//標記外設,讓它的生命週期與控制器的一致
self.peripheral = peripheral;
// 可以根據外設名字來過濾外設
// [central connectPeripheral:peripheral options:nil];
}
// 連線外設
// [central connectPeripheral:peripheral options:nil];
}
6、連線外圍裝置
//連線外圍裝置,中心管理者連線外設成功,如果連線成功就會回撥這個協議方法
/** 連線成功 */
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
//連線成功之後,可以進行服務和特性的發現。 停止中心管理裝置的掃描動作,要不然在你和已經連線好的外設進行資料溝通時,如果又有一個外設進行廣播且符合你的連線條件,那麼你的iOS裝置也會去連線這個裝置(因為iOS BLE4.0是支援一對多連線的),導致資料的混亂。
//停止掃描動作
[self.centralManager stopScan];
// 設定外設的代理
peripheral.delegate = self;
// 根據UUID來尋找服務
// [peripheral discoverServices:@[[CBUUID UUIDWithString:SERVICE_UUID]]];
//外設發現服務,傳nil代表不過濾,一次性讀出外設的所有服務
[peripheral discoverServices:nil];
NSLog(@"%s, line = %d, %@=連線成功", __FUNCTION__, __LINE__, peripheral.name);
}
//外設連線失敗
/** 連線失敗的回撥 */
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error {
NSLog(@"%s, line = %d, %@=連線失敗", __FUNCTION__, __LINE__, peripheral.name);
}
//丟失連線 掉線
/** 斷開連線 */
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error {
NSLog(@"%s, line = %d, %@=斷開連線", __FUNCTION__, __LINE__, peripheral.name);
// 斷開連線可以設定重新連線
[central connectPeripheral:peripheral options:nil];
}
7、獲取外圍裝置服務和特徵
/** 發現服務 */
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
// 遍歷出外設中所有的服務
for (CBService *service in peripheral.services) {
// NSLog(@"所有的服務:%@",service);
}
// 這裡僅有一個服務,所以直接獲取
CBService *service = peripheral.services.lastObject;
// 根據UUID尋找服務中的特徵
// [peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:CHARACTERISTIC_UUID]] forService:service];
// [peripheral discoverCharacteristics:@[service.UUID] forService:service];
[peripheral discoverCharacteristics:nil forService:service];
}
8、從外圍裝置讀取資料
// 更新特徵的value的時候會呼叫 (凡是從藍芽傳過來的資料都要經過這個回撥,簡單的說這個方法就是你拿資料的唯一方法) 你可以判斷是否 從外圍裝置讀資料
/** 接收到資料回撥 */
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
// if (characteristic == @"你要的特徵的UUID或者是你已經找到的特徵") {
// //characteristic.value就是你要的資料
// }
if ([peripheral.name hasPrefix:@"TEAMOSA"]){
NSData *data = characteristic.value;
NSString *value = [self hexadecimalString:data];
// NSLog(@"characteristic(讀取到的): %@, data : %@, value : %@", characteristic, data, value);
}
// 拿到外設傳送過來的資料
// NSData *data = characteristic.value;
// self.textFild.text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
9、向外圍裝置傳送(寫入)資料
//這個方法你可以放在button的響應裡面,也可以在找到特徵的時候就寫入,具體看你業務需求怎麼用
//[self.peripherale writeValue:_batteryData forCharacteristic:self.characteristic type:CBCharacteristicWriteWithResponse];//第一個引數是已連線的藍芽裝置; 第二個引數是要寫入到哪個特徵; 第三個引數是通過此響應記錄是否成功寫入 需要注意的是特徵的屬性是否支援寫資料
/** 寫入資料回撥 */
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(nonnull CBCharacteristic *)characteristic error:(nullable NSError *)error {
/*
typedef NS_OPTIONS(NSUInteger, CBCharacteristicProperties) {
CBCharacteristicPropertyBroadcast = 0x01,
CBCharacteristicPropertyRead = 0x02,
CBCharacteristicPropertyWriteWithoutResponse = 0x04,
CBCharacteristicPropertyWrite = 0x08,
CBCharacteristicPropertyNotify = 0x10,
CBCharacteristicPropertyIndicate = 0x20,
CBCharacteristicPropertyAuthenticatedSignedWrites = 0x40,
CBCharacteristicPropertyExtendedProperties = 0x80,
CBCharacteristicPropertyNotifyEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0) = 0x100,
CBCharacteristicPropertyIndicateEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0) = 0x200
};
打印出特徵的許可權(characteristic.properties),可以看到有很多種,這是一個NS_OPTIONS的列舉,可以是多個值
常見的又read,write,noitfy,indicate.知道這幾個基本夠用了,前倆是讀寫許可權,後倆都是通知,倆不同的通知方式
*/
// NSLog(@"%s, line = %d, char.pro = %d", __FUNCTION__, __LINE__, characteristic.properties);
// 此時由於列舉屬性是NS_OPTIONS,所以一個列舉可能對應多個型別,所以判斷不能用 = ,而應該用包含&
NSLog(@"write value success(寫入成功) : %@", characteristic);
}
10、具體呼叫給藍芽外設寫入資料方法,這裡的例子是以按鈕點選事件裡面來呼叫處理
//傳送按鈕點選事件
- (void)sendClick {
if (!self.characteristic) {
return;
}
_tempValue = [NSString stringWithFormat:@"%.0f", progressView.centigradeDegree];
_timeValue = [NSString stringWithFormat:@"%.0ld", (long)progressView1.timeDegree];
NSString *ttData = [NSString stringWithFormat:@"%@,%@U", _tempValue, _timeValue];
// NSString *aaa = [DataCoverTool coverFromStringToHexStr:ttData];
// 用NSData型別來寫入
// NSData *data = [NSKeyedArchiver archivedDataWithRootObject:arry];
NSData *data = [ttData dataUsingEncoding:NSUTF8StringEncoding];
// NSData *data = [self dataWithString:ttData];
// 根據上面的特徵self.characteristic來寫入資料
[self.peripheral writeValue:data forCharacteristic:self.characteristic type:CBCharacteristicWriteWithResponse];
}
以上就是藍芽通訊的全部步驟,共同交流,歡迎關注三掌櫃的微信公眾號,歡迎關注!