藍牙 BLE CoreBluetooth 初探

藍牙 BLE CoreBluetooth 初探

藍牙

Bluetooth 4.0之後就將通訊模式分為高速及低速,低速低耗能簡稱為BLE,可以連接一些量測型的感測器類型像:心跳計、血壓…等,使得iDevice可以不用再使用Dock方式製作產品,也不需要再經過MFi認證才能與iDevice連接,如此一來可以增加APP型態的多元,也能間階的降低一些成本,如果想要跟BLE週邊連接,iOS 5之後提供corebluetooth framework與週邊連接,整流程中為DiscoverConnectExploreInteract,下面文章將會從iDevice連線至BLE周邊讀取資料為例子介紹。

Discover/Connect

依照箭頭方向由上而下為順序依序完成Discover、Connect流程。

CBCentralManager

使用CoreBluetooth Framework中,主要管理連線的是CBCentralManager這個Object,它掌控整個BLE狀態的管理,使用時要先對CBCentralManager初始化:

//-----------start-----------
CBCentralManager *CM = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
//------------end------------

現在就開始往下介紹。

centralManagerDidUpdateState

在一開始宣告初CBCentralManager時就有指定Delegate為self,並且必需要在.h內加上Delegate宣告:

//-----------start-----------
@interface TestCoreBluetooth : NSObject<CBCentralManagerDelegate> {
:
:
:
}
//------------end------------

宣告完成後,再加入centralManagerDidUpdateState這個Delegate內容,

//-----------start-----------
-(void)centralManagerDidUpdateState:(CBCentralManager*)cManager
{
    NSMutableString* nsmstring=[NSMutableString stringWithString:@"UpdateState:"];
    BOOL isWork=FALSE;
    switch (cManager.state) {
        case CBCentralManagerStateUnknown:
            [nsmstring appendString:@"Unknown\n"];
            break;
        case CBCentralManagerStateUnsupported:
            [nsmstring appendString:@"Unsupported\n"];
            break;
        case CBCentralManagerStateUnauthorized:
            [nsmstring appendString:@"Unauthorized\n"];
            break;
        case CBCentralManagerStateResetting:
            [nsmstring appendString:@"Resetting\n"];
            break;
        case CBCentralManagerStatePoweredOff:
            [nsmstring appendString:@"PoweredOff\n"];
            if (connectedPeripheral!=NULL){
                [CM cancelPeripheralConnection:connectedPeripheral];
            }
            break;
        case CBCentralManagerStatePoweredOn:
            [nsmstring appendString:@"PoweredOn\n"];
            isWork=TRUE;
            break;
        default:
            [nsmstring appendString:@"none\n"]; 
            break;
    }
    NSLog(@"%@",nsmstring);
    [delegate didUpdateState:isWork message:nsmstring getStatus:cManager.state];
}
//------------end------------

centralManagerDidUpdateState的Delegate是用來得知藍牙目前的狀態,所以會有個結果是用來判斷iDevice是否支援BLE,因為BLE是在iphone 4s、New iPad之後才有的,現階段還是需要偵測使用的環境,當然可以根據這些狀態的口報來決定APP的功能或其他提示使用者的動作。

scanForPeripheralsWithServices

先前確定周邊支援BLE且運作正常後,我們就要來開啟BLE搜尋功能來尋找BLE的週邊,當週邊接收到搜尋功能的廣播訊息時,依照BLE通訊規範,週邊會在一定時間內回覆,所以我們在此可以設定2秒的Timer計時器,當時間一到就停止scan的功能。

//-----------start-----------
CBCentralManager *CM = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
[CM scanForPeripheralsWithServices:nil options:options];
[NSTimer scheduledTimerWithTimeInterval:2.0f target:self selector:@selector(scanTimeout:) userInfo:nil repeats:NO];
//------------end------------

設定2秒後觸發執行scanTimeoutmethod,再將scanForPeripheralsWithServices的值設為nil,代表搜尋的Service type不受限制,當你搜尋特定時,就必需要將它的UUID填入,像範例這樣:

//-----------start-----------
 NSArray    *uuidArray= [NSArray arrayWithObjects:[CBUUID UUIDWithString:@"180D"], nil];
        [CM scanForPeripheralsWithServices:uuidArray options:options];
//------------end------------

其中UUIDWithString:@"180D"180D就是Heart Rate Service type,一旦指定Service type,結果就只會將週邊有Heart Rate類型一一列出來,要了解更多的Service Type可以到Bluetooth官網查詢。 當您了解Service type是哪一種類型時就可以來做對應的流程及資料的解析,也可以製作出符合一般標準週邊的通用APP。

didDiscoverPeripheral

didDiscoverPeripheral屬於Delegate功能,所以要按照它預設的宣告將要處理的過程寫在裡面,格式如下:

//-----------start-----------
-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{

//處理過程

}
//------------end------------

advertisementData會報告可以連線的週邊內容, 如果將它印出來會像這樣:

//-----------start-----------
adverisement:{
    kCBAdvDataLocalName = "INFOS 4090v35.05";
    kCBAdvDataServiceUUIDs =     (
        "Unknown (<fff0>)"
    );
    kCBAdvDataTxPowerLevel = 0;
}

//------------end------------

RSSI是訊號的強度,是以NSNumber Object存在,取得後可以依照NSNumber的方式整數值做處理與轉換,接下來我們將一些資訊列印出來,整個範例可以是這樣子:

//-----------start-----------

-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI { NSMutableString* nsmstring=[NSMutableString stringWithString:@"\n"]; [nsmstring appendString:@"Peripheral Info:"]; [nsmstring appendFormat:@"NAME: %@\n",peripheral.name]; [nsmstring appendFormat:@"RSSI: %@\n",RSSI]; if (peripheral.isConnected){ [nsmstring appendString:@"isConnected: connected"]; }else{ [nsmstring appendString:@"isConnected: disconnected"]; } NSLog(@"adverisement:%@",advertisementData); [nsmstring appendFormat:@"adverisement:%@",advertisementData]; [nsmstring appendString:@"didDiscoverPeripheral\n"]; NSLog(@"%@",nsmstring); } //------------end------------

結果輸出:

//-----------start-----------
2013-02-25 14:43:17.243 gw-health-01[141:907] 
Peripheral Info:NAME: INFOS 4090v35.05
RSSI: -69
isConnected: disconnected
adverisement:{
    kCBAdvDataServiceUUIDs =     (
        "Unknown (<fff0>)"
    );
}
//------------end------------

如果有發現可連線的BLE週邊,它就會不斷的執行didDiscoverPeripheral,並將資訊傳入,利用這個方式將每次得到的結果存入Array,就可以得到搜尋周邊的結果然後再提供給USER選擇,或是從中可以去判斷某個特別的週邊是否存在而決定要不要連線。

stopScan

執行scanForPeripheralsWithServices 掃描周邊設定2秒的Timer,當時間到時就停止scan,一般2秒內無反應就可以當作是沒有其他週邊回應,承上面scanForPeripheralsWithServices中有設定Timer去呼叫scanTimeout,所以將stopScan寫在scanTimeout裡面:

//-----------start-----------
- (void) scanTimeout:(NSTimer*)timer
{
    if (CM!=NULL){
            [CM stopScan];
    }else{
        NSLog(@"CM is Null!");
    }
    NSLog(@"scanTimeout");
}

//------------end------------

connectPeripheral

didDiscoverPeripheral得到的BLE週邊列表讓User選擇要連線的BLE,再將 CBPeripheral傳入connectPeripheral進行連線,格式:

//-----------start-----------
 [CBCentralManager connectPeripheral:CBPeripheral* options:NSDictionary*]
//------------end------------

在此將它包裝成一個connect Method,

//-----------start-----------
- (void) connect:(CBPeripheral*)peripheral
{

    if (![peripheral isConnected]) {
        [CM connectPeripheral:peripheral options:nil];
        connectedPeripheral=peripheral;
    }

}

//------------end------------

option傳入nil,connectPeripheral傳入Method connect的值。

didConnectPeripheral

執行connectPeripheral之後並連線成功後就會引發didConnectPeripheral的Delegate:

//-----------start-----------
-(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
:
:
:

}
//------------end------------

在這裡有個重點,連線成功後引發Delegate時,就必需要針對其CBPeripheral馬上進行discoverServices的動作,去了解週邊提供什麼樣的Services

執行discoverServices之後又會引發另一個didDiscoverServicesDelegate,不過這會在Explore中介紹。

Explore

Discover/Connect 中使用CBCentralManager進行連線/搜尋BLE周邊的功能,連線之後需要靠的是CBPeripheral來傳送/接收資料。

CBPeripheral

//-----------start-----------
@interface DYCoreBluetooth : NSObject<CBCentralManagerDelegate, CBPeripheralDelegate> {

:
:
:

}

//------------end------------

之後連線的重點全都是在Delegate的互動,查看Service Type或是有什麼樣的Services可以提供。

didConnectPeripheral

前面有稍為介紹didConnectPeripheral,這是在連線成功後就會引發的Delegate,但一定要在這裡執行一些Method才可以順利的引發另一個CBPeripheral的Delegate去查看有什麼樣的Services

//-----------start-----------
-(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
    NSLog(@"Connect To Peripheral with name: %@\nwith UUID:%@\n",peripheral.name,CFUUIDCreateString(NULL, peripheral.UUID));

    peripheral.delegate=self;
    [peripheral discoverServices:nil];//一定要執行"discoverService"功能去尋找可用的Service

}

//------------end------------

例子中已經將peripheral.delegate=self,接下來進行peripheral的任何動做引發的Delegate都在這個Object中,執行discoverServicesMethod,讓它去尋找Services,一找到Services就又會引發didDiscoverServicesDelegate,這樣我們就可以了解有什麼Services。

didDiscoverServices

從這裡開始就是最關鍵

//-----------start-----------
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error {
    NSLog(@"didDiscoverServices:\n");
    if( peripheral.UUID == NULL  ) return; // zach ios6 added
    if (!error) {
        NSLog(@"====%@\n",peripheral.name);
        NSLog(@"=========== %d of service for UUID %@ ===========\n",peripheral.services.count,CFUUIDCreateString(NULL,peripheral.UUID));

        for (CBService *p in peripheral.services){
            NSLog(@"Service found with UUID: %@\n", p.UUID);
            [peripheral discoverCharacteristics:nil forService:p];
        }

    }
    else {
        NSLog(@"Service discovery was unsuccessfull !\n");
    }

}

//------------end------------

peripheral.services.count會知道有多少個Services,在每個Servces中還會有Characteristics需要了解,所以會針對每個Service來執行 peripheral discoverCharacteristics: forService:去知道每個Service下有多少個Characteristics提供傳送/接收的溝通,在執行discoverCharacteristics後也引發didDiscoverCharacteristicsForService Delegate,最後再由didDiscoverCharacteristicsForService真正的判斷什麼樣的Service、什麼樣的Characteristic再進行之後收到的資料的處理動作,例如: 發現2A37的Characteristic,就要進行註冊通知,到時候BLE週邊發訊息過來才會立即的得到通知並得到資料。

didDiscoverCharacteristicsForService

整個最關鍵的地方就是這個Delegate,程式架構如下:

//-----------start-----------
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{

:
:
:

}

//------------end------------

Interact

完成didDiscoverCharacteristicsForService之後,整個連線過程算是完成,之後的didUpdateValueForCharacteristicDelegate是整個資料接收動作都在這發生,經過接收到的資料進行即時處理就可以取得BLE週邊的訊息,如果必需要將資料傳至BLE週邊時,再使用writeValue的Method將資料出,以上為BLE連線最基本使用方式就大致上完成。

didDiscoverCharacteristicsForService

由Apple提供的資料擷取某部分來了解架構,等下程式就是利用這架構去尋訪所有的CharacteristicsForService

每個Servic下都會有很多的Characteristics,Characteristics是提供資料傳遞的重點,它會有個UUID編號,再由這個編號去Bluetooth 官方查表得到是哪種資料格式,知道格式後就能去將資料解開並加以使用。

真正的例子:

//-----------start-----------
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{

    CBService *s = [peripheral.services objectAtIndex:(peripheral.services.count - 1)];
    NSLog(@"=========== Service UUID %s ===========\n",[self CBUUIDToString:service.UUID]);
    if (!error) {
        NSLog(@"=========== %d Characteristics of service ",service.characteristics.count);

        for(CBCharacteristic *c in service.characteristics){

            NSLog(@" %s \n",[ self CBUUIDToString:c.UUID]);
          //  CBService *s = [peripheral.services objectAtIndex:(peripheral.services.count - 1)];
            if(service.UUID == NULL || s.UUID == NULL) return; // zach ios6 added


            //Register notification
            if ([service.UUID isEqual:[CBUUID UUIDWithString:@"180D"]])

            {
                if ([c.UUID isEqual:[CBUUID UUIDWithString:@"2A37"]])
                {
                    [self notification:service.UUID characteristicUUID:c.UUID peripheral:peripheral on:YES];
                    NSLog(@"registered notification 2A37");
                }
                if ([c.UUID isEqual:[CBUUID UUIDWithString:@"2A38"]])
                {
                    [self notification:service.UUID characteristicUUID:c.UUID peripheral:peripheral on:YES];
                    NSLog(@"registered notification 2A38");
                }
                if ([c.UUID isEqual:[CBUUID UUIDWithString:@"2A39"]])
                {
                    [self notification:service.UUID characteristicUUID:c.UUID peripheral:peripheral on:YES];
                    NSLog(@"registered notification 2A39");
                }

            }

        }
        NSLog(@"=== Finished set notification ===\n");


    }
    else {
        NSLog(@"Characteristic discorvery unsuccessfull !\n");

    }
    if([self compareCBUUID:service.UUID UUID2:s.UUID]) {//利用此來確定整個流程都結束後才能設定通知
        [delegate didConnected:peripheral error:error];
        NSLog(@"=== Finished discovering characteristics ===\n");
        //全部服務都讀取完畢時才能使用!

    }

}

//------------end------------

上面 例子是以Heart Rate(180D)為主,

Heart Rate的規格來說,0x2A37可以得到心跳的數據,所以針對此項進行註冊通知,一旦有新的數據就會傳入新的數據資料並呼叫didUpdateValueForCharacteristicDelegate,來得到每次的心跳數據更新。

//-----------start-----------
 [(CBPeripheral *)p setNotifyValue:(BOOL) forCharacteristic:CBCharacteristic *)]

//------------end------------

將Characteristic的Point傳入並設定setNotifyValue:on就完成註冊通知,之後如果有更新資料時就會引發didUpdateValueForCharacteristic Delegate,再進行資料處理。

notification

在設定註冊通知過程有點繁雜,所以我自行撰寫一個Method為notification,它可以從Service UUID及Characteristic UUID來找到Service與Characteristic的Object Point:。

//-----------start-----------
-(void) notification:(CBUUID *) serviceUUID characteristicUUID:(CBUUID *)characteristicUUID peripheral:(CBPeripheral *)p on:(BOOL)on {

    CBService *service = [self getServiceFromUUID:serviceUUID p:p];
    if (!service) {
        if (p.UUID == NULL) return; // zach ios6 addedche
        NSLog(@"Could not find service with UUID on peripheral with UUID \n");
        return;
    }
    CBCharacteristic *characteristic = [self getCharacteristicFromUUID:characteristicUUID service:service];
    if (!characteristic) {
        if (p.UUID == NULL) return; // zach ios6 added
        NSLog(@"Could not find characteristic with UUID  on service with UUID  on peripheral with UUID\n");
        return;
    }
    [p setNotifyValue:on forCharacteristic:characteristic];

}


-(CBService *) getServiceFromUUID:(CBUUID *)UUID p:(CBPeripheral *)p {

    for (CBService* s in p.services){
        if ([self compareCBUUID:s.UUID UUID2:UUID]) return s;
    }
    return nil; //Service not found on this peripheral
}

