藍牙(Bluetooth)

  • 整理大神班視頻

一、GameKit

簡介:

  • 實現藍牙設備之間的通訊
  • 只能使用在iOS設備之間同一個應用內連接
  • iOS7開始過期了
  • 但是GameKit是最基本的藍牙通訊框架
  • 通過藍牙可以實現文件的共享(僅限設備沙盒中的文件)
  • 此框架一般用於遊戲開發(比如五子棋對戰)

過程:

  • 使用藍牙將兩個iOS設備連接起來
  • 搜索對方的設備
  • 實現將手機中的圖片發送給對方

藍牙互連:

    // 初始化鏈接藍牙控制器
    GKPeerPickerController *peerCtr = [[GKPeerPickerController alloc]init];
    // 顯示匹配到的藍牙設備
    [peerCtr show];

* GKPeerPickerController代理

/*
 * 連接藍牙的方式    附近    在線
 */
- (void)peerPickerController:(GKPeerPickerController *)picker didSelectConnectionType:(GKPeerPickerConnectionType)type {
}

// 連接會話的方式   附近  在線
- (GKSession *)peerPickerController:(GKPeerPickerController *)picker sessionForConnectionType:(GKPeerPickerConnectionType)type {

    return nil;
}

/* 連接成功
 *  peerID  連接成功的設備id
 *  session  當前回話  只需要保存當前的會話  即 可 數據傳遞
 */
- (void)peerPickerController:(GKPeerPickerController *)picker didConnectPeer:(NSString *)peerID toSession:(GKSession *)session {

    // 隱藏選擇器
    [picker dismiss];

    // 接收數據的回調  GameKIt  必須實現的
    [session setDataReceiveHandler:self withContext:nil];

    // 保存會話
    self.session = session;
}

/*
 *  退出
 */
- (void)peerPickerControllerDidCancel:(GKPeerPickerController *)picker
{ 
}
// 只要有數據回來  那麼就會調用
- (void) receiveData:(NSData *)data fromPeer:(NSString *)peer inSession: (GKSession *)session context:(void *)context
{
}

圖片相互發送:

// 發送圖片
- (IBAction)sendImage {

    // 拿到需要發送出去的圖片
    UIImage *image = self.showImageView.image;
    // 將圖片轉換成NSData類型
    NSData *imgData = UIImagePNGRepresentation(image);

    /**
     *  發送數據給所有匹配上的用戶
     *
     *  @param GKSendDataMode 數據發送的模式:(安全/不安全模式)
     *                        GKSendDataUnreliable : 不安全模式:就像發10個傳單,傳單直接往人羣中砸過去,能不能收到不管
     *                        GKSendDataReliable:安全模式:就像發10個傳單,每一個傳單都得發到路人的手上,纔再發下一個傳單
     *  @return
     */
    [self.m_Session sendDataToAllPeers:imgData withDataMode:GKSendDataUnreliable error:nil];
}

設置圖片:

* GameKit提供的接受數據是方法的回調

* 需要監聽接收傳遞過來的數據

* 在連接成功代理方法中設置監聽

    // 若執行下面方法,必須設置
    // 接收數據的回調  GameKIt  必須實現的
    // [session setDataReceiveHandler:self withContext:nil];
        /** 監聽傳遞過來的數據
         *  setDataReceiveHandler: 由哪個對象來監聽數據的接受
         *  withContext : 監聽需要傳遞的參數
         */
      [session setDataReceiveHandler:self withContext:nil];
/** 實現監聽方法
 * 只設置由誰監聽傳遞過來的數據還是不足的,
 * 因爲我們還是不能拿到傳遞過來的數據,進入監聽方法的頭文件可以看到
 *  SEL = -receiveData:fromPeer:inSession:context:
 * 所以我們必須實現這個方法才能拿到接收到的數據,這個回調方法方法
 */

/**
 *  實現接收數據的回調方法
 *
 *  @param data    接收到的數據
 *  @param peer    傳遞數據的設備ID
 *  @param session 當前回話
 *  @param context 註冊監聽傳遞過來的數據
 */
