被忽略的設置要重新建立連接,需要重新按步驟進行。這里以手機與藍牙連接為例加以說明。 手機要先打開藍牙并處在被發(fā)現(xiàn)狀態(tài),按住藍牙耳機開關鍵不放,直到手機藍牙搜索到耳機并顯示出耳機型號,再點擊手機中顯示的耳機型號進行連接(有時還需要輸入PIN碼,默認一般是”1234"),顯示“已連接”說明連接成功,此時方可松開耳機開關鍵。 以下以科奈信藍牙耳機為例,說一下具體與手機的連接步驟,供參考: 1、在耳機關閉狀態(tài),長按多功能鍵約 5秒,語音提示”開機“”配對中“,此時紅藍指示燈快速交替閃爍; 2、激活手機或其他設備上的藍牙功能,然后使用菜單來”添加“、”搜索“或”掃描“新的藍牙設備; 3、從手機或其他設備的藍牙設備列表中選擇藍牙型號名(如”Y4“)并連接(如果要求輸入密碼,請輸入”0000“)。連接成功后語音提示”藍牙已連接“。就可以在手機或其他設備上使用通話功能及收聽設備上的音頻。 還有的藍牙耳機連接手機用以下辦法: 1、在耳機關機的狀態(tài),長按NFC功能(大約10秒鐘),先會出現(xiàn)藍燈閃爍,這個時候不要激動,繼續(xù)長按保持,直到耳機指示燈出現(xiàn)紅藍交替閃爍的狀態(tài),進入被搜索的狀態(tài)。(切記耳機一定要在被搜索的狀態(tài),才能被其他藍牙設備搜索到。) 2、打開手機的藍牙,點擊搜索藍牙設備,直到手機搜索到耳機的信號,會顯示出藍牙型號。 3、點擊進行連接,連接成功后,耳機指示燈會顯示為藍燈間隔閃爍。
創(chuàng)新互聯(lián)專注于復興網(wǎng)站建設服務及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗。 熱誠為您提供復興營銷型網(wǎng)站建設,復興網(wǎng)站制作、復興網(wǎng)頁設計、復興網(wǎng)站官網(wǎng)定制、小程序開發(fā)服務,打造復興網(wǎng)絡公司原創(chuàng)品牌,更為您提供復興網(wǎng)站排名全網(wǎng)營銷落地服務。
總結一下藍牙開發(fā)相關的知識點和注意事項,做個筆記,也希望你們能少踩坑
(公司部分藍牙項目為混編項目,藍牙相關處理均采用了Objective-C,故本文????均采用OC,Swift處理相同)
藍牙4.0包含兩個藍牙標準,它是一個是 雙模 的標準,它包含 傳統(tǒng)藍牙部分(也稱經(jīng)典藍牙) 和 低功耗藍牙部分(BLE) , 二者適用于不同的應用場景和應用條件。他們的特點如下
所以藍牙4.0是集成了傳統(tǒng)藍牙和低功耗藍牙兩個標準的,并不只是低功耗藍牙
藍牙4.0支持兩種部署方式: 雙模式 和 單模式 ,雙模同時支持經(jīng)典藍牙和低功耗藍牙,而單模則只支持其中一種。
二者更多細節(jié)詳見: 傳統(tǒng)藍牙和低功耗藍牙的區(qū)別
iOS中藍牙相關功能都封裝進了 CoreBluetooth 類中,其中有幾個常見的參數(shù)和概念
具體API參考 CoreBluetooth藍牙開發(fā)
保存到數(shù)組中的設備可通過 UUID 來進行區(qū)分。從 iOS7之后蘋果不提供外設的mac地址,外設的唯一標識換成了由mac封裝加密后的UUID,需要注意的是不同的手機獲取同一個外設的UUID是不同的,所以在不同手機之間UUID不是唯一的,但在本機上可以作為唯一標識(特殊情況手機刷機后也會改變UUID)。
如何獲取Mac地址
一般使用場景是根據(jù)Mac地址區(qū)分某個外設
注意點:
寫入數(shù)據(jù)時可能會遇到需要分包發(fā)送的情況,我們可以通過下面的API或許當前特征支持的最大的單條寫入長度
maxLength 一般取決于藍牙模塊內(nèi)部接收 緩沖區(qū) 的大小,很多硬件設備這個緩沖區(qū)的大小是 20 字節(jié), 這個大小也和特征的寫入權限有關,像具有寫入權限 withResponse 類的特征其大小一般為 512 字節(jié),當然這些都是取決于設備測的設置;
當我們單次發(fā)送的數(shù)據(jù)字節(jié)長度大于 maxLength 時,我們就需要采用分包的方式來發(fā)送數(shù)據(jù)了,
分包發(fā)送的邏輯類似于下面
這邊延時主要是設備側的接收模塊接收數(shù)據(jù)以及處理能力有限
外圍設備測和中心設備(大部分情況下是手機)保持藍牙連接的狀態(tài)下,如果長時間不產(chǎn)生交互,藍牙就會斷開,所以為了保持兩者持續(xù)的連接狀態(tài),需要做?;钐幚?,也就是需要持續(xù)的發(fā)送心跳包(watchdog)。相應的處理是使用一個定時器定時向設備側發(fā)送符合設備協(xié)議格式的心跳包。
斷開連接很簡單,只需要調(diào)用 [self.centralManager cancelPeripheralConnection:peripheral] 傳入需要斷開連接的設備對象就行了。斷開連接時會自動調(diào)用 centralManager:didDisconnectPeripheral:error: 代理方法。
按照之前的慣例,當error為nil時表示斷開成功,error不為nil時斷開失敗。這種理解是錯誤的。
當你調(diào)用 cancelPeripheralConnection: 方法(主動斷開)斷開連接時error為nil ; 沒有調(diào)用這個方法(異常斷開)而斷開時error返回的是異常斷開的原因。也可以理解為主動調(diào)用斷開連接方法一定會斷開
接下來就是斷開重連的問題了,對藍牙功能進行封裝時肯定少不了斷開重連。首先斷開時可通過上面的代理方法的error是否為nil判斷是否是異常斷開,一般情況下異常斷開時是需要重連的
原因就是當設備斷開連接后 peripheral.services 為nil了,當然 service.characteristics 也是nil,所以需要在斷開連接時把保存這個設備對應的服務和特征全部清除,然后在連接成功時重新過一遍發(fā)現(xiàn)服務和發(fā)現(xiàn)特征的流程就好了。
iOS7 開始,Apple加入了Beacon圍欄檢測的API, ( iBeacon-維基百科 ), 其工作方式是,配備有低功耗藍牙(BLE)通信功能的設備使用 BLE 技術向周圍發(fā)送自己特有的 ID,接收到該 ID 的應用軟件會根據(jù)該 ID 采取一些行動。比如,在店鋪里設置 iBeacon 通信模塊的話,便可讓 iPhone 和 iPad 上運行一資訊告知服務器,或者由服務器向顧客發(fā)送折扣券及進店積分, 或者公司的手機打卡,只要手機靠近打卡器一定范圍,手機測就向打開器發(fā)送打卡信息,從而自動打卡。這種場景還有很多。 其中一個最重要的功能就是App的喚醒功能(殺死后也能喚醒)
舉一個我們的例子,我們的產(chǎn)品業(yè)務場景就是在進入車輛以后,需要使用藍牙連接我們的后裝車載設備以采集車輛信息和駕駛行為行程等,這里有一個問題就是在App被殺死的情況下如何喚醒App, 因為不可能要求用戶每次都主動去打開App,這樣體驗太差。我們的做法是通過iBeacon,當我們的車輛點火以后,設備測通電,發(fā)出 iBeacon廣播 ,App實現(xiàn)監(jiān)聽iBeacon相關功能后就可以喚醒我們App,然后在相應的回調(diào)的處理一些事情,比如通過藍牙連接設備。這里的前提條件是我們的硬件設備測包含iBeacon模塊,具有iBeacon功能,而且對iBeacon的廣播頻率也有一定的要求,長了可能喚醒的功能會不穩(wěn)定,官方建議的好像是100ms,頻率超高越耗電,但可以讓手機或其它監(jiān)聽設備越快地發(fā)現(xiàn)iBeacon。標準的BLE廣播距離是100m,這使Beacon在室內(nèi)位置跟蹤場景下的效果更理想。
關于iBeacon更多的使用及介紹請參考
蘋果核 - iOS端近場圍欄檢測(一) ——iBeacon
iBeacon技術初探
1、按下iPhone手機右側的【電源鍵】讓手機進入屏幕鎖定的待機狀態(tài)中。
2、輕觸【主屏幕按鈕】進入解鎖狀態(tài),手動輸入自行設置的6位數(shù)字密碼。
3、將iPhone手機解鎖至手機桌面上,按住屏幕底部【向上滑動】。
4、按住屏幕上滑打開【控制中心】后,選擇【藍牙】功能點擊,屏幕上提示【藍牙連接已啟用】時,即為成功開了iPhone手機的藍牙可搜索模式。
5、按下【HOME鍵】返回至手機桌面后找到【設置】圖標打開。
6、在【設置】的具體選項列表中找到【藍牙】設置打開。
7、頁面跳轉至【藍牙】的詳情頁面中,可搜索狀態(tài)下,選擇想要連接的設備。
8、成功連接設備后,設備名稱右側即會出現(xiàn)【已連接】的字樣。
藍牙開發(fā)說簡單也簡單,說不簡單也有點難,開發(fā)人員在首次開發(fā)藍牙前首先需要搞清楚藍牙開發(fā)的概念,還要了解掌握藍牙開發(fā)的一整套流程,這樣才能快速上手開發(fā)藍牙。
? 藍牙開發(fā)分為兩種模式:管理者模式和中心者模式。管理者模式基本很少用到,相當于iPhone手機作為外設,自己創(chuàng)建服務和特性,然后用其他設備連接iPhone手機;中心者模式一般是大部分情況下都會使用的,使用中心者模式開發(fā)相當于iPhone手機作為主機,連接藍牙外設,下面介紹藍牙開發(fā)的例子就是使用的中心者模式來講解的。
在這里我還是要推薦下我自己建的iOS開發(fā)學習群:680565220,群里都是學ios開發(fā)的,如果你正在學習ios ,我歡迎你加入,今天分享的這個案例已經(jīng)上傳到群文件,大家都是軟件開發(fā)黨,不定期分享干貨(只有iOS軟件開發(fā)相關的),包括我自己整理的一份2018最新的iOS進階資料和高級開發(fā)教程
一、關于藍牙開發(fā)的一些重要的理論概念:
1、服務(services):藍牙外設對外廣播的時候一定會有一個服務,有些時候也可以是有多個服務,服務下面包含一些特性,服務可以理解成一個模塊的窗口;
2、特征(characteristic):特征存在于服務下面的,一個服務下面可以有多個特征,特征可以理解成具體實現(xiàn)功能的窗口,一般的特性都會有value,也就是特征值,是特征和外界交互的最小單位;
? 3、UUID:藍牙上的唯一標示符,為了區(qū)分不同服務和特征,就用UUID來表示。
二、藍牙連接的主要步驟
?1、創(chuàng)建一個CBCentralManager實例來進行藍牙管理;
?2、搜索掃描外圍設備;
?3、連接外圍設備;
?4、獲得外圍設備的服務;
?5、獲得服務的特征;
?6、從外圍設備讀取數(shù)據(jù);
?7、給外圍設備發(fā)送(寫入)數(shù)據(jù)。
三、藍牙連接和數(shù)據(jù)讀寫的具體步驟
?1、導入蘋果系統(tǒng)藍牙框架
#import
?2、遵循兩個藍牙框架相關的協(xié)議
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()]; ? ? //創(chuàng)建實例進行藍牙管理
}
//若中心管理者初始化之后 就會觸發(fā)下面這個代理方法 該代理方法是用來判斷手機藍牙的狀態(tài)的
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
// 藍牙可用,開始掃描外設
if (central.state == CBManagerStatePoweredOn) {
NSLog(@"藍牙可用");
//在中心管理者成功開啟之后再進行一些操作
//搜索掃描外設
// 根據(jù)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(@"藍牙當前狀態(tài)不明確");
}
if (central.state == CBManagerStateUnauthorized) {
NSLog(@"藍牙未被授權");
}
}
? 5、搜索外圍設備
//執(zhí)行掃描動作之后,如果掃描到外設了,就會自動回調(diào)下面的協(xié)議方法
/** 發(fā)現(xiàn)符合要求的外設,回調(diào) */
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
NSLog(@"%@====",peripheral.name);
//根據(jù)外設名字有選擇性的篩選連接藍牙設備
if ([peripheral.name hasPrefix:@"TEAMOSA"]) {
//在這里對外設攜帶的廣播數(shù)據(jù)進行進一步的處理
if ([self.peripheraNames containsObject:peripheral.name]) {
//如果數(shù)組中包含了就不再添加
return;
}
//添加到外設名字數(shù)組中
[self.peripheraNames addObject:peripheral.name];
//標記外設,讓它的生命周期與控制器的一致
self.peripheral = peripheral;
// 可以根據(jù)外設名字來過濾外設
// [central connectPeripheral:peripheral options:nil];
}
// 連接外設
// [central connectPeripheral:peripheral options:nil];
}
6、連接外圍設備
//連接外圍設備,中心管理者連接外設成功,如果連接成功就會回調(diào)這個協(xié)議方法
/** 連接成功 */
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
//連接成功之后,可以進行服務和特性的發(fā)現(xiàn)。 停止中心管理設備的掃描動作,要不然在你和已經(jīng)連接好的外設進行數(shù)據(jù)溝通時,如果又有一個外設進行廣播且符合你的連接條件,那么你的iOS設備也會去連接這個設備(因為iOS BLE4.0是支持一對多連接的),導致數(shù)據(jù)的混亂。
//停止掃描動作
[self.centralManager stopScan];
// 設置外設的代理
peripheral.delegate = self;
// 根據(jù)UUID來尋找服務
// [peripheral discoverServices:@[[CBUUID UUIDWithString:SERVICE_UUID]]];
//外設發(fā)現(xiàn)服務,傳nil代表不過濾,一次性讀出外設的所有服務
[peripheral discoverServices:nil];
NSLog(@"%s, line = %d, %@=連接成功", __FUNCTION__, __LINE__, peripheral.name);
}
//外設連接失敗
/** 連接失敗的回調(diào) */
- (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、獲取外圍設備服務和特征
/** 發(fā)現(xiàn)服務 */
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
// 遍歷出外設中所有的服務
for (CBService *service in peripheral.services) {
// NSLog(@"所有的服務:%@",service);
}
// 這里僅有一個服務,所以直接獲取
CBService *service = peripheral.services.lastObject;
// 根據(jù)UUID尋找服務中的特征
// [peripheral discoverCharacteristics:@[[CBUUID UUIDWithString:CHARACTERISTIC_UUID]] forService:service];
// [peripheral discoverCharacteristics:@[service.UUID] forService:service];
[peripheral discoverCharacteristics:nil forService:service];
}
8、從外圍設備讀取數(shù)據(jù)
// 更新特征的value的時候會調(diào)用 (凡是從藍牙傳過來的數(shù)據(jù)都要經(jīng)過這個回調(diào),簡單的說這個方法就是你拿數(shù)據(jù)的唯一方法) 你可以判斷是否 從外圍設備讀數(shù)據(jù)
/** 接收到數(shù)據(jù)回調(diào) */
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
// if (characteristic == @"你要的特征的UUID或者是你已經(jīng)找到的特征") {
// //characteristic.value就是你要的數(shù)據(jù)
// }
if ([peripheral.name hasPrefix:@"TEAMOSA"]){
NSData *data = characteristic.value;
NSString *value = [self hexadecimalString:data];
// NSLog(@"characteristic(讀取到的): %@, data : %@, value : %@", characteristic, data, value);
}
// 拿到外設發(fā)送過來的數(shù)據(jù)
// NSData *data = characteristic.value;
// self.textFild.text = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
}
9、向外圍設備發(fā)送(寫入)數(shù)據(jù)
//這個方法你可以放在button的響應里面,也可以在找到特征的時候就寫入,具體看你業(yè)務需求怎么用
//[self.peripherale writeValue:_batteryData forCharacteristic:self.characteristic type:CBCharacteristicWriteWithResponse];//第一個參數(shù)是已連接的藍牙設備; 第二個參數(shù)是要寫入到哪個特征; 第三個參數(shù)是通過此響應記錄是否成功寫入 需要注意的是特征的屬性是否支持寫數(shù)據(jù)
/** 寫入數(shù)據(jù)回調(diào) */
- (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、具體調(diào)用給藍牙外設寫入數(shù)據(jù)方法,這里的例子是以按鈕點擊事件里面來調(diào)用處理
//發(fā)送按鈕點擊事件
- (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];
// 根據(jù)上面的特征self.characteristic來寫入數(shù)據(jù)
[self.peripheral writeValue:data forCharacteristic:self.characteristic type:CBCharacteristicWriteWithResponse];
iOS 藍牙開發(fā)(一)
iOS 藍牙開發(fā)(二)
iOS 藍牙開發(fā)(四)
前面記錄了藍牙如何進行掃描、鏈接、以及獲取外設的服務和特征,本篇筆記我將記錄如何實現(xiàn) 與外設做數(shù)據(jù)交互(explore and interact) 。
構建方法流程:鏈接成功-獲取指定的服務與特征-訂閱指定的特征值-通過具有寫權限的特征值來寫數(shù)據(jù)-最后在函數(shù) didUpdateValueForCharacteristic 中獲取藍牙的反饋信息;
總結:
本篇筆記大概就是在接收到服務和特征后對數(shù)據(jù)進行寫入的操作的過程,筆記中的重點在于要熟悉構建特征和服務的方法流程。熟悉流程,我們就能清楚知道當在寫入數(shù)據(jù)時,系統(tǒng)藍牙會在函數(shù) didUpdateValueForCharacteristic 方法中給我們反饋寫入是否成功的反饋信息。
要先看狀態(tài)是不是POWER_ON ,POWER_ON后再開啟掃描。另外看看打開藍牙了沒?