iOS 藍芽
iOS 開發藍芽4.0的框架是CoreBluetooth
在CoreBluetooth中有兩個主要的部分,Central(中心)和Peripheral(周邊)。
CBPeripheralManager作為周邊裝置是伺服器,CBCentralManager作為中心裝置是客戶端。所有可用的iOS 裝置可以作為周邊 也可以作為中央,但不可以同時既是周邊也是中央。
一般手機是客戶端(中心裝置),裝置(魔法棒)---->硬體裝置,因為是手機去連線手環這個伺服器的。周邊(Peripheral)是生成或者儲存了資料的裝置,中心是使用這些資料的裝置。
可以認為周邊是一個廣播資料的裝置,他廣播到外部世界說他這兒有資料,並且也說明了能提供的服務。另一邊,中央開始掃描附近有沒有服務,如果中央發現了想要的服務,然後中央就會請求連線周邊,一旦連線成功,兩個裝置之間就開始交換資料了。
除了中央和周邊,還要考慮兩者交換的資料結構,這些資料在服務中被結構化,每個服務由不同的特徵組成,特徵是包含一個單一邏輯值的屬性型別。
BLE-----------buletouch low energy , 藍芽4.0裝置耗電低
peripheral--外設 central 中心 發起連線的是central 被連線的裝置是peripheral
service and characteristics -- 服務和特徵 每個裝置都會提供服務和特徵,類似於服務端的API,但是機構不同。每個外設會有很多服務,每個服務中包含很多欄位,這些欄位的許可權一般分為 讀read 和寫write ,通知notify幾種,就是我們連線裝置後具體需要操作的內容。
Description 每個characteristics可以對應一個或多個Descrition使用者描述characteristics的資訊或屬性
藍芽一般有兩種不同的業務場景,一種叫做中心模式,就是以你的app作為中心,連線其他的外設的場景;另一種是外設模式,使用手機作為外設識別其他中心裝置操作的場景。
藍芽中心模式流程
1 建立中心角色
2 掃描外設
3 連線外設
4掃描外設中的服務和特徵
4.1 獲取外設的services
4.2 獲取外設的Characteristics,獲取characteristics的值,獲取characteristics的Descriptor和Descriptor的值
5 與外設做資料互動
6 訂閱characteristics的通知
7 斷開連線(disconnect)
藍芽外設模式流程
1 啟動一個Peripheral管理物件
2 本地Peraipheral設定服務、特性、描述、許可權等等
3 Peripheral傳送廣告
4 設定處理訂閱、取消訂閱、讀Characteristic 寫characteristics的委託方法
藍芽裝置的狀態
CBCentralManagerStateUnknown ------ 初始化中
CBCentralManagerStateResetting ------ 裝置不支援狀態
CBCentralManagerStateUnsupported --------裝置未授權狀態
CBCentralManagerStateUnauthorized ---------裝置未授權狀態
CBCentralManagerStatePoweredOff -------- 尚未開啟藍芽
CBCentralManagerStatePoweredOn ----------藍芽已經成功開啟
藍芽裝置中的五種工作狀態
準備 廣播 監聽掃描 發起連線 已連線
藍芽外設模式
//
// HB_BindStickViewController.m
// HomeBridge
//
// Created by Jason on 15/9/9.
// Copyright (c) 2015年 ___HB___. All rights reserved.
//
#import "HB_BindStickViewController.h"
#import <CoreBluetooth/CoreBluetooth.h>
#import "Header.h"
#define OPENBLUETOOTH 100
#define BINDSUCCESS 101
#define ALREADYBIND 102
@interface HB_BindStickViewController ()<UITableViewDataSource,UITableViewDelegate,CBCentralManagerDelegate,CBPeripheralDelegate,UIAlertViewDelegate>
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (weak, nonatomic) IBOutlet UIView *bindView;
@property (nonatomic,retain) NSMutableArray * dataArray;
@property(nonatomic,retain)CBCentralManager * manager;
@property(nonatomic,retain)CBPeripheral * peripheral;
@property(nonatomic,retain)CBCharacteristic * characteristic;
@property(nonatomic,assign)NSInteger type;
@property (nonatomic,copy) NSString * teacherID;
@property (nonatomic,assign) BOOL isShowAlert;
//@property (nonatomic,copy) NSMutableString * macID;
@end
@implementation HB_BindStickViewController
- (void)viewDidLoad {
[super viewDidLoad];
if (!_dataArray) {
_dataArray = [[NSMutableArray alloc]initWithCapacity:1];
}
self.manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
}
- (void)getUserInfoWithID:(NSString *)user_id{
// HB_UserInfoModel * userinfo = [HB_UserInfoModel defaultManager];
//判斷是否相同_macID
[HB_UserService customsGetPropWithUserId:[NSNumber numberWithInteger:[user_id integerValue]] tn:@"customs" field:@"rftoken" withBlock:^(NSDictionary *result, NSError *error) {
if (result) {
NSString * str = [result valueForKey:@"Content"];
NSString * _macID = [[NSUserDefaults standardUserDefaults]stringForKey:@"macID"];
if ([str isEqual:_macID]) {
[self showAL:user_id];
}else{
[self Bindbluetooth];
}
}
}];
}
- (void)showAL:(NSString *)user_id{
NSString * val = [NSString stringWithFormat:@"%@",user_id];
[HB_UserService customsGetPropWithUserId:[NSNumber numberWithInteger:[user_id integerValue]] tn:@"customs" field:@"phone" withBlock:^(NSDictionary *result, NSError *error) {
if (result) {
NSString * phone = [result valueForKey:@"Content"];
[HB_UserService getUserInfo:@"id" Val:val More:@1 withBlock:^(NSDictionary *result1, NSError *error1) {
if (result1) {
NSArray * item = [result1 valueForKey:@"Content"];
NSString * name;
if (item.count > 0 ) {
name = [[item objectAtIndex:0] valueForKey:@"name_zh"];
}
NSString * string = [NSString stringWithFormat:@"此裝置已繫結到其他教師,如需使用請聯絡此教師解鎖此裝置\n%@聯絡電話:%@",name,phone];
UIAlertView * alertView = [[UIAlertView alloc]initWithTitle:@"教棒已被使用" message:string delegate:self cancelButtonTitle:@"確定" otherButtonTitles: nil];
alertView.tag = ALREADYBIND;
if (!_isShowAlert) {
_isShowAlert = YES;
[alertView show];
}
}
}];
}
}];
}
- (IBAction)ScanBluetoothBtnClick:(UIButton *)sender {
if (_manager.state != CBCentralManagerStatePoweredOn) {
UIAlertView * alertView = [[UIAlertView alloc]initWithTitle:@"開啟藍芽" message:nil delegate:self cancelButtonTitle:@"不開啟" otherButtonTitles:@"開啟", nil];
alertView.tag = OPENBLUETOOTH;
[alertView show];
}else{
[self.manager scanForPeripheralsWithServices:nil options:nil];
}
}
//藍芽狀態改變
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
NSString * message;
switch (central.state) {
case 0:
message = @"初始化中,請稍後……";
break;
case 1:
message = @"裝置不支援狀態,過會請重試……";
break;
case 2:
message = @"裝置未授權狀態,過會請重試……";
break;
case 3:
message = @"裝置未授權狀態,過會請重試……";
break;
case 4:
message = @"尚未開啟藍芽,請在設定中開啟……";
break;
case 5:
message = @"藍芽已經成功開啟,稍後……";
break;
default:
break;
}
}
//掃描到裝置
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{
NSLog(@"發現藍芽裝置:%@",peripheral.name);
if (_dataArray.count == 0) {
[_dataArray addObject:peripheral];
}else{
for (NSInteger i = 0 ; i < _dataArray.count; i++) {
CBPeripheral * ph = _dataArray[i];
if (i == _dataArray.count - 1 && ph != peripheral) {
[_dataArray addObject:peripheral];
}
}
}
[_tableView reloadData];
if ([peripheral.name isEqual:BLUETOOTHNAME]) {
self.peripheral = peripheral;
}
}
//連線成功
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
peripheral.delegate = self;
[central stopScan];
[peripheral discoverServices:nil];
}
//返回的藍芽服務通知通過代理實現
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
for (CBService * service in peripheral.services) {
if (error) {
NSLog(@"Error changing notification state: %@",[error localizedDescription]);
return;
}
NSLog(@"Service found with UUID :%@",service.UUID);
NSLog(@"%@",service.UUID.UUIDString);
// if ([service.UUID isEqual:[CBUUID UUIDWithString:@"FFE0"]]) {
[peripheral discoverCharacteristics:nil forService:service];
// }
}
}
//查詢到該裝置所對應的服務
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
if (error) {
NSLog(@"Error changing notification state: %@",[error localizedDescription]);
return;
}
NSLog(@"%@",service.UUID.UUIDString);
for (CBCharacteristic * characteristic in service.characteristics) {
NSLog(@"查詢到的服務(屬性)%@",characteristic.UUID);
NSString * str1 = characteristic.UUID.UUIDString;
NSLog(@"哈哈哈哈哈哈哈哈%@",str1);
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"2A23"]]) {
[peripheral readValueForCharacteristic:characteristic];
}
//所對應的屬性用於接收和傳送資料
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"2AF0"]]) {
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
[peripheral readValueForCharacteristic:characteristic];
}
// NSLog(@"%@",string);
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"2AF1"]]) {
_characteristic = characteristic;
// [self Bindbluetooth];
[self LookForID];
}
}
}
//接收資料的函式.處理藍芽發過來得資料 讀資料代理
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
if (error) {
NSLog(@"Error changing notification state: %@",[error localizedDescription]);
return;
}
NSLog(@"---------%@",[characteristic UUID]);
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"2AF0"]]) {
NSLog(@"收到藍芽發來的資料%@",characteristic.value);
NSString * string = [self hexadecimalString:characteristic.value];
if ([string isEqual:@"00"]) {
[self LookForID];
return;
}
if ([string isEqual:@"0000ff00ff00"]) {
if (_type == 2) {
[self contect];
}
}
NSLog(@"%@",string);
[self getUserIDWithString:string];
}else if([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"2A23"]]){
NSLog(@"收到藍芽發來的資料%@",characteristic.value);
NSString * string = [self hexadecimalString:characteristic.value];
NSLog(@"##############################%@",string);
NSMutableString * _macID = [[NSMutableString alloc]init];
for (NSInteger i = string.length - 1 ; i >= 0 ; i-= 2) {
NSString * sr = [string substringWithRange:NSMakeRange(i - 1, 2)];
if (i== 1) {
// sr = [NSString stringWithFormat:@"%d",[self to10:sr].integerValue - 16];
sr = [self to16:[self to10:sr].integerValue - 16];
}
[_macID appendString:sr];
if (i % 2 != 0 && i > 1) {
[_macID appendString:@":"];
}
}
[[NSUserDefaults standardUserDefaults]setValue:_macID forKey:@"macID"];
}
}
//寫資料代理
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
sleep(3);
NSLog(@"%@",characteristic.UUID);
if (error) {
NSLog(@"Error changing notification state: %@",[error localizedDescription]);
[HB_Utils showItoast:@"繫結失敗"];
}
}
- (void)contect{
NSString * _macID = [[NSUserDefaults standardUserDefaults]stringForKey:@"macID"];
[HB_UserService customsEditWithUserId:[HB_UserInfoModel defaultManager].user_id tn:@"customs" field:@"rftoken" val:_macID withBlock:^(NSDictionary *result, NSError *error) {
if (result) {
UIAlertView * alertView = [[UIAlertView alloc]initWithTitle:@"魔法棒繫結成功,可以鼓勵孩子了!" message:nil delegate:self cancelButtonTitle:@"確定" otherButtonTitles: nil];
alertView.tag = BINDSUCCESS;
if (!_isShowAlert) {
_isShowAlert = YES;
[alertView show];
}
return;
}
}];
}
#pragma mark - NSData and NSString
//將傳入的NSData型別轉換成NSString並返回
- (NSString*)hexadecimalString:(NSData *)data{
NSString* result;
const unsigned char* dataBuffer = (const unsigned char*)[data bytes];
if(!dataBuffer){
return nil;
}
NSUInteger dataLength = [data length];
NSMutableString* hexString = [NSMutableString stringWithCapacity:(dataLength * 2)];
for(int i = 0; i < dataLength; i++){
[hexString appendString:[NSString stringWithFormat:@"%02lx", (unsigned long)dataBuffer[i]]];
}
result = [NSString stringWithString:hexString];
return result;
}
//將傳入的NSString型別轉換成NSData並返回
- (NSData*)dataWithHexstring:(NSString *)hexstring{
NSData* aData;
return aData = [hexstring dataUsingEncoding: NSUTF16StringEncoding];
}
// 十六進位制轉換為普通字串的。
- (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;
}
- (NSString *)to10:(NSString *)num
{
NSString *result = [NSString stringWithFormat:@"%ld", strtoul([num UTF8String],0,16)];
return result;
}
- (NSString *)to16:(int)num
{
NSString *result = [NSString stringWithFormat:@"%@",[[NSString alloc] initWithFormat:@"%1x",num]];
if ([result length] < 2) {
result = [NSString stringWithFormat:@"0%@", result];
}
return result;
}
- (void)LookForID{
_type = 1;
if(_characteristic == nil){
NSLog(@"_characteristic 為空");
return;
}
u_int8_t packet[7] = {0x00, 0x00, 0xFF, 0x03, 0x01, 0x04, 0x00};
NSMutableData *value = [NSMutableData data];
for (NSInteger i = 0; i < 7; i ++) {
NSData * data ;
data = [NSData dataWithBytes:&packet[i] length:1];
NSLog(@"%02lx",(unsigned long)packet[i]);
[value appendData:data];
}
NSLog(@"十六進位制:%@",value);
sleep(3);
[_peripheral writeValue:value forCharacteristic:_characteristic type:CBCharacteristicWriteWithResponse];
NSLog(@"已經向外設%@的特徵值%@寫入資料",_peripheral.name,_characteristic.description);
}
- (void)Bindbluetooth{
_type = 2;
if(_characteristic == nil){
NSLog(@"_characteristic 為空");
return;
}
u_int8_t packet[8] = {0x00, 0x00, 0xFF, 0x07, 0x02, 0x00, 0x00, 0x00};
// u_int16_t str = 539;
// NSString * m = [self to16:540];
NSInteger userid = [[HB_UserInfoModel defaultManager].user_id integerValue];
// NSLog(@"----%@",[self stringFromHexString:s]);
NSData * idData = [NSData dataWithBytes:&userid length:4];
const unsigned char* dataBuffer = (const unsigned char*)[idData bytes];
NSMutableData * Data5= [NSMutableData data];
NSInteger length = 0;
for (NSInteger i = idData.length - 1; i >= 0; i --) {
[Data5 appendData:[NSData dataWithBytes:&dataBuffer[i] length:1]];
length += [[self to10:[NSString stringWithFormat:@"%02lx", (unsigned long)dataBuffer[i]]]integerValue];
}
NSLog(@"%@",Data5);
NSInteger checkNum = length + 9;
NSData * checkNumData = [NSData dataWithBytes:&checkNum length:4];
const unsigned char* dataBuffer2 = (const unsigned char*)[checkNumData bytes];
NSMutableData * Data6= [NSMutableData data];
for (NSInteger i = 0; i < 1; i ++) {
[Data6 appendData:[NSData dataWithBytes:&dataBuffer2[i] length:1]];
}
NSLog(@"%@",Data6);
NSMutableData *value = [NSMutableData data];
for (NSInteger i = 0; i < 8; i ++) {
NSData * data ;
if (i == 5) {
data = Data5;
}else if(i == 6){
data = Data6;
}else{
data = [NSData dataWithBytes:&packet[i] length:1];
}
NSLog(@"%02lx",(unsigned long)packet[i]);
[value appendData:data];
}
NSLog(@"十六進位制:%@",value);
sleep(3);
[_peripheral writeValue:value forCharacteristic:_characteristic type:CBCharacteristicWriteWithResponse];
NSLog(@"已經向外設%@的特徵值%@寫入資料",_peripheral.name,_characteristic.description);
}
#pragma mark -tableViewDelegate
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return _dataArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
CBPeripheral * peripheral = _dataArray[indexPath.row];
//NSLog(@"%@",peripheral.RSSI);
cell.textLabel.text = peripheral.name;
if ([peripheral.name isEqual:BLUETOOTHNAME]) {
cell.detailTextLabel.text = @"魔法棒";
}else{
cell.detailTextLabel.text = nil;
}
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
CBPeripheral * peripheral = _dataArray[indexPath.row];
if ([peripheral.name isEqual:BLUETOOTHNAME]) {
self.peripheral = peripheral;
[self.manager connectPeripheral:self.peripheral options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:CBConnectPeripheralOptionNotifyOnDisconnectionKey]];
}else{
UIAlertView * alertView = [[UIAlertView alloc]initWithTitle:@"選擇的裝置有誤" message:nil delegate:self cancelButtonTitle:@"重新選擇" otherButtonTitles: nil];
[alertView show];
}
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
return 44;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section{
return 0.01;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section{
return 0.01;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//應答回覆
- (void)answerBack{
if(_characteristic == nil){
NSLog(@"_characteristic 為空");
return;
}
u_int8_t packet[6] = {0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00};
NSMutableData *value = [NSMutableData data];
for (NSInteger i = 0; i < 6; i ++) {
NSData * data = [NSData dataWithBytes:&packet[i] length:1];
[value appendData:data];
}
NSLog(@"十六進位制:%@",value);
sleep(3);
[_peripheral writeValue:value forCharacteristic:_characteristic type:CBCharacteristicWriteWithResponse];
NSLog(@"已經向外設%@的特徵值%@回覆資料",_peripheral.name,_characteristic.description);
}
#pragma mark - alertViewDelegate
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex{
if (alertView.tag == OPENBLUETOOTH) {
if (buttonIndex == 1) {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"prefs:root=Bluetooth"]];
}
}else if (alertView.tag == BINDSUCCESS){
[[NSUserDefaults standardUserDefaults]setBool:YES forKey:ISBINGING];
if ([self.delegate respondsToSelector:@selector(updateUIWithBindSuccess:)]) {
[self.delegate updateUIWithBindSuccess:YES];
}
[self.navigationController popViewControllerAnimated:YES];
}else if (alertView.tag == ALREADYBIND){
[self.navigationController popViewControllerAnimated:YES];
}
}
- (void)getUserIDWithString:(NSString *)string{
if (string.length > 15 && _type == 1) {
_teacherID = [self to10:[string substringWithRange:NSMakeRange(8, 8)]];
if (_teacherID.integerValue == 0) {
[self Bindbluetooth];
}else{
[self getUserInfoWithID:_teacherID];
}
[self answerBack];
}
}
@end
相關文章
- ios 藍芽iOS藍芽
- iOSBluetooth(藍芽)iOS藍芽
- iOS藍芽開發iOS藍芽
- MASA MAUI Plugin IOS藍芽低功耗(三)藍芽掃描UIPluginiOS藍芽
- iOS藍芽開發 Bluetooth藍芽CoreBluetooth 藍芽中心裝置的實現 藍芽外設的實現 有DemoiOS藍芽
- iOS 藍芽開發 - swift版iOS藍芽Swift
- iOS 藍芽開發·基礎篇iOS藍芽
- iOS藍芽4.0(BLE)開發(一)iOS藍芽
- [轉載]ios藍芽開發學習筆記(四)ios藍芽應用的後臺處理iOS藍芽筆記
- iOS藍芽Mesh開發總結一iOS藍芽
- iOS藍芽Mesh開發總結二iOS藍芽
- iOS藍芽4.0開發基礎教程iOS藍芽
- 藍芽藍芽
- iOS 藍芽4.0開發使用(內附Demo)iOS藍芽
- iOS-BLE藍芽開發持續更新iOS藍芽
- Android藍芽使用詳解(普通藍芽)Android藍芽
- 藍芽模組藍芽模組
- Android藍芽那點事——深入瞭解藍芽BlE藍芽 《總結篇》Android藍芽
- Android藍芽協議-藍芽掃描 startDiscoveryAndroid藍芽協議
- 藍芽HFP 藍芽電話剖析(二) --- AT command集合藍芽
- ESP32藍芽學習--藍芽概念學習藍芽
- java+藍芽Java藍芽
- 藍芽4.0 BLE藍芽
- 白色藍芽耳機藍芽
- iOS藍芽開發CoreBlueTooth庫核心方法使用介紹iOS藍芽
- MASA MAUI Plugin 安卓藍芽低功耗(一)藍芽掃描UIPlugin安卓藍芽
- 熊晨灃藍芽實戰--小程式藍芽連線2.0藍芽
- 藍芽工作流程藍芽
- 藍芽之九-AT命令藍芽
- 低功耗藍芽(5)藍芽
- 低功耗藍芽(2)藍芽
- 低功耗藍芽(3)藍芽
- 藍芽學習1藍芽
- BLE低功耗藍芽藍芽
- 藍芽耳機怎麼恢復中文模式 藍芽耳機調不了中文藍芽模式
- GJLightBlueTooth——一個輕量級的iOS藍芽開發庫iOS藍芽
- iOS之BLE藍芽SDK開發個人總結(進階篇)iOS藍芽
- iOS之BLE藍芽SDK開發個人總結(基礎篇)iOS藍芽