1. 程式人生 > >iOS基於CoreBlutooth的藍芽開發

iOS基於CoreBlutooth的藍芽開發

首先如同網路一般,藍芽也類似的可以分服務端和客戶端,CoreBlutooth中有兩個角色,一個是Peripheral,相當於伺服器端,也就是我們開啟手機藍芽搜尋時找到的各個裝置;一個是Central,相當於客戶端,也就是我們使用的手機,這兩個角色和一般的手機使用主權引起的角色意識有點衝突。

藍芽通訊過程中有幾個部分,一個是Service,即伺服器提供的服務,一個服務端可能有一個或者多個Service,還有一個是Characteristic,即特徵值,相當於溝通過程中的欄位,服務端和客戶端可以針對指定特徵值進行資料交流。

因為沒有藍芽模組和藍芽裝置,所以我是在MAC端編寫了Peripheral端,手機上執行Central端(藍芽程式必須真機除錯

Peripheral端

#import <CoreBluetooth/CoreBluetooth.h>

#define TRANSFER_SERVICE_UUID @"0bd51666-e7cb-469b-8e4d-2742f1ba77cc"	//服務的UUID
#define TRANSFER_CHARACTERISTIC_UUID @"1bd51666-e7cb-469b-8e4d-2742f1ba77dd"	//讀取埠的特徵值UUID
#define TRANSFER_CHARACTERISTIC1_UUID @"2bd51666-e7cb-469b-8e4d-2742f1ba77dd"	//寫入埠的特徵值UUID

@interface ViewController ()<CBPeripheralManagerDelegate>

@property (nonatomic,strong) CBPeripheralManager *peripheral;	//peripheral管理者

@property (nonatomic,strong) CBMutableCharacteristic *transferCharacteristic;	//讀取埠特徵值

@property (nonatomic,strong) CBMutableCharacteristic *transferCharacteristic1;	//寫入埠特徵值
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    //按鈕     用於更新欄位值
    NSButton *button = [NSButton buttonWithTitle:@"dianji" target:self action:@selector(btnClick)];
    
    button.frame = NSRectFromCGRect(CGRectMake(10, 10, 100, 50));
    [self.view addSubview:button];
    
    self.peripheral = [[CBPeripheralManager alloc]initWithDelegate:self queue:nil];	//初始化,並設定代理
    
    CBMutableService *transferService = [[CBMutableService alloc]initWithType:[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID] primary:YES];	//構建服務
    // 構建兩個特徵值 引數Type:特徵值UUID,properties:埠屬性,通知、讀、寫、不帶回應寫入等等,value:特徵值,如果要設定,特徵值須為readonly,permissions:讀寫許可權
    self.transferCharacteristic = [[CBMutableCharacteristic alloc]initWithType:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID] properties: CBCharacteristicPropertyRead value:nil permissions:CBAttributePermissionsReadable];
    // properties很重要,如果沒有設定讀屬性,central呼叫read方法時會被禁止
    self.transferCharacteristic1 = [[CBMutableCharacteristic alloc]initWithType:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC1_UUID] properties: CBCharacteristicPropertyNotify |  CBCharacteristicPropertyWrite | CBCharacteristicPropertyWriteWithoutResponse value:nil permissions: CBAttributePermissionsReadEncryptionRequired | CBAttributePermissionsWriteEncryptionRequired];
    // 為服務新增特徵值
    transferService.characteristics = @[self.transferCharacteristic,self.transferCharacteristic1];
    [self.peripheral addService:transferService];	//為peripheral新增服務
    [self.peripheral startAdvertising:@{CBAdvertisementDataServiceUUIDsKey:[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]}];           //開啟廣播
}

// 必須的代理,狀態更新
- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral{
    NSLog(@"%ld",(long)peripheral.state);
}

// 接收到寫入請求後的代理
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray<CBATTRequest *> *)requests{
    CBATTRequest *request = requests[0];
    NSLog(@"-----%d",[self.peripheral updateValue:request.value forCharacteristic:self.transferCharacteristic1 onSubscribedCentrals:nil]);
}
// 接收到讀取請求後的代理
- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request{
    NSLog(@"read");
}



- (void)btnClick{
    //    [self.peripheral updateValue:[NSData dataWithBytes:"Hello world" length:11] forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil];
    
    //    self.transferCharacteristic.value = [NSData dataWithBytes:"Hello World" length:11];
    [self.peripheral updateValue:[NSData dataWithBytes:"hello World" length:11] forCharacteristic:self.transferCharacteristic1 onSubscribedCentrals:nil];	//更新指定特徵值埠的值,並不會改變characteristic.value
    [self.peripheral updateValue:[NSData dataWithBytes:"hello" length:11] forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil];
    NSLog(@"%@",[[NSString alloc]initWithData:self.transferCharacteristic1.value encoding:NSUTF8StringEncoding]);
    
}

