1.掃碼簡(jiǎn)史
這些年移動(dòng)互聯(lián)網(wǎng)的普及审姓,也讓二維碼技術(shù)成功的推廣蚓聘。在遙遠(yuǎn)的iOS7.0之前的年代壳鹤,我們實(shí)現(xiàn)二維碼掃描的功能鉴嗤,還需要借助兩大開源組件ZXing和ZBar來實(shí)現(xiàn)斩启。iOS7.0以后,蘋果提供了AVFoundation框架醉锅,來實(shí)現(xiàn)二維碼是掃碼兔簇,而且效率更高。
與此同時(shí)荣挨,蘋果的Swift開發(fā)語(yǔ)言男韧,也經(jīng)歷了從1.0誕生到4.1,其中不乏一些新特性以及API的變化默垄。
本文講解了如何用Swift4此虑,實(shí)現(xiàn)二維碼掃描的功能
2.具體實(shí)現(xiàn)
2.1權(quán)限控制
實(shí)現(xiàn)二維碼掃描,必然要打開手機(jī)攝像頭口锭,就需要獲取權(quán)限朦前。首先,在你的項(xiàng)目工程的info.plist中加入如下key-value鹃操,否則app調(diào)試的時(shí)候崩潰韭寸。
<key>NSCameraUsageDescription</key>
<string>CameraUsageDescription</string>
另外需要手動(dòng)去檢測(cè)當(dāng)前APP的攝像頭權(quán)限。如下代碼:
func checkCameraAuth() -> Bool {
let status = AVCaptureDevice.authorizationStatus(for: .video)
return status == .authorized
}
不難看出荆隘,status是個(gè)枚舉值恩伺,只有 .authorized才是已經(jīng)獲取攝像頭權(quán)限,其余的都不行椰拒。
2.2 上代碼
2.2.1 初始化
導(dǎo)入AVFoundation框架之后晶渠,我們就可以初始化捕捉設(shè)備、創(chuàng)建捕捉會(huì)話燃观、輸入媒體類型褒脯、設(shè)置代理等
// 捕捉設(shè)備
guard let device = AVCaptureDevice.default(for: .video) else {
return
}
do {
// 輸入
inPut: AVCaptureDeviceInput = try AVCaptureDeviceInput.init(device: device)
} catch {
print(error)
}
/// 輸出
let outPut: AVCaptureMetadataOutput = {
let outPut = AVCaptureMetadataOutput.init()
outPut.connection(with: .metadata)
return outPut
}()
/// 會(huì)話 session
let session: AVCaptureSession = {
let session = AVCaptureSession.init()
if session.canSetSessionPreset(.high){
session.sessionPreset = .high
}
return session
}()
/// 預(yù)覽層
let preLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer.init()
2.2.2 設(shè)置代理
初始化之后,開始設(shè)置代理
// 設(shè)代理
outPut.setMetadataObjectsDelegate(self as AVCaptureMetadataOutputObjectsDelegate, queue: DispatchQueue.main)
// 指定預(yù)覽層的捕捉會(huì)話
preLayer.session = session
2.2.3 指定會(huì)話輸入輸出
然后把捕捉會(huì)話添加輸入輸出
// 捕捉會(huì)話加入input和output
if session.canAddInput(input) && session.canAddOutput(outPut) {
session.addInput(input)
session.addOutput(outPut)
// 設(shè)置元數(shù)據(jù)處理類型(注意, 一定要將設(shè)置元數(shù)據(jù)處理類型的代碼添加到 會(huì)話添加輸出之后)
outPut.metadataObjectTypes = [.ean13, .ean8, .upce, .code39, .code93, .code128, .code39Mod43, .qr]
}
設(shè)置元數(shù)據(jù)處理類型缆毁, 可見不僅有二維碼番川,而且還有其他條碼,就不一一介紹了脊框。注意, 一定要將設(shè)置元數(shù)據(jù)處理類型的代碼添加到會(huì)話添加輸出之后颁督。
2.2.4 添加會(huì)話預(yù)覽圖層
接著開始在頁(yè)面添加預(yù)覽層, 這樣才能看到攝像頭捕捉到的畫面。
// 添加預(yù)覽圖層
let flag = view.layer.sublayers?.contains(preLayer)
if flag == false || flag == nil {
self.preLayer.frame = view.bounds
view.layer.insertSublayer(preLayer, at: 0)
}
2.2.5 開啟會(huì)話
到此為止缚陷,這個(gè)session捕捉會(huì)話需要的參數(shù)都全了适篙,然后開始愉快的開始這個(gè)會(huì)話
// 啟動(dòng)會(huì)話
session.startRunning()
2.2.6 監(jiān)聽捕捉會(huì)話輸出代理
開啟捕捉會(huì)話,我們就可以在代理方法中查看會(huì)話捕捉到的東西箫爷。
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!)
識(shí)別到的就在這個(gè)方法里告訴你。
什么?什么虎锚?硫痰,方法不調(diào)用?
敲黑板4芑ぁPО摺!API有變化了
Swift4.0的代理方法在下面
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection){
var resultStrs = [String]()
for obj in metadataObjects {
guard let codeObj = obj as? AVMetadataMachineReadableCodeObject else {
return
}
resultStrs.append(codeObj.stringValue ?? "")
}
}
在這個(gè)方法里面就能拿到掃碼之后的結(jié)果了柱徙。
2.2.7 思考
寫到這里缓屠,不經(jīng)停下思考:
1.這里還只是基本的掃碼功能,就已經(jīng)這么多代碼了护侮,關(guān)于掃碼頁(yè)面的長(zhǎng)啥樣子的代碼我還沒寫敌完;
2.一般開發(fā)中頁(yè)面少不了UI的網(wǎng)絡(luò)的代碼,難道我要再把這么一大坨AVFoundation代碼都寫到控制器嗎羊初?
3.如果我一個(gè)項(xiàng)目里面滨溉,不止一個(gè)地方用到掃碼,難道我還要再把這么多代碼再?gòu)?fù)制幾遍
3.封裝
高內(nèi)聚 低耦合
就按照這個(gè)原則來封裝长赞。
1.首先把這些AVFoundation模塊的代碼晦攒,統(tǒng)統(tǒng)抽到一個(gè)工具類里,需要的時(shí)候得哆,直接拿工具類調(diào)用脯颜,識(shí)別結(jié)果delegate返回。
2.可以根據(jù)經(jīng)驗(yàn)贩据,把一些定制的需求也放進(jìn)去栋操,比如說掃碼的時(shí)候,中間透明的框框乐设,加上周邊的黑色蒙板讼庇。
3.擴(kuò)展一些其他功能,比如掃碼成功播放一段提示音等待
什么近尚?你準(zhǔn)備動(dòng)手了蠕啄?別著急,我已經(jīng)弄好了,使勁戳????
HRQRCodeScanTool
最簡(jiǎn)單的戈锻,在控制器中歼跟,你只需要
// in ViewController
HRQRCodeScanTool.shared.delegate = self
HRQRCodeScanTool.shared.beginScanInView(view: view)
然后掃碼結(jié)果代理返回
// scan result will call in delegate methods
func scanQRCodeFaild(error: HRQRCodeTooError){
print(error)
}
func scanQRCodeSuccess(resultStrs: [String]){
print(resultStrs.first)
}
如果你需要二維碼描邊,你只需要設(shè)置這幾個(gè)屬性
open var isDrawQRCodeRect: Bool true 是否描繪二維碼邊框 默認(rèn)true
open var drawRectColor: UIColor UIColor.red 二維碼邊框顏色 默認(rèn)紅色
open var drawRectLineWith: CGFloat 2 二維碼邊框線寬 默認(rèn)2
如果你需要添加蒙板格遭,你只需要設(shè)置這幾個(gè)屬性
open var isShowMask: Bool true 是否展示黑色蒙版板層 默認(rèn)開啟
open var maskColor: UIColor Black.alpha 0.5 蒙板層 默認(rèn)黑色 alpha 0.5
open var centerWidth: CGFloat 200 中心非蒙板區(qū)域的寬
open var centerHeight: CGFloat 5.0 中心非蒙板區(qū)域的寬
open var centerPosition: CGPoint? nil 中心非蒙板區(qū)域的中心點(diǎn) 默認(rèn)Veiw的中心
哪里需要掃碼哈街,直接接入工具類,沒多少行代碼搞定拒迅,就問你爽不爽骚秦。
另外她倘,項(xiàng)目里還提供了兩個(gè)擴(kuò)展,用來識(shí)別二維碼圖片作箍,以及圖片生成二維碼硬梁,需要的各位看官老爺自取。
還支持Cocoapods哦