-(CBCharacteristic *) getCharacteristicFromUUID:(CBUUID *)UUID service:(CBService*)service {

    for (CBCharacteristic* c in service.characteristics){
        if ([self compareCBUUID:c.UUID UUID2:UUID]) return c;
    }
    return nil; //Characteristic not found on this service
}
//------------end------------

使用時只需要將Service/Characteristic的UUID及得到週邊的Peripheral物件傳入,並設定是on(YES)或off(NO)就完成。

didUpdateValueForCharacteristic

didUpdateValueForCharacteristic在連線完成後對於數據資得的取得顯的非常重要,範例中有比對2個UUID為2A372A38

//-----------start-----------
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{

    if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"2A37"]])
    {
        if( (characteristic.value)  || !error )
        {

        }
    }

    if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"2A38"]])
    {
        //set refresh int
        uint8_t val = 1;
        NSData* valData = [NSData dataWithBytes:(void*)&val length:sizeof(val)];
        [peripheral writeValue:valData forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
    }

}

//------------end------------

針對這兩個UUID成立時在這個Delegate做對應處理的工作,範例中以2A38來解說一下:

當更新資料為2A38時,程式將直接寫入 1 ,為什麼寫入1呢?在下表中可以了解,1所代表的就是Chest

意思是告訴心跳感測器量測的位置是在胸部的部分。

注意

整個didUpdateValueForCharacteristic在處理時請注意資料格式的解釋,往往是因為格式解釋錯誤才會得到不正確的資料。

延伸閱讀

目前已經完成CoreBluetooth For Centeral系列文章,下面為文章的標題:

CoreBluetooth for Central (1) ~ (7)

這是講述CoreBluetooth For Central使用方式,整篇文章最後會完成Heart Rate Measurement連接Polar H7的例子結束Central的學習。

1.Bluetooth Low Energy(BLE)

2.BLE Status

3.Discover BLE Device

4.Connect BLE Device

5.ReConnect BLE Device

6.Explore Services from Device

7.Interact Data

8,Read RSSI

更新資訊