- (void)setRepresentedObject:(id)representedObject {
    [super setRepresentedObject:representedObject];
    
    // Update the view, if already loaded.
}


@end


上面是服務端的程式碼,需要注意的是如果是自己開發藍芽模組的話,相關service的UUID以及characteristic的UUID可以和模組開發人員商定,如果是手環或者其他商用成品的話,商家應該會提供相關UUID。

Central端

//
//  ViewController.m
//  testDD
//
//  Created by 周小偉 on 2017/7/7.
//  Copyright © 2017年 周小偉. All rights reserved.
//

#import "ViewController.h"
#import <CoreBluetooth/CoreBluetooth.h>
// 三個特徵值必須和服務端一樣,不然找不到指定特徵值
#define TRANSFER_SERVICE_UUID @"0bd51666-e7cb-469b-8e4d-2742f1ba77cc"
#define TRANSFER_CHARACTERISTIC_UUID @"1bd51666-e7cb-469b-8e4d-2742f1ba77dd"
#define TRANSFER_CHARACTERISTIC1_UUID @"2bd51666-e7cb-469b-8e4d-2742f1ba77dd"

@interface ViewController ()<CBCentralManagerDelegate,CBPeripheralDelegate>

@property (nonatomic,strong) NSMutableArray *peripherArr;	//用於儲存已經發現的裝置

@property (nonatomic,strong) CBCentralManager *manager;		//central管理者

@property (nonatomic,strong) CBPeripheral *peripheral;		//當前連線的peripheral

@property (nonatomic,strong) CBCharacteristic *char1;		//讀取的特徵值埠

@property (nonatomic,strong) CBCharacteristic *char2;		//寫入的特徵值埠
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.manager = [[CBCentralManager alloc]initWithDelegate:self queue:nil];	//初始化管理者
    //CBCentralManager非當前迴圈建立,如果不用強指標引用,出了應用域就會被釋放,執行會報錯
}

// central管理者代理,必須呼叫 判斷藍芽狀態,如果狀態為藍芽開啟的話,開始掃描
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
    if (central.state == CBManagerStatePoweredOn) {
        [self.manager scanForPeripheralsWithServices:nil options:nil];
    }
}

// 掃描的代理方法 在停止掃描之前會不斷呼叫
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI{
    if (!peripheral.name) {
        return;	//過濾沒有名字的裝置
    }
    [self.manager stopScan];	//停止掃描,也可以在連線裝置後停止掃描
    
    //因為附近只有一個裝置,所以沒有對裝置進行判斷,實際上可以新增到陣列中儲存,順便新增強引用
    [central connectPeripheral:peripheral options:nil];//連線裝置,如果有必要可以針對裝置屬性進行判斷,然後連線,比如裝置名字,UUID等
    self.peripheral = peripheral;//只為了新增強引用,一般不這麼寫
    self.peripheral.delegate = self;//設定代理
}

//管理者代理,連線到裝置後呼叫
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{ [peripheral discoverServices:@[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]];//查詢服務,引數如果設定為nil為查詢所有服務
}

//peripheral代理,發現沒用的服務時呼叫
- (void)peripheral:(CBPeripheral *)peripheral didModifyServices:(NSArray<CBService *> *)invalidatedServices{ NSLog(@"---- %@",invalidatedServices);
}

//發現服務後呼叫
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
    NSArray *services = peripheral.services;
    //獲取裝置的所有服務,下面的處理只因為服務端我只有一個service,所以沒有進行處理,實際上一個裝置會有多個service,需要遍歷分別處置
    if (services.count) {
        CBService *service = services[0];
        CBUUID *writeUUID = [CBUUID UUIDWithString: TRANSFER_CHARACTERISTIC1_UUID];
        CBUUID *readUUID = [CBUUID UUIDWithString: TRANSFER_CHARACTERISTIC_UUID];
        [peripheral discoverCharacteristics:@[writeUUID, readUUID] forService:service];//查詢指定特徵值
    }
}

