iOS-藍牙開發(fā)

iOS個版本藍牙比較

隨著藍牙低功耗技術(shù)BLE(Bluetooth Low Energy)的發(fā)展,藍牙技術(shù)正在一步步成熟笛匙,如今的大部分移動設(shè)備都配備有藍牙4.0欣喧,相比之前的藍牙技術(shù)耗電量大大降低歹撒。從iOS的發(fā)展史也不難看出蘋果目前對藍牙技術(shù)也是越來越關(guān)注,例如蘋果于2013年9月發(fā)布的iOS7就配備了iBeacon技術(shù)看疗,這項技術(shù)完全基于藍牙傳輸沙峻。但是眾所周知蘋果的設(shè)備對于權(quán)限要求也是比較高的,因此在iOS中并不能像Android一樣隨意使用藍牙進行文件傳輸(除非你已經(jīng)越獄)两芳。在iOS中進行藍牙傳輸應(yīng)用開發(fā)常用的框架有如下幾種:

- GameKit.framework:iOS7之前的藍牙通訊框架摔寨,從iOS7開始過期,但是目前多數(shù)應(yīng)用還是基于此框架怖辆。
- MultipeerConnectivity.framework:iOS7開始引入的新的藍牙通訊開發(fā)框架是复,用于取代GameKit。
- CoreBluetooth.framework:功能強大的藍牙開發(fā)框架竖螃,要求設(shè)備必須支持藍牙4.0淑廊。

前兩個框架使用起來比較簡單,但是缺點也比較明顯:僅僅支持iOS設(shè)備特咆,傳輸內(nèi)容僅限于沙盒或者照片庫中用戶選擇的文件季惩,并且第一個框架只能在同一個應(yīng)用之間進行傳輸(一個iOS設(shè)備安裝應(yīng)用A,另一個iOS設(shè)備上安裝應(yīng)用B是無法傳輸?shù)模.?dāng)然CoreBluetooth就擺脫了這些束縛画拾,它不再局限于iOS設(shè)備之間進行傳輸啥繁,你可以通過iOS設(shè)備向Android、Windows Phone以及其他安裝有藍牙4.0芯片的智能設(shè)備傳輸青抛,因此也是目前智能家居旗闽、無線支付等熱門智能設(shè)備所推崇的技術(shù)。

對比

框架 版本 運用
GameKit.framework 僅支持iOS設(shè)備(iOS7之后淘汰) 同一游戲應(yīng)用相關(guān)
MultipeerConnectivity.framework 僅支持iOS設(shè)備(替代GameKit) 不同應(yīng)用之間
CoreBluetooth.framework 支持第三方外設(shè)(藍牙4.0以上) 不同應(yīng)用之間

GameKit

目前因為GameKit已經(jīng)淘汰過時脂凶,那么就不在詳細寫這個框架宪睹,網(wǎng)上也有相關(guān)的講解愁茁,有興趣就可以去了解了解蚕钦,看看別人寫的代碼。

MultipeerConnectivity

MultipeerConnectivity并不僅僅支持藍牙連接鹅很,準確的說它是一種支持Wi-Fi網(wǎng)絡(luò)嘶居、P2P Wi-Fi已經(jīng)藍牙個人局域網(wǎng)的通信框架,它屏蔽了具體的連接技術(shù)促煮,讓開發(fā)人員有統(tǒng)一的接口編程方法邮屁。通過MultipeerConnectivity連接的節(jié)點之間可以安全的傳遞信息、流或者其他文件資源而不必通過網(wǎng)絡(luò)服務(wù)菠齿。此外使用MultipeerConnectivity進行近場通信也不再局限于同一個應(yīng)用之間傳輸佑吝,而是可以在不同的應(yīng)用之間進行數(shù)據(jù)傳輸(當(dāng)然如果有必要的話你仍然可以選擇在一個應(yīng)用程序之間傳輸)。
要了解MultipeerConnectivity的使用必須要清楚一個概念:廣播(Advertisting)和發(fā)現(xiàn)(Disconvering)绳匀,這很類似于一種Client-Server模式芋忿。假設(shè)有兩臺設(shè)備A、B疾棵,B作為廣播去發(fā)送自身服務(wù)戈钢,A作為發(fā)現(xiàn)的客戶端。一旦A發(fā)現(xiàn)了B就試圖建立連接是尔,經(jīng)過B同意二者建立連接就可以相互發(fā)送數(shù)據(jù)殉了。在使用GameKit框架時,A和B既作為廣播又作為發(fā)現(xiàn)拟枚,當(dāng)然這種情況在MultipeerConnectivity中也很常見薪铜。

  • A.廣播

無論是作為服務(wù)器端去廣播還是作為客戶端去發(fā)現(xiàn)廣播服務(wù),那么兩個(或更多)不同的設(shè)備之間必須要有區(qū)分恩溅,通常情況下使用MCPeerID對象來區(qū)分一臺設(shè)備痕囱,在這個設(shè)備中可以指定顯示給對方查看的名稱(display name)。另外不管是哪一方暴匠,還必須建立一個會話MCSession用于發(fā)送和接受數(shù)據(jù)鞍恢。通常情況下會在會話的-(void)session:(MCSession )session peer:(MCPeerID )peerID didChangeState:(MCSessionState)state代理方法中跟蹤會話狀態(tài)(已連接、正在連接、未連接);在會話的-(void)session:(MCSession )session didReceiveData:(NSData )data fromPeer:(MCPeerID )peerID代理方法中接收數(shù)據(jù);同時還會調(diào)用會話的-(void)sendData: toPeers:withMode: error:*方法去發(fā)送數(shù)據(jù)帮掉。廣播作為一個服務(wù)器去發(fā)布自身服務(wù)弦悉,供周邊設(shè)備發(fā)現(xiàn)連接。在MultipeerConnectivity中使用MCAdvertiserAssistant來表示一個廣播蟆炊,通常創(chuàng)建廣播時指定一個會話MCSession對象將廣播服務(wù)和會話關(guān)聯(lián)起來稽莉。一旦調(diào)用廣播的start方法周邊的設(shè)備就可以發(fā)現(xiàn)該廣播并可以連接到此服務(wù)。在MCSession的代理方法中可以隨時更新連接狀態(tài)涩搓,一旦建立了連接之后就可以通過MCSession的connectedPeers獲得已經(jīng)連接的設(shè)備污秆。

  • B.發(fā)現(xiàn)

前面已經(jīng)說過作為發(fā)現(xiàn)的客戶端同樣需要一個MCPeerID來標志一個客戶端,同時會擁有一個MCSession來監(jiān)聽連接狀態(tài)并發(fā)送昧甘、接受數(shù)據(jù)良拼。除此之外,要發(fā)現(xiàn)廣播服務(wù)充边,客戶端就必須要隨時查找服務(wù)來連接庸推,在MultipeerConnectivity中提供了一個控制器MCBrowserViewController來展示可連接和已連接的設(shè)備(這類似于GameKit中的GKPeerPickerController),當(dāng)然如果想要自己定制一個界面來展示設(shè)備連接的情況你可以選擇自己開發(fā)一套UI界面浇冰。一旦通過MCBroserViewController選擇一個節(jié)點去連接贬媒,那么作為廣播的節(jié)點就會收到通知,詢問用戶是否允許連接肘习。由于初始化MCBrowserViewController的過程已經(jīng)指定了會話MCSession际乘,所以連接過程中會隨時更新會話狀態(tài),一旦建立了連接漂佩,就可以通過會話的connected屬性獲得已連接設(shè)備并且可以使用會話發(fā)送脖含、接受數(shù)據(jù)

下面用兩個不同的應(yīng)用程序來演示使用MultipeerConnectivity的使用過程,其中:

  1. 一個應(yīng)用運行在模擬器中作為廣播節(jié)點仅仆,
  2. 另一個運行在iPhone真機上作為發(fā)現(xiàn)節(jié)點器赞,并且實現(xiàn)兩個節(jié)點的圖片互傳。

效果展示(同一個分代碼墓拜,同一個UI界面):


運行結(jié)果.png

SB中的界面搭建:


XIB界面搭建.png

代碼:
<pre ><code>

// ViewController.swift
// 藍牙數(shù)據(jù)傳輸(MultipeerConnectivity)
// Created by 禮光 on 2016/11/2.

// Copyright ? 2016年 LLG. All rights reserved.

import UIKit

import MultipeerConnectivity

//需要用到的內(nèi)容是:

//1.創(chuàng)建設(shè)備ID.發(fā)現(xiàn)的名字

//2.會話對象

//3.廣播助理

//4.代理方法(狀態(tài)管理,發(fā)送接收消息)

//服務(wù)類型隨便取
let serviceType = "LLG"

class ViewController: UIViewController {

    //控件屬性
    @IBOutlet weak var stateLabel: UILabel!
    @IBOutlet weak var isFound: UISwitch!
    @IBOutlet weak var photo: UIImageView!
    @IBOutlet weak var isConnect: UIButton!

    //自定義屬性
    lazy var session : MCSession = {
        let peerID = MCPeerID(displayName: UIDevice.current.name)//使用當(dāng)前設(shè)備的名稱
        let session = MCSession(peer: peerID)
        session.delegate = self
        return session
    }()

    var advertiserAssistant : MCAdvertiserAssistant!

    lazy var matchPeerIDs : NSMutableArray = {
        let matchPeerIDs = NSMutableArray.init(array: [])
        return matchPeerIDs;
    }()


    override func viewDidLoad() {
        super.viewDidLoad()
        self.isFound.isOn = false//初始化不能被發(fā)現(xiàn)
        self.stateLabel.text = "匹配狀態(tài): 未連接"
        self.isConnect.isEnabled = false
        self.isConnect.backgroundColor = UIColor.gray
        self.isConnect.setTitle("未連接成功", for: .normal)
    }


    @IBAction func switchToBeFound(_ sender: UISwitch) {
    //創(chuàng)建一個廣播助手
    self.advertiserAssistant = MCAdvertiserAssistant(serviceType: serviceType, discoveryInfo: nil, session: self.session)
  
    switch sender.isOn {
        case true:
            //"可被發(fā)現(xiàn)"
            print("可被發(fā)現(xiàn)")
            self.advertiserAssistant.start()
        default:
            //"不可被發(fā)現(xiàn)"
            print("不可被發(fā)現(xiàn)")
            self.advertiserAssistant.stop()
        }
    }


    @IBAction func searchDevice(_ sender: UIButton) {
        //創(chuàng)建一個藍牙發(fā)現(xiàn)彈出頁面,用于選擇連接的設(shè)備
        let browserVc = MCBrowserViewController(serviceType: serviceType, session: self.session)
        browserVc.delegate = self;
        self.present(browserVc, animated: true, completion: nil)
    }



    @IBAction func sendData(_ sender: UIButton) {
        let data = UIImagePNGRepresentation(UIImage(named: "01")!)
        //發(fā)送數(shù)據(jù)給已經(jīng)連接的所有藍牙設(shè)備,以不可靠的方式
        try?self.session.send(data!, toPeers: self.session.connectedPeers, with: .unreliable)
    }
}

//MARK: - MCBrowserViewController代理

extension ViewController : MCBrowserViewControllerDelegate {
//點擊完成

    func browserViewControllerDidFinish(_ browserViewController: MCBrowserViewController) {
        self.dismiss(animated: true, completion: nil)
    }
    //點擊取消
    func browserViewControllerWasCancelled(_ browserViewController: MCBrowserViewController) {
        self.dismiss(animated: true, completion: nil)
    }

}

//MARK: - MCSession代理

extension ViewController : MCSessionDelegate {

//監(jiān)聽數(shù)據(jù)傳輸

    func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
        let image = UIImage(data: data)
        DispatchQueue.main.async {
        self.photo.image = image
        }
    }
    //監(jiān)聽連接狀態(tài)
    func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) {
        switch state {
        case .connected:
            //回到主線程刷新界面
            DispatchQueue.main.async(execute: {
                self.stateLabel.text = "匹配狀態(tài): 已連接設(shè)備\(peerID.displayName)"
                self.isConnect.isEnabled = true
                self.isConnect.backgroundColor = UIColor.red
                self.isConnect.setTitle("傳輸數(shù)據(jù)", for: .normal)
            })
        case .connecting:
            //回到主線程刷新界面
            DispatchQueue.main.async(execute: {
                self.stateLabel.text = "匹配狀態(tài): 連接中..."
            })
        default:
            DispatchQueue.main.async(execute: {
                self.stateLabel.text = "匹配狀態(tài): 連接失敗"
            })
        }
    
    }

//用不到港柜,代理空實現(xiàn)
    func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) {
    }
    func session(_ session: MCSession, didStartReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, with progress: Progress) {
    }
    func session(_ session: MCSession, didFinishReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, at localURL: URL, withError error: Error?) {
    }

}</code></pre>

<pre><code>
ahdiuiqhwudbqwiuiuqwbsjdhvfajfhaskdhfasidhfisadhfjashdfkshdjkfhsjkdfhaksjdhfkaljshdfklasjhdfiueoiruweoriuweoirkjsdalksjdlkasjdio wqeajdhjasdhiehr iuhdksajd qidoiq dasd
qwdhashdoi dq dakjsdn qw
</code></pre>

這個使用markdown來編輯的的代碼效果實在是太惡心了,后續(xù)再補充

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市咳榜,隨后出現(xiàn)的幾起案子夏醉,更是在濱河造成了極大的恐慌,老刑警劉巖涌韩,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件畔柔,死亡現(xiàn)場離奇詭異,居然都是意外死亡臣樱,警方通過查閱死者的電腦和手機靶擦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門腮考,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人玄捕,你說我怎么就攤上這事踩蔚。” “怎么了枚粘?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵馅闽,是天一觀的道長。 經(jīng)常有香客問我馍迄,道長福也,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任攀圈,我火速辦了婚禮暴凑,結(jié)果婚禮上叫挟,老公的妹妹穿的比我還像新娘貌虾。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布撕捍。 她就那樣靜靜地躺著,像睡著了一般泣洞。 火紅的嫁衣襯著肌膚如雪忧风。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天球凰,我揣著相機與錄音狮腿,去河邊找鬼。 笑死呕诉,一個胖子當(dāng)著我的面吹牛缘厢,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播甩挫,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼贴硫,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了伊者?” 一聲冷哼從身側(cè)響起英遭,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎亦渗,沒想到半個月后挖诸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡法精,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年多律,在試婚紗的時候發(fā)現(xiàn)自己被綠了痴突。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡狼荞,死狀恐怖苞也,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情粘秆,我是刑警寧澤如迟,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站攻走,受9級特大地震影響殷勘,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜昔搂,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一玲销、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧摘符,春花似錦贤斜、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至带族,卻和暖如春锁荔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蝙砌。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工阳堕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人择克。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓恬总,卻偏偏與公主長得像,于是被迫代替她去往敵國和親肚邢。 傳聞我的和親對象是個殘疾皇子壹堰,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容