日期 內容
2015/01/27 增加延伸閱讀

  • 最近在研究藍牙技術,想要讓i device連接非i device,似乎只有MFi認證的裝置,或是jailbreak的裝置,才能順利連接。

    • Bluetooth Low Energy似乎是目前每個平台能共通的方式之一,有不理解之處可以提出來一起討論

  • Thomas Tseng

    您好,請問您藍芽設備,有可能像藍芽耳機訪問ios設備嗎?

    • 一般的BLE 需要由程式來自行搜尋BLE設備並自行用程式連接,無法使用內建的藍芽選項來與藍芽配對。

  • LacusCheng

    您好,請問一下ios是不是沒辦法抓到BLE的mac address,還是說peripheral 的 uuid 就是mac format過的值?

    • iOS的BLE週邊是以它提供的Peripheral的UUID為主當連線的依據,Android是以mac address來連線!

      • 王文聰

        不好意思可否問一下,那是否有辦法能在ios下取得BLE的mac address???

        • iOS有管制,所以無法得知mac address,只會得到UUID,且UUID是當下你這台iDevice所產生與MAC對應的UUID,同樣的BLE Device在每台iDevice產生的都不同

        • 王文聰

          因為我看其他的專案,有使用kCBAdvDataManufacturerData這個key取得mac address,是否要ble device端做開放才能取得??

          • 對,沒提供的話就是空資料

  • 江鈞

    請問您是否有過斷線的情形

    我用iphone 4 測試程式 回在收到大約3~4次數值後 斷線

    • 藍牙如果有多重連接時可能會不穩定(ex:已連藍牙機聽音樂),有時WiFi開啟時也會造成不穩定情況,我BLE應該是iphone 4s後才有喔?

      • 江鈞

        謝謝你的回覆 我是不清楚機型 不過我想那應該就是4s(都還收得到UUID) 我關WIFI在做測試

  • Timman

    請問如果先在 iOS 設定 -> 藍芽 ..裡面把 BLE 裝置連線上 APP有辦法取得 iOS 目前已經連上的裝置 然後去收送資料嗎?? 主要是希望可以使用 iOS 配對 and Bonding後才在APP內取得此連線做溝通

    • 於iOS設定上配對成功時只是告知週邊與iOS上間的配對已經功成並無連線關系,有些週邊會利用是否有配點去管控Characteristic的權限,連線還是必需要利用手動的方式連線,這是目前我知道的訊息供您參考。

      • Timman

        謝謝回覆..那如果是在設定 -> 藍芽 手動連線上裝置後 打開 自有的 APP , 有辦法可以取得目前本機連線的 BLE 裝置嗎 因為目前看起來都要先 APP 內 SCAN 然後 APP 內 Connect 之後 APP 取到 peripheral 再去做讀寫

        • 如果知道周邊在iOS上產生的UUID是不需要透過SCAN就能嘗試直接連線取得peripheral再進行讀寫的!否則還是需要經過SCAN的方式得知iOS Device身邊有哪些BLE供連線

          • 基本上BLE + 配對可能不是你所了解如此,根據我測試結果,第一次iOS需要跟BLE連線後再看其中屬性找到需要配點的Characteristic,此時系統會自帶配對的Dialog後請你輸入配對密碼,如果正確,週邊會自行記憶此訊息,並且App要自行記錄與管理連線UUID,下次直接連線時就不需要再配點,但會在"iOS設定"上看到配點過的週邊名稱,有錯誤請指正討論^^

          • Timman

            你好, 我目前實測過了..第一次連線時..會出現配對視窗, 配對好後.. 設定->藍芽 裡面會有連線中的裝置 之後 APP 斷線, 也將 UUID 儲存下來了,… 但是下次device開啟時, iOS 後端會直接連線 (設定 -> 藍芽裡面)

            此時.. APP 內..無法 scan , 也無法直接 connect, 我儲存的 UUID 變成不知道該怎麼去存取device 請問此時我該怎麼去透過已經儲存下來的 UUID 以及 iOS 已經自動連線的情況下去對 Device 做存取呢?

          • 你這個Case跟我所了解的不太一樣,目前無法給你好的建議,能確定它是BLE的裝置嗎?也有可能是MFi的Bluetooth喔!還是您能提供是什麼樣的設備我研究一下它的資訊

          • Timman

            呵呵, 確定是 BLE 裝置, 因為是自己公司做的 BLE Device 目前就是卡在 第一次配對後, 之後 iOS 在背景後端會直接連上 BLE Device 但是 APP 就不知道該怎麼去跟 iOS 要來存取了

          • 目前我實驗結果得知的結論是: BLE具有配對模式功能時會在iOS上的設定-藍牙上能被搜尋並且進行配對,但配對後你具備的GATT並非iOS預設,即時連線後也不會有功能,所以這朝這方向配對目前還找不到參考資料可以取得已連線的BLE Peripheral直接給APP使用。 APP可能做法為: APP->Scan->Connect-(具配對功能BLE Device,iOS會自動跳出配對對話框,配對成功能連線會成功,失敗大部分都會斷線)->Read/Write……. 以上供您參考.

          • Timman

            感謝回覆耶~~

            有稍微實驗過, 有找到方法了

            如果是第一次連線, 可以按照你的方法去實現, 但是如果APP關掉後, iOS會持續連接BLE Device

            此時開啟APP就不能 Scan -> Connect 了, 因為 Scan 也沒辦法找到東西.. (被 iOS 連接中)

            必須取得跟 iOS 連線中的 Peripheral 給 APP 使用..

            目前已經成功取到, 也可以正常拿來 Read/Write 了… ( K 了很久的 API , 慢慢嘗試 =.=)

            也很謝謝您的幫忙跟這幾篇文章, 從完全不懂開始就慢慢懂了.. THX

          • 可否分享一下是如何取到的呢?

          • Timman

            當然沒問題的嚕!!!!在這邊也得到不少幫助

            進入 APP 後 利用 CBCentralManager 裡面的 retrieveConnectedPeripheralsWithServices

            就可以取到透過 iOS or 其他方式連接的 BLE Device 的 CBPeripheral Array

            如果沒有任何連線 Array 當然就抓到 0 嚕

            此方法是使用 Service 去抓, 如果不知道 Service 的話, 就沒輒啦, 通常應該會知道啦

            如果有相同 Service 的 Device , CBPeripheral 抓回來後, 可以透過比對 UUID or NAME 去區分

            然後取用這個 CBPeripheral 就可以 Read/Write 了

            如果有不詳細的地方再告知一下嚕, 大家一起加油~~~

          • 你也真的太厲害了,這要一個一個API看完才會發現,謝謝提供這麼重要的訊息!iOS考慮的這麼周詳,連這也考慮到了,不過這樣APP就要做多重判斷來連接BLE Device吧?

          • Timman

            沒有很厲害啦, 只是覺得不太可能是 iOS 不給用 (終究 BLE 都開放了)

            所以只好進去 API 一個一個看說明..找比較有可能的 function 一個一個去試試看

            其實.. APP 也沒有很複雜的判斷..在自己要去連接 BLE 前面加入一小段 Code 而已

            大概像下面這樣而已, 詳細的 code 就是依照每個人專案不同去寫嚕

            //==================== if([array count] > 0 ) //這樣就是 iOS 端有連線的裝置 { for(NSUUID *tmp in array) { UUID 有自己要的直接拿來取用的 functon

                return;
            }`
            

            }

            原本自己主動去連 BLE 的 Function //=====================

            大家一起努力加油

          • 感謝你提供的訊息交換,這次非常有心得,往後我會再補上這個方式的連接讓篇幅完整,方便透露是什麼樣的BLE產品嗎?產品開賣別忘了回來通知我

          • Timman

            哈..我們不是做攜帶型產品唷..所以不是手錶, 等等之類的攜帶式裝置

            我們是將 BLE 加裝在原本安全系統內, 多添增一個管道去用 APP 跟 Product 溝通並控制 :D

          • 安全系統有支援BLE也很不錯啊!之前我還想自已弄一個BLE 的switch去當開關,你們BLE那端的firmware是自已寫嗎?

          • Timman

            是的, FW 也是自己寫, 所以靈活度比較高, 中間的協定也都自己定義..

            只是差在.. iOS 靈活度終究沒有 Android 高 >_<… 所以才有點困擾

            不過慢慢都找到方法解決了…也算一個練習啦 ..

          • android那邊你有測過連線時突然間把ble device那段電源斷線後,android回報disconnect比ios慢的問題嗎?我這測的反應android都大約5~8秒,iOS很快就斷了

          • Timman

            哈~我們不適用 TI 的, 我們使用 AMICCOM 的, 目前測試起來, iOS 滿平均的 Android 有部分手機 ok , 部分手機比 iOS 慢一些, 實際幾秒沒有測試過 所以可以試試看多拿幾隻 Android 試試看 , 我們是把全公司不同的 Android 都試一次了

          • 通常它寫"連線中"就已經被連線,scan會關閉,所以目前無解,是不是您公司的BLE device GATT符合apple health app中的的類似心跳之類的,如果有在之中選擇它的"來源"就有可能自動連線

  • LacusCheng

    請問~~有沒有辦法在APP中知道已經配對的裝置

    • 利用CBCentralManager 裡面的 retrieveConnectedPeripheralsWithServices,以Service的UUID方式去找已經配對好的裝置,細節可以參考下面Timman與我討論的內容。

      • LacusCheng

        有看了,所以目前也只能透過UUID的方式找已經配對好的裝置嗎? 因為目前的需求是想要把以配對的都列出來選擇要使用的裝置

        • 目前能配點的BLE裝置都是能符合Health Kit的Service UUID,像:180D(心跳)、1808(血糖)…這些,所以你可以試著利用這些uuid來列舉所有已配對好的裝置,主要是利用後這取得peripheral就能知道裝置名稱

          • LacusCheng

            我有成功的找到了已配對且連線的裝置,但app卻無法跟他connect和discoverService。在設定裡面看裝置是連線狀態

          • 取得到"peripheral"就能直接用,因為它本身已經連線

          • 下面有個圖您參考一下。

  • Pingback: iOS 藍牙 BLE 初探 | Pearltrees()