//peripheral代理,發現特徵值時呼叫
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
    if (!error) {
        NSArray *characteristicArray = service.characteristics;//獲取service的特徵值,實際上一個service可能有多個特徵值,需要自己處理,比如針對特徵值的properties進行處理
        if(characteristicArray.count > 1){
            //因為讀寫操作是針對特徵值進行的,所以要取得兩個特徵值
            CBCharacteristic *readCharacteristic = characteristicArray[0];
            CBCharacteristic *writeCharacteristic = characteristicArray[1];
            self.char1 = readCharacteristic;
            self.char2 = writeCharacteristic;
            
            // 通知使能, `YES` enable notification only, `NO` disable notifications and indications
            //[peripheral setNotifyValue:YES forCharacteristic:readCharacteristic];
            // [peripheral setNotifyValue:YES forCharacteristic:writeCharacteristic]; //為指定特徵值新增通知,需要特徵值的properties設定了notify屬性才能設定,一般前面會加入判斷 if(writeCharacteristic.properties & CBCharacteristicPropertyNotify)
            // [peripheral readValueForCharacteristic:readCharacteristic];//讀取資料,需要特徵值的properties設定了read屬性,判斷方法類似上一句// [peripheral readValueForCharacteristic:writeCharacteristic];
        }
        NSLog(@"Hello ");
    } else {
        NSLog(@"Discover Charactertics Error : %@", error);
    }
}
// peripheral代理,設定過notify屬性的特徵值的值發生變化後會呼叫這個方法,比如我的demo裡面的寫入特徵值我設定了notify和write,然後寫入後因為值改變了就會呼叫這個代理方法,在peripheral為特徵值設定setNotifyValue:forCharacteristic:時就會呼叫這個方法
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    if (error) {
        NSLog(@"%@",characteristic);
        NSLog(@"%@",error.userInfo);
        return;
    }
    CBCharacteristicProperties properties = characteristic.properties;
    if (properties) {
        NSLog(@"%@",characteristic.value);
    }
}

// peripheral代理方法,寫入操作後呼叫需要寫入時設定type為withResponse才會呼叫
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    if (!error) {
        NSLog(@"Write Success");
    }else{
        NSLog(@"WriteValue Error = %@",error.userInfo);
    }
}

// peripheral代理方法,指定特徵值的value值變化了後呼叫
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    if (error) {
        NSLog(@"update value error:%@",error.userInfo);
    }else{
        NSData *responseData = characteristic.value;
        NSLog(@"||||||||||%@",[[NSString alloc]initWithData:responseData encoding:NSUTF8StringEncoding]);
        NSLog(@"%@",[[NSString alloc]initWithData:characteristic.value encoding:NSUTF8StringEncoding]);
    }
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    static int i = 0;
    NSString *str = [NSString stringWithFormat:@"Hello %d",i];
    [self.peripheral writeValue:[NSData dataWithBytes:str.UTF8String length:strlen(str.UTF8String)]forCharacteristic:self.char2 type:CBCharacteristicWriteWithResponse];//寫入操作,引數type,必須要withResponse才會有代理回撥,如果要設定withoutResponse需要相關特徵值設定了一樣的屬性
    NSLog(@"%ld",[self.peripheral maximumWriteValueLengthForType:CBCharacteristicWriteWithoutResponse]);
    i++;
    // [self.peripheral readValueForCharacteristic:self.char1];//讀取操作
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated.
}
@end

主要的藍芽互動過程就類似於上面所示,但實際上溝通過程並沒有達到理想效果,比如寫入操作只能進行一次,我並不知道是否因為裝置的原因,如果有機會可以找到其他裝置再來嘗試。


相關推薦

iOS基於CoreBlutooth開發

首先如同網路一般,藍芽也類似的可以分服務端和客戶端,CoreBlutooth中有兩個角色,一個是Peripheral,相當於伺服器端,也就是我們開啟手機藍芽搜尋時找到的各個裝置;一個是Central,相當於客戶端,也就是我們使用的手機,這兩個角色和一般的手機使用主權引起的角

iOS開發—CoreBluetooth詳解

CoreBluetooth的API是基於BLE4.0的標準的。這個框架涵蓋了BLE標準的所有細節。僅僅只有新的iOS裝置和Mac是和BLE標準相容.在CoreBluetooth框架中,有兩個主要的角色:周邊和中央(Peripheral and Central) ,整個框架

iOS開發(二)在裝置端實現Central角色

若想在裝置上實現Central角色的功能,主要有以下步驟: 2.搜尋周圍廣播的裝置 3.與一個外設進行連線,並探索外設提供的服務 4.向外設傳送讀寫characteristic的請求,如果有需要訂閱characteristic值得更新,來跟蹤資料的變化。 myCe

IOS Ble開發實現

1.本篇博文闡述如何開發Ble藍芽。在藍芽中的一些常見服務,掃描,以及連結; 主藍芽類檔案.h 主藍芽類檔案.m UUID檔案 藍芽列表展示的檔案 一:引入Ble藍芽的框架<CoreBluetooth/CoreBluetooth.h>

iOS開發 —— 連線列印機發送16進位制資料的問題

