1. 程式人生 > >iOS藍芽開發:藍芽的連線和資料的讀寫

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];

}

以上就是藍芽通訊的全部步驟,共同交流,歡迎關注三掌櫃的微信公眾號,歡迎關注!