1.掃碼簡史
這些年移動互聯(lián)網(wǎng)的普及,也讓二維碼技術(shù)成功的推廣。在遙遠的iOS7.0之前的年代,我們實現(xiàn)二維碼掃描的功能,還需要借助兩大開源組件ZXing和ZBar來實現(xiàn)。iOS7.0以后,蘋果提供了AVFoundation框架,來實現(xiàn)二維碼是掃碼,而且效率更高。
與此同時,蘋果的Swift開發(fā)語言,也經(jīng)歷了從1.0誕生到4.1,其中不乏一些新特性以及API的變化。
本文講解了如何用Swift4,實現(xiàn)二維碼掃描的功能
2.具體實現(xiàn)
2.1權(quán)限控制
實現(xiàn)二維碼掃描,必然要打開手機攝像頭,就需要獲取權(quán)限。首先,在你的項目工程的info.plist中加入如下key-value,否則app調(diào)試的時候崩潰。
<key>NSCameraUsageDescription</key>
<string>CameraUsageDescription</string>
另外需要手動去檢測當(dāng)前APP的攝像頭權(quán)限。如下代碼:
func checkCameraAuth() -> Bool {
let status = AVCaptureDevice.authorizationStatus(for: .video)
return status == .authorized
}
不難看出,status是個枚舉值,只有 .authorized才是已經(jīng)獲取攝像頭權(quán)限,其余的都不行。
2.2 上代碼
2.2.1 初始化
導(dǎo)入AVFoundation框架之后,我們就可以初始化捕捉設(shè)備、創(chuàng)建捕捉會話、輸入媒體類型、設(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
}()
/// 會話 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ù)覽層的捕捉會話
preLayer.session = session
2.2.3 指定會話輸入輸出
然后把捕捉會話添加輸入輸出
// 捕捉會話加入input和output
if session.canAddInput(input) && session.canAddOutput(outPut) {
session.addInput(input)
session.addOutput(outPut)
// 設(shè)置元數(shù)據(jù)處理類型(注意, 一定要將設(shè)置元數(shù)據(jù)處理類型的代碼添加到 會話添加輸出之后)
outPut.metadataObjectTypes = [.ean13, .ean8, .upce, .code39, .code93, .code128, .code39Mod43, .qr]
}
設(shè)置元數(shù)據(jù)處理類型, 可見不僅有二維碼,而且還有其他條碼,就不一一介紹了。注意, 一定要將設(shè)置元數(shù)據(jù)處理類型的代碼添加到會話添加輸出之后。
2.2.4 添加會話預(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 開啟會話
到此為止,這個session捕捉會話需要的參數(shù)都全了,然后開始愉快的開始這個會話
// 啟動會話
session.startRunning()
2.2.6 監(jiān)聽捕捉會話輸出代理
開啟捕捉會話,我們就可以在代理方法中查看會話捕捉到的東西。
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!)
識別到的就在這個方法里告訴你。
什么?什么?,方法不調(diào)用?
敲黑板!??!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 ?? "")
}
}
在這個方法里面就能拿到掃碼之后的結(jié)果了。
2.2.7 思考
寫到這里,不經(jīng)停下思考:
1.這里還只是基本的掃碼功能,就已經(jīng)這么多代碼了,關(guān)于掃碼頁面的長啥樣子的代碼我還沒寫;
2.一般開發(fā)中頁面少不了UI的網(wǎng)絡(luò)的代碼,難道我要再把這么一大坨AVFoundation代碼都寫到控制器嗎?
3.如果我一個項目里面,不止一個地方用到掃碼,難道我還要再把這么多代碼再復(fù)制幾遍

3.封裝
高內(nèi)聚 低耦合
就按照這個原則來封裝。
1.首先把這些AVFoundation模塊的代碼,統(tǒng)統(tǒng)抽到一個工具類里,需要的時候,直接拿工具類調(diào)用,識別結(jié)果delegate返回。
2.可以根據(jù)經(jīng)驗,把一些定制的需求也放進去,比如說掃碼的時候,中間透明的框框,加上周邊的黑色蒙板。
3.擴展一些其他功能,比如掃碼成功播放一段提示音等待
什么?你準備動手了?別著急,我已經(jīng)弄好了,使勁戳????
HRQRCodeScanTool
最簡單的,在控制器中,你只需要
// 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è)置這幾個屬性
open var isDrawQRCodeRect: Bool true 是否描繪二維碼邊框 默認true
open var drawRectColor: UIColor UIColor.red 二維碼邊框顏色 默認紅色
open var drawRectLineWith: CGFloat 2 二維碼邊框線寬 默認2
如果你需要添加蒙板,你只需要設(shè)置這幾個屬性
open var isShowMask: Bool true 是否展示黑色蒙版板層 默認開啟
open var maskColor: UIColor Black.alpha 0.5 蒙板層 默認黑色 alpha 0.5
open var centerWidth: CGFloat 200 中心非蒙板區(qū)域的寬
open var centerHeight: CGFloat 5.0 中心非蒙板區(qū)域的寬
open var centerPosition: CGPoint? nil 中心非蒙板區(qū)域的中心點 默認Veiw的中心
哪里需要掃碼,直接接入工具類,沒多少行代碼搞定,就問你爽不爽。
另外,項目里還提供了兩個擴展,用來識別二維碼圖片,以及圖片生成二維碼,需要的各位看官老爺自取。

還支持Cocoapods哦