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的使用過程,其中:
- 一個應(yīng)用運行在模擬器中作為廣播節(jié)點仅仆,
- 另一個運行在iPhone真機上作為發(fā)現(xiàn)節(jié)點器赞,并且實現(xiàn)兩個節(jié)點的圖片互傳。
效果展示(同一個分代碼墓拜,同一個UI界面):
SB中的界面搭建:
代碼:
<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ù)再補充