最近在做公司的一個藍芽連線印表機的專案,正常的藍芽連線印表機進行列印沒問題,但是要傳送一個16進位制的指令來獲取藍芽裝置資訊時頗費了一番功夫,現做如下記錄: Byte byteArray[] = {0x1d ,0x67 ,0x61}; NSData *sendData = [NSData data

iOS開發

原作者:===>https://blog.csdn.net/swibyn/article/details/20531593 demo下載 http://download.csdn.net/detail/swibyn/9717588 直接看程式碼 http://blog.

iOS近場通訊(開發,WiFi開發)

標籤: ios it 近場通訊 藍芽 wifi 分類: iOS 1 AirDrop (UIActivityViewController類) 功能:實現iOS裝置間的檔案和資料分享。AirDrop使用藍芽來掃描周圍的裝置,當兩臺裝置通過藍芽建立起了連線,考慮到

iOS開發連線和資料讀寫

當下藍芽開發可謂是越來越火,不論是智慧穿戴的興起還是藍芽傢俱,車聯網藍芽等等,很多同學也會接觸到藍芽的專案,我從事藍芽開發也有一段時間了,經手了兩個專案。廢話不多說了,先向大家簡單的介紹有關藍芽開發的知識。藍芽低能耗(BLE),以下介紹的都是圍繞iOS的框架展開

iOS開發(二):iOS 4.0中心模式 程式碼實現

上一篇簡單介紹了藍芽的部分基礎知識,詳細的東西大家可以去github上搜babyBluetooth,裡面有一些學習資料 iOS連線外設的流程 建立中心管理者 掃描外設 discoverPeripheral 連線外設 connectPeripheral

iOS開發

因工作的需要, 前段時間整理了一下IOS藍芽通訊相關的東西,把整理的一個成果給大家分享一下。如果有不足的地方歡迎指正。 一、專案背景 簡單介紹一下我所做的東西,裝置目前有四個,分別是體脂秤、血壓計、血糖儀、監護儀等。從名稱大家應該知道這些是什麼東西了。對,沒錯,這些裝置主要

ios開發(三)app作為外設被連線的實現

再上一節說了app作為central連線peripheral的情況,這一節介紹如何使用app釋出一個peripheral,給其他的central連線 還是這張圖,central模式用的都是左邊的類,而peripheral模式用的是右邊的類 peripheral模式的流

iOS開發的連線和資料的讀寫

       藍芽開發說簡單也簡單,說不簡單也有點難,開發人員在首次開發藍芽前首先需要搞清楚藍芽開發的概念,還要了解掌握藍芽開發的一整套流程,這樣才能快速上手開發藍芽。       藍芽開發分為兩種模式:管理者模式和中心者模式。管理者模式基本很少用到,相當於iPhone手機

iOS開發把16進位制字串轉換成NSData的方法

把16進位制字串轉換成NSData: -(NSData *)hexString:(NSString *)hexString { int j=0; Byte bytes[20];

開發BLE協議流程(iOS為例)

憑藉大腦殘留的記憶寫的BLE的一些概念與接入流程。IOT領域與智慧裝置通訊的方式除了zigbee wifi 就算藍芽了,BLE(bluetooth low energy)看名字就是低功耗的一個東西,通俗來說ble很簡單啊,因為無論是iOS還是android 提供的api 都遮

iOS 開發——CoreBluetooth開發(一)

最近要做關於iOS上的藍芽開發專案,為此閱讀了蘋果的官方文件,這裡做一些翻譯和摘錄和大家共享交流。(如需轉載請註明出處) 關於Core BlueTooth Core BlueTooth是一個iOS的開發框架,其中包含了若干類,能夠和低功耗藍芽(符合藍芽4

iOS開發CoreBluetooth快速入門

在iOS開發中,實現藍芽通訊有兩種方式,一種是使用傳統的GameKit.framework,另一種就是使用在iOS 5中加入的CoreBluetooth.framework。 利用CoreBluetooth框架,我們可以輕鬆實現兩個iOS裝置、iOS裝置與非

iOS開發(一)相關基礎知識

藍芽常見名稱和縮寫 MFI ======= make for ipad ,iphone, itouch 專們為蘋果裝置製作的裝置 BLE ==== buletouch low energy,藍芽4.0裝置因為低耗電,所以也叫做BLE peripher

Android開發模組進行通訊(基於eclipse)

public class ComminuteActivity extends Activity { private BluetoothReceiver receiver; private BluetoothAdapter bluetoothAdapter; private Lis

Android 開發常用UUID表

        // Sample Services.          attributes.put("0000180d-0

IOS--swift BLE通訊管理(多裝置)

之前一直做的是Android,公司IOS端突然要同時進行多個專案,IOS同學表示壓力山大,所以臨危受命由我來完成專案中關於BLE通訊的功能模組,由於之前做過Android版本的,並且執行狀況良好,一直都比較穩定,因此分享出來,也希望大家能提出好的建議。 總共有4個swift檔案。 如圖