1.先拉一個 UIViewController 並用 NavigationController embed 起來,在 Navigation Bar 上面加個 title 和 UIBarButtonItem,這邊是選擇 Refresh 的 System Item 樣式,並且在剩下的範圍加上一個 UITableview 當作掃描後顯示藍芽裝置的列表
- 2.製作一個客製化的 UITableviewCell 讓掃描結束後可以顯示資訊
- Name:藍芽裝置的名稱,通常是我們是可以知道的
- RSSI:藍芽裝置的訊號強度,這個執事參考值,會受到周遭的環境影響
- UUID:藍芽裝置的唯一 ID
- Connectable:該藍芽裝置是否可以被連線
- Distance:目前與該藍芽裝置的距離,這個值是用 RSSI 算出來的,但是因為 RSSI 的環境參數常常都不同,所以只能當參考。( 個人試過有時候會差很多,網上參考資源很多這邊也不對轉換公式做贅述 )
- 簡單的 UITableviewCell
好啦真的有點醜,不過測試用就別計較啦
3.東西準備好了那要來掃描了,首先這邊使用 CoreBlueTooth 這個函式庫。要進行所有藍芽工作時,都要從一個 CBCentralManager 物件來開始動作。方法很簡單,在 UIViewcontroller 中建立一個全域物件,並且在會執行到的地方來初始化他
var myCenteralManager: CBCentralManager? = nil
override func viewWillAppear(animated: Bool) {
myCenteralManager = CBCentralManager(delegate: self, queue: nil)
}
這邊會發現他的 delegate 放的是 self,也就是 UIViewController
的實體,所以我們的 UIViewController
需要實作 CBCentralManagerDelegate
的委派,其實就是要實作 centralManagerDidUpdateState
這個方法啦~
在這個方法中會隨時監聽 iOS 裝置的藍芽狀態,只要有改變就會進行 callback 的動作,其中動作有分 5 項,這邊就通通 print 出來就好
func centralManagerDidUpdateState(central: CBCentralManager) {
switch central.state {
case CBCentralManagerState.PoweredOn:
print("BT ON")
case CBCentralManagerState.PoweredOff:
print("BT OFF")
case CBCentralManagerState.Resetting:
print("BT RESSTING")
case CBCentralManagerState.Unknown:
print("BT UNKNOW")
case CBCentralManagerState.Unauthorized:
print("BT UNAUTHORIZED")
case CBCentralManagerState.Unsupported:
print("BT UNSUPPORTED")
}
}
- 接下來就把
UIBarButtonItem
讓touchUpInside
事件去執行掃描的動作 - 不要重複掃描:當開始掃描後會把 UIBarButtonItem 的 Enable 屬性改為 false
- 不要一直掃描:一直掃描會非常耗電,所以盡量設一個掃描時間
啟動掃描後當偵測到藍芽裝置就會進入進入didDiscoverPeripheral
的 callBack
,所以這邊先用幾個陣列才儲存掃瞄到的資訊
var BTPeripheral:[CBPeripheral] = [] // 儲存掃瞄到的 peripheral 物件
var BTIsConnectable: [Int] = [] // 儲存各個藍芽裝置是否可連線
var BTRSSI:[NSNumber] = [] // 儲存各個藍芽裝置的訊號強度
好那就開始進行掃描吧
@IBAction func actionScan(sender: UIBarButtonItem!) {
bbScan.enabled = false
bbScan.title = "Scanning"
BTPeripheral.removeAll(keepCapacity: false)
BTRSSI.removeAll(keepCapacity: false)
BTIsConnectable.removeAll(keepCapacity: false)
myCenteralManager!.scanForPeripheralsWithServices(nil, options: nil)
NSTimer.scheduledTimerWithTimeInterval(5, target: self, selector: "stopScan", userInfo: nil, repeats: false)
}
func stopScan() {
tbvBTDevices.reloadData()
myCenteralManager!.stopScan()
bbScan.title = "Scan"
bbScan.enabled = true
}
點擊掃描案的時後以防重複掃描所以先把按鈕狀態改成 Disable,因為重新掃描了所以將儲存的陣列清空,然後就執行 scanForPeripheralWithServices 開始掃描了,這個方法所帶入的參數是可以指定搜尋條件的。不過這邊先是把所有的裝置都搜尋出來,最後設定 5 秒後停止掃描,並且把掃描的按鈕狀態改回 Enable
4.開啟掃描後只要有掃描到裝置就會進入centralManager
的 didDiscoverPeripheral
callback 方法,所以要在此方法中將收到的資料儲存到剛剛建立的幾個陣列中,並且 reload UITableview 讓他即時更新
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber) {
let temp = BTPeripheral.filter { (pl) -> Bool in
return pl.name == peripheral.name
}
if temp.count == 0 {
BTPeripheral.append(peripheral)
BTRSSI.append(RSSI)
BTIsConnectable.append(Int(advertisementData[CBAdvertisementDataIsConnectable]!.description)!)
}
tbvBTDevices.reloadData()
}
這邊先判定了是否陣列已經有該筆紀錄,將沒有的儲存起來,可以看到 Connectable 的資訊是存在 advertisementData 之中,最後在 tableview 的顯示就放在 cellForRowAtIndexPath 方法中
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("BlueToothTableViewCell", forIndexPath: indexPath) as! BlueToothTableViewCell
cell.lbName.text = BTPeripheral[indexPath.row].name
cell.lbID.text = BTPeripheral[indexPath.row].identifier.UUIDString
cell.lbRSSI.text = "\(BTRSSI[indexPath.row])"
let distancePower = Double(abs(BTRSSI[indexPath.row].integerValue) - RSSI_MEAN) / Double(10 * RSSI_N)
cell.lbDistance.text = "\(pow(10.0,distancePower)) M"
cell.lbIsConnectable.text = BTIsConnectable[indexPath.row].description
return cell
}
其中的 Distance 目前是設定 RSSI_MEAN 是 70,RSSI_N 是 1 的環境條件下去做計算,當然只能參考了
掃描後的畫面像這樣,其中第一和第二個就是我要連的客製化藍芽模組,第三個是我的藍芽滑鼠哈哈
下一步就是進行連線囉
作者已經移除這則留言。
回覆刪除最後一篇有範例喔
刪除http://shenyun23-4.blogspot.tw/2015/11/ios-corebluetooth-swift-2-ble-4.html
我看到了,謝謝你!
刪除