Swift4.2使用CoreBluetooth進(jìn)行藍(lán)牙設(shè)備連接2019-04-17

代碼完整蚁孔,只要用自己 設(shè)備的名字 跟 特征uuid 即可看到效果

import UIKit
import CoreBluetooth

class PeripheralInfo {
    var serviceUUID: CBUUID?
    var characteristics: [CBCharacteristic]?
}
class TTBluetoothManger:NSObject {

    static var share =  TTBluetoothManger()
    private override init(){}
    
    lazy var centralManager:CBCentralManager = {
        let c =  CBCentralManager.init()
        c.delegate = self
        return c
    }()
    
    var currentPeripheral:CBPeripheral?
    var currentCharacteristic_01_01:CBCharacteristic?
    var currentCharacteristic_02_01:CBCharacteristic?

    ///設(shè)備名
    let Cperipheral_name = "M*****  "
    
    ///服務(wù)UUID
    let Cserve_01_uuid = "38*"
    let Cserve_02_uuid = "26*"
    
    ///特征UUID
    let  Ccharacteristic_01_01_uuid = "3***"
    let  Ccharacteristic_02_01_uuid = "2***"

  注:每個設(shè)備的服務(wù)與特征數(shù)量都不同

}

extension TTBluetoothManger{

    ///啟用藍(lán)牙,搜索鏈接設(shè)備
    ///在控制器中調(diào)用即可進(jìn)行整個流程
    func bluetoohStar() {
        self.centralManager.delegate = self
    }
    
    func printShow(str:String) {
        
        print("=====================================")
        print("|             \(str)                |")
        print("-------------------------------------")
    }
    
    ///App向設(shè)備寫入數(shù)據(jù)時調(diào)用次方法
    func deviceStartWriteValue(_ characteristic: CBCharacteristic) {
        
        ///這是我自己設(shè)備的寫入數(shù)據(jù)
        let data = Data.init(bytes:[
            0x01,0xfe,0x00,0x00,
            0x23,0x33,0x10,0x00,
            0x64,0x00,0x00,0x00,
            0x00,0x00,0x00,0x00])
        currentPeripheral!.writeValue(data, for: characteristic, type: CBCharacteristicWriteType.withResponse)
    }
    
}

extension TTBluetoothManger:CBCentralManagerDelegate{
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        
        switch central.state {
        case .unknown:
            print("CBCentralManager state:", "unknown")
        case .resetting:
            print("CBCentralManager state:", "resetting")
        case .unsupported:
            print("CBCentralManager state:", "unsupported")
        case .unauthorized:
            print("CBCentralManager state:", "unauthorized")
        case .poweredOn:
            print("CBCentralManager state:", "poweredOn")
            ///掃描設(shè)備
            central.scanForPeripherals(withServices: nil, options: [CBCentralManagerScanOptionAllowDuplicatesKey:NSNumber.init(value: false)])
            
        case .poweredOff:
            print("CBCentralManager state:", "poweredOff")
        default:
            print("未知錯誤")
        }
    }
    
    ///發(fā)現(xiàn)設(shè)備
    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
        print("---------------------START---------------------")
        print("peripheral.name = \(peripheral.name ?? "搜索失敗!")")
        if peripheral.name != nil{
            guard peripheral.name == "DMK28  " else{return}
            print("peripheral.name = \(peripheral.name!)")
            print("central = \(central)")
            print("peripheral = \(peripheral)")
            print("RSSI = \(RSSI)")
            print("advertisementData = \(advertisementData)")
            self.currentPeripheral = peripheral
            
            ///連接設(shè)備
            if let _ = self.currentPeripheral{
                central.stopScan()
                central.connect(self.currentPeripheral!, options: nil)
            }
            
        }
    }
    
    ///連接設(shè)備成功
    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
        
        printShow(str: "連接成功")
        self.currentPeripheral = peripheral
        peripheral.delegate = self
        //開始尋找Services。傳入nil是尋找所有Services
        peripheral.discoverServices(nil)
    }
    
    ///連接設(shè)備失敗
    func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
    
        printShow(str: "連接失敗:\(error.debugDescription)")
    }

    ///斷開連接
    func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
        printShow(str: "斷開連接")
        
        ///可重新掃描
    }
    
    
}

extension TTBluetoothManger:CBPeripheralDelegate{
    