- (void) receiveData:(NSData *)data fromPeer:(NSString *)peer inSession: (GKSession *)session context:(void *)context
{
}

二、mutipeerConnectivity

簡介

  • iOS 7引入的一個全新框架
  • 多點連接
  • 替代GameKit框架
  • 多用於文件的傳輸

* iOS設備不聯網也能跟附近的人聊天

* FireChat
* See You Around
* 以上近場聊天App都是基於mutipeerConnectivity框架

* 搜索和傳輸的方式

* 雙方WIFI和藍牙都沒有打開:無法實現
* 雙方都開啓藍牙:通過藍牙發現和傳輸
* 雙方都開啓WIFI:通過WIFI Direct發現和傳輸,速度接近AirDrop
* 雙方同時開啓了WIFI和藍牙:模擬AirDrop,通過低功耗藍牙技術掃描發現握手,然後通過WIFI Direct傳輸 

連接設備

  • 創建MCSession對象用於存放當前連接的會話
// 創建MCSession對象
// initWithPeer:設備的ID
// 用於存放當前的連接的會話
self.mc_Session = [ [MCSession alloc]initWithPeer:[[MCPeerID alloc] initWithDisplayName:[UIDevice currentDevice].name]];
  • 開啓廣播對象,通知正在搜索的設備他們是可用的
// 廣播對象,告訴其它的設備他們是可用的
// 創建廣播對象
//  initWithServiceType: 廣播類型的標示(因爲廣播可能比較多,所以最好每個廣播綁定一個唯一標示)(自定義字符串,類似cell的註冊ID)
//  session:當前會話
//  discoveryInfo: 廣播信息
MCAdvertiserAssistant   *advertiserAssistant =[[MCAdvertiserAssistant alloc] initWithServiceType:SERVICE_TYPE discoveryInfo:nil session:self.mc_Session];
        }
        // 開啓廣播
        [self.advertiserAssistant start];
  • 開始搜索藍牙設備
    // 創建搜索藍牙設備控制器
    MCBrowserViewController *mbVC = [[MCBrowserViewController alloc]initWithServiceType:SERVICE_TYPE session:self.mc_Session];
    // 設置控制器代理
    mbVC.delegate = self;
    // 跳轉到搜索控制器
    [self presentViewController:mbVC animated:YES completion:nil];

選擇數據

  • 在搜索控制器的連接完成的代理方法中隱藏搜索控制器
/**
 *  連接完成
 *
 *  @param browserViewController 搜索控制器
 */
- (void)browserViewControllerDidFinish:(MCBrowserViewController *)browserViewController
{
    [browserViewController dismissViewControllerAnimated:YES completion:nil];
}

發送數據

  • 實現搜索控制器的代理方法,獲取連接上的設備ID
#pragma mark - MCBrowserViewControllerDelegate
/**
 *  連接成功
 *
 *  @param browserViewController 搜索控制器
 *  @param peerID                連接上的設備ID
 *  @param info                  連接的信息
 *
 *  @return                      YES : 只發送連接上的用戶
 */
- (BOOL)browserViewController:(MCBrowserViewController *)browserViewController
      shouldPresentNearbyPeer:(MCPeerID *)peerID
            withDiscoveryInfo:(nullable NSDictionary<NSString *, NSString *> *)info
{
    self.peerID = peerID;
    NSLog(@"info == %@   peer = %@",info, peerID);
    return YES;
}
  • 將圖片發送給連接上的ID
    // 獲取圖片
    UIImage *image = self.showImage.image;
    // 將圖片轉換成NSData類型
    NSData *data = UIImagePNGRepresentation(image);
    /**
     *  發送數據
     *  toPeers : 發給的設備ID的數組
     *  withMode: 發送模式,是否是安全模式
     */
    if (self.peerID != nil) {
        [self.mc_Session sendData:data toPeers:@[self.peerID] withMode:MCSessionSendDataUnreliable error:nil];
    }
}

接收數據

  • 實現MCSession的代理方法接受數據
  • 在MCSeesion代理方法中設置獲取過來的數據
// 接收的數據
- (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID
{
    UIImage *image = [[UIImage alloc]initWithData:data];
    if(image != nil){
        // 設置數據
        dispatch_async(dispatch_get_main_queue(), ^{
            self.showImage.image = image;
        });
    }
}

三、CoreBlueTooth

簡介:

  • 可用於第三方藍牙設備交互,設備必須支持藍牙4.0
  • iPhone的設備必須是4S或者更新
  • iPad設備必須是iPad mini或者更新
  • iOS的系統必須是iOS 6或者更新
  • 藍牙4.0以低功耗著稱,所以一般被稱爲BLE(bluetooth low energy)
  • 應用場景
    • 運動手環
    • 智能家居
    • 拉卡拉藍牙刷卡器

核心概念

  • CBCentralManager:中心設備(用來連接到外部設備的管家)
  • CBPeripheralManager:外部設備(第三方的藍牙4.0設備)

開發步驟

  • 建立中心管家
// 1. 創建中心管家,並且設置代理
self.cmgr = [[CBCentralManager alloc]initWithDelegate:self queue:nil];
  • 掃描外設(discover)
// 2. 在代理方法中掃描外部設備
 /**
  *  scanForPeripheralsWithServices :如果傳入指定的數組,那麼就只會掃描數組中對應ID的設備
  *                                   如果傳入nil,那麼就是掃描所有可以發現的設備
  *  掃描完外部設備就會通知CBCentralManager的代理
  */
 - (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
    if ([central state] == CBCentralManagerStatePoweredOn) {
        [self.cmgr scanForPeripheralsWithServices:nil options:nil];
    }
}
/**
 *  發現外部設備,每發現一個就會調用這個方法
 *  所以可以使用一個數組來存儲每次掃描完成的數組
 */
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI
{
    // 有可能會導致重複添加掃描到的外設
    // 所以需要先判斷數組中是否包含這個外設
    if(![self.peripherals containsObject:peripheral]){
        [self.peripherals addObject:peripheral];
    }
}
  • 連接外設
/**
 *  模擬開始連接方法
 */
- (void)start
{
    // 3. 連接外設
    for (CBPeripheral *ppl in self.peripherals) {
        // 掃描外設的服務
        // 這個操作應該交給外設的代理方法來做
        // 設置代理
        ppl.delegate = self;
        [self.cmgr connectPeripheral:ppl options:nil];
    }
}
  • 掃描外設中的服務和特徵
  • 服務和特徵的關係

每個藍牙4.0的設備都是通過服務和特徵來展示自己的,一個設備必然包含一個或多個服務,每個服務下面又包含若干個特徵。

/**
 *  連接外設成功調用
 */
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
    // 查找外設服務
    [peripheral discoverServices:nil];
}
/**
 *  發現服務就會調用代理方法
 *
 *  @param peripheral 外設
 */
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{
    // 掃描到設備的所有服務
    NSArray *services = peripheral.services;
    // 根據服務再次掃描每個服務對應的特徵
    for (CBService *ses in services) {
        [peripheral discoverCharacteristics:nil forService:ses];
    }
}
  • 與外設做數據交互
  • 在指定的特徵下做相應的操作
/**
 *  發現服務對應的特徵
 */
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
{
    // 服務對應的特徵
    NSArray *ctcs = service.characteristics;
    // 遍歷所有的特徵
    for (CBCharacteristic *character in ctcs) {
        // 根據特徵的唯一標示過濾
        if ([character.UUID.UUIDString isEqualToString:@"XMG"]) {
            NSLog(@"可以吃飯了");
        }
    }
}
  • 斷開連接
/**
 *  斷開連接
 */
- (void)stop
{
    // 斷開所有連接上的外設
    for (CBPeripheral *per in self.peripherals) {
        [self.cmgr cancelPeripheralConnection:per];
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章