1.掃碼簡史
這些年移動網際網路的普及,也讓二維碼技術成功的推廣。在遙遠的iOS7.0之前的年代,我們實現二維碼掃描的功能,還需要藉助兩大開源元件ZXing和ZBar來實現。iOS7.0以後,蘋果提供了AVFoundation框架,來實現二維碼是掃碼,而且效率更高。 與此同時,蘋果的Swift開發語言,也經歷了從1.0誕生到4.1,其中不乏一些新特性以及API的變化。
本文講解了如何用Swift4,實現二維碼掃描的功能
2.具體實現
2.1許可權控制
實現二維碼掃描,必然要開啟手機攝像頭,就需要獲取許可權。首先,在你的專案工程的info.plist中加入如下key-value,否則app除錯的時候崩潰。
<key>NSCameraUsageDescription</key>
<string>CameraUsageDescription</string>
複製程式碼
另外需要手動去檢測當前APP的攝像頭許可權。如下程式碼:
func checkCameraAuth() -> Bool {
let status = AVCaptureDevice.authorizationStatus(for: .video)
return status == .authorized
}
複製程式碼
不難看出,status是個列舉值,只有 .authorized才是已經獲取攝像頭許可權,其餘的都不行。
2.2 上程式碼
2.2.1 初始化
匯入AVFoundation框架之後,我們就可以初始化捕捉裝置、建立捕捉會話、輸入媒體型別、設定代理等
// 捕捉裝置
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
}()
/// 預覽層
let preLayer: AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer.init()
複製程式碼
2.2.2 設定代理
初始化之後,開始設定代理
// 設代理
outPut.setMetadataObjectsDelegate(self as AVCaptureMetadataOutputObjectsDelegate, queue: DispatchQueue.main)
// 指定預覽層的捕捉會話
preLayer.session = session
複製程式碼
2.2.3 指定會話輸入輸出
然後把捕捉會話新增輸入輸出
// 捕捉會話加入input和output
if session.canAddInput(input) && session.canAddOutput(outPut) {
session.addInput(input)
session.addOutput(outPut)
// 設定後設資料處理型別(注意, 一定要將設定後設資料處理型別的程式碼新增到 會話新增輸出之後)
outPut.metadataObjectTypes = [.ean13, .ean8, .upce, .code39, .code93, .code128, .code39Mod43, .qr]
}
複製程式碼
設定後設資料處理型別, 可見不僅有二維碼,而且還有其他條碼,就不一一介紹了。注意, 一定要將設定後設資料處理型別的程式碼新增到會話新增輸出之後。
2.2.4 新增會話預覽圖層
接著開始在頁面新增預覽層, 這樣才能看到攝像頭捕捉到的畫面。
// 新增預覽圖層
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捕捉會話需要的引數都全了,然後開始愉快的開始這個會話
// 啟動會話
session.startRunning()
複製程式碼
2.2.6 監聽捕捉會話輸出代理
開啟捕捉會話,我們就可以在代理方法中檢視會話捕捉到的東西。
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!)
複製程式碼
識別到的就在這個方法裡告訴你。 什麼?什麼?,方法不呼叫? 敲黑板!!!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 ?? "")
}
}
複製程式碼
在這個方法裡面就能拿到掃碼之後的結果了。
2.2.7 思考
寫到這裡,不經停下思考: 1.這裡還只是基本的掃碼功能,就已經這麼多程式碼了,關於掃碼頁面的長啥樣子的程式碼我還沒寫; 2.一般開發中頁面少不了UI的網路的程式碼,難道我要再把這麼一大坨AVFoundation程式碼都寫到控制器嗎? 3.如果我一個專案裡面,不止一個地方用到掃碼,難道我還要再把這麼多程式碼再複製幾遍
3.封裝
高內聚 低耦合 就按照這個原則來封裝。 1.首先把這些AVFoundation模組的程式碼,統統抽到一個工具類裡,需要的時候,直接拿工具類呼叫,識別結果delegate返回。 2.可以根據經驗,把一些定製的需求也放進去,比如說掃碼的時候,中間透明的框框,加上週邊的黑色蒙板。 3.擴充套件一些其他功能,比如掃碼成功播放一段提示音等待
什麼?你準備動手了?彆著急,我已經弄好了,使勁戳??
HRQRCodeScanTool
最簡單的,在控制器中,你只需要
// in ViewController
HRQRCodeScanTool.shared.delegate = self
HRQRCodeScanTool.shared.beginScanInView(view: view)
複製程式碼
然後掃碼結果代理返回
// scan result will call in delegate methods
func scanQRCodeFaild(error: HRQRCodeTooError){
print(error)
}
func scanQRCodeSuccess(resultStrs: [String]){
print(resultStrs.first)
}
複製程式碼
如果你需要二維碼描邊,你只需要設定這幾個屬性
open var isDrawQRCodeRect: Bool true 是否描繪二維碼邊框 預設true
open var drawRectColor: UIColor UIColor.red 二維碼邊框顏色 預設紅色
open var drawRectLineWith: CGFloat 2 二維碼邊框線寬 預設2
複製程式碼
如果你需要新增蒙板,你只需要設定這幾個屬性
open var isShowMask: Bool true 是否展示黑色蒙版板層 預設開啟
open var maskColor: UIColor Black.alpha 0.5 蒙板層 預設黑色 alpha 0.5
open var centerWidth: CGFloat 200 中心非蒙板區域的寬
open var centerHeight: CGFloat 5.0 中心非蒙板區域的寬
open var centerPosition: CGPoint? nil 中心非蒙板區域的中心點 預設Veiw的中心
複製程式碼
哪裡需要掃碼,直接接入工具類,沒多少行程式碼搞定,就問你爽不爽。 另外,專案裡還提供了兩個擴充套件,用來識別二維碼圖片,以及圖片生成二維碼,需要的各位看官老爺自取。
還支援Cocoapods哦