    ///尋找服務(wù)
    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
        printShow(str: "搜索服務(wù)")
        if error != nil{  print("服務(wù)異常:",error.debugDescription);return}
        guard let pservices = peripheral.services else {return}
        for ser in pservices {
            print("[服務(wù)的UUID] \(ser.uuid)")
            //在感興趣的服務(wù)中尋找感興趣的特征
            if ser.uuid.uuidString == Cserve_01_uuid || ser.uuid.uuidString == Cserve_02_uuid{
                self.currentPeripheral?.discoverCharacteristics(nil, for: ser)
            }
            
        }
    }

    /// 從感興趣的服務(wù)中,確認(rèn) 我們所發(fā)現(xiàn)感興趣的特征
    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
        printShow(str: "確認(rèn)特征")

        if error != nil{  print("特征異常:",error.debugDescription);return}
        guard let serviceCharacters = service.characteristics else {return}
        for characteristic in serviceCharacters {
            let characteristic_uuid = characteristic.uuid
            print("<特征UUID>",characteristic_uuid)

            // 訂閱關(guān)于感興趣特征的持續(xù)通知;
            // “當(dāng)你啟用特征值的通知時欧瘪,外圍設(shè)備調(diào)用……
            if characteristic_uuid.uuidString == Ccharacteristic_01_01_uuid{
                self.currentCharacteristic_01_01 = characteristic
                peripheral.setNotifyValue(true, for: characteristic)
            }
            //讀取感興趣的特征
            if characteristic_uuid.uuidString == Ccharacteristic_02_01_uuid{
                self.currentCharacteristic_02_01 = characteristic
                peripheral.readValue(for: characteristic)

            }
        }
    }
    
    //MARK: - 檢測向外設(shè)寫數(shù)據(jù)是否成功
    func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
        if error != nil {
            printShow(str: "寫數(shù)據(jù)失敗!!!")
        }else{printShow(str: "??寫入數(shù)據(jù)成功??")}
        
    }
    
    // 接收外設(shè)發(fā)來的數(shù)據(jù) 每當(dāng)一個特征值定期更新或者發(fā)布一次時宝与,我們都會收到通知岖沛;
    // 閱讀并解譯我們訂閱的特征值
    // MARK: - 獲取外設(shè)發(fā)來的數(shù)據(jù)
    // 注意罢坝,所有的廓握,不管是 read , notify 的特征的值都是在這里讀取
    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
        printShow(str: "接收數(shù)據(jù)")
        if (characteristic.value != nil) {
            let data = characteristic.value
            
            let mod = Model()
            mod.read_analyzeData(fromData: data!)
        }
    }
    
    //接收characteristic信息    //MARK: - 特征的訂閱狀體發(fā)生變化
    func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
        print("========特征的訂閱狀體變化========")
        printShow(str: characteristic.uuid.uuidString)
        
    }
    
}


class Model: NSObject {
    
    var waterArr = [Double]()
    var oilArr = [Double]()
    var lastwaterArr = [Double]()
    var lastoilArr = [Double]()
    
    var min:UInt8 = 0
    var sec:UInt8 = 0
    var waterValue:UInt8 = 0
    var oilValue:UInt8 = 0
    var countdownFlag:UInt8 = 0
    var workStatus:UInt8 = 0
    var surplus:UInt8 = 0
    var timeString:String = "00:00"
    var isPush = false
    
    var waterValue_100: Int = 0
    var oilValue_100:Int = 0
    
    func read_analyzeData(fromData data:Data) -> Void {
        
        let byteArr = data.bytes
        print(byteArr);
        if byteArr.count > 0{
            let hour = byteArr[7];
            let min = byteArr[8];
            let sec = byteArr[9];
            
            let waterValue = byteArr[10];
            let oilValue = byteArr[11];
            
            let countdownFlag = byteArr[12];
            let workStatus = byteArr[13];
            ///剩余使用次數(shù)
            let surplus = byteArr[14];
            
            
            print("[","時 = ",hour);
            print("分 = ",min);
            print("秒 = ",sec);
            print("水分 = ",waterValue);
            print("油分 = ",oilValue);
            print("倒計時標(biāo)志 = ",countdownFlag);
            print("工作狀態(tài) = ",workStatus);
            print("剩余次數(shù) = ",surplus,"]");
            
            var minString = "\(min)"
            var secString = "\(sec)"
            
            if min < 10 {
                minString = "0" + minString;
            }
            
            if sec < 10 {
                secString = "0" + secString;
            }
            
            let timeString = minString + ":" + secString;
            
            self.min = min;
            self.sec = sec;
            self.waterValue = waterValue;
            self.oilValue = oilValue;
            self.countdownFlag = countdownFlag;
            self.workStatus = workStatus;
            self.surplus = surplus;
            self.timeString = timeString;
            
            
            let temp_water = Int(waterValue)
            self.waterValue_100 = temp_water
            
            let temp_oil = Int(oilValue)
            self.oilValue_100 = temp_oil;
        }
    }
}










extension Data {
    /// Data -> Array, Dictionary
    ///
    /// - Returns: Array
    func toArray() -> [Any]? {
        
        return toArrayOrDictionary() as? [Any]
    }
    
    /// Data -> Array, Dictionary
    ///
    /// - Returns: Array
    func toDictionary() -> [String:Any]? {
        
        return toArrayOrDictionary() as? [String:Any]
    }
    
    /// Data -> Array, Dictionary
    ///
    /// - Returns: Any
    fileprivate func toArrayOrDictionary() -> Any? {
        
        do {
            
            let data = try JSONSerialization.jsonObject(with: self, options: JSONSerialization.ReadingOptions.allowFragments)
            
            return data
        } catch let _ {
            return nil
        }
    }
    
    public var bytes: Array<UInt8> {
        return Array(self)
    }
}

extension String {
    
    //16進(jìn)制的轉(zhuǎn)換
    //16進(jìn)制類型的字符串[A-F,0-9]和Data之間的轉(zhuǎn)換可以使用下面的方法。如果是包含=之類的可以直接用字符串轉(zhuǎn)換Data即可

    ///16進(jìn)制字符串轉(zhuǎn)Data
    func hexData() -> Data? {
        var data = Data(capacity: count / 2)
        let regex = try! NSRegularExpression(pattern: "[0-9a-f]{1,2}", options: .caseInsensitive)
        regex.enumerateMatches(in: self, range: NSMakeRange(0, utf16.count)) { match, flags, stop in
            let byteString = (self as NSString).substring(with: match!.range)
            var num = UInt8(byteString, radix: 16)!
            data.append(&num, count: 1)
        }
        guard data.count > 0 else { return nil }
        return data
    }
    
    func utf8Data()-> Data? {
        return self.data(using: .utf8)
    }
    
}

extension Data {
    ///Data轉(zhuǎn)16進(jìn)制字符串
    func hexString() -> String {
        return map { String(format: "%02x", $0) }.joined(separator: "").uppercased()
    }
}

···
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末嘁酿,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子男应,更是在濱河造成了極大的恐慌闹司,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沐飘,死亡現(xiàn)場離奇詭異游桩,居然都是意外死亡牲迫,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進(jìn)店門借卧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來盹憎,“玉大人,你說我怎么就攤上這事铐刘∨忝浚” “怎么了?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵镰吵,是天一觀的道長檩禾。 經(jīng)常有香客問我,道長疤祭,這世上最難降的妖魔是什么盼产? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮勺馆,結(jié)果婚禮上戏售,老公的妹妹穿的比我還像新娘。我一直安慰自己草穆,他們只是感情好蜈项,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著续挟,像睡著了一般紧卒。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上诗祸,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天跑芳,我揣著相機(jī)與錄音,去河邊找鬼直颅。 笑死博个,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的功偿。 我是一名探鬼主播盆佣,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼械荷!你這毒婦竟也來了共耍?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤吨瞎,失蹤者是張志新(化名)和其女友劉穎痹兜,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體颤诀,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡字旭,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年对湃,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片遗淳。...
    茶點(diǎn)故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡拍柒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出屈暗,到底是詐尸還是另有隱情拆讯,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布恐锦,位于F島的核電站往果,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏一铅。R本人自食惡果不足惜陕贮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望潘飘。 院中可真熱鬧肮之,春花似錦、人聲如沸卜录。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽艰毒。三九已至筐高,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間丑瞧,已是汗流浹背柑土。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留绊汹,地道東北人稽屏。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像西乖,于是被迫代替她去往敵國和親狐榔。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評論 2 348