iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 10
0
自我挑戰組

老蕭咖啡館,情境式學習基礎iOS Swift系列 第 10

[2019鐵人賽Day10]老蕭咖啡館-老闆加映篇(Barcode Reader)

[鐵人碎念Time]
https://ithelp.ithome.com.tw/upload/images/20181025/20091333QkcF5q5wZb.png

我也擠了擠我的乳溝,發現時間還是只剩一小時啊!/images/emoticon/emoticon09.gif
妳呢?快擠看看!!/images/emoticon/emoticon37.gif
我可以不要百煉成鋼,可以成神嗎/images/emoticon/emoticon37.gif

==========

誒~老闆不對啊!(林宇)
老闆很對啊,哪裡不對了~除了現在還是魯蛇外,一切都很對啊/images/emoticon/emoticon16.gif

不是啦,是你介紹QR Code、Barcode產生器,那怎沒連掃描內容的APP也順便介紹啊!!(林宇)
因那時蕭亦翔沒教我也沒提到啊,再說現在掃瞄器這麼多,Line也有,且iOS 11在相機中內建了掃描QR Code的功能了啊!

不管啦,我就是好奇嗎~教我啦!(林宇撒嬌樣)
先說好,這可比前面說的那兩樣難多了,同時也複雜多了唷...

(林宇一臉可憐樣盯著看)/images/emoticon/emoticon02.gif
唉~/images/emoticon/emoticon67.gif
好啦好啦,就算我同場加映教妳吧
就知道你人最好了!!(林宇)/images/emoticon/emoticon41.gif

==========

Step1. 首先,先到「Apple Developer」(https://developer.apple.com/)申請開發者帳號
(這之前要先有Apple ID(https://appleid.apple.com/account#!&page=create))
關於怎申請,這方面我就不多做說明了,Google上可以查到許多

Step2. 接著在Xcode左上選單「Xcode」->「Preferences...」
https://ithelp.ithome.com.tw/upload/images/20181026/20091333Aav0pgZex3.png

Step3.點選「Accounts」->請照著圖片上的步驟1「+」->接著步驟2選擇「Apple ID」->點選步驟三3「Continue」->登入Apple ID
https://ithelp.ithome.com.tw/upload/images/20181026/20091333RusZXvGWZq.png

https://ithelp.ithome.com.tw/upload/images/20181026/20091333S5VkNqnWks.png

Step4. 登入後,請按照圖上所示點選步驟1管理憑證「Manage Certificates...」->點選步驟2「+」->步驟3加入「iOS Developmengt」->「Done」
https://ithelp.ithome.com.tw/upload/images/20181026/20091333pjBmLHMDVM.png

(以上為等等要順利編譯後在手機上呈現的步驟之一)

==========

Step5. 接著建立新專案,名稱為「scanBarcode」,Team應該可以選擇,不會只有「None」的選項
https://ithelp.ithome.com.tw/upload/images/20181026/20091333zvZxklPFL8.png

Step6. 在畫面上拉出一個View跟一個Label
https://ithelp.ithome.com.tw/upload/images/20181026/200913335yCXFIZPrX.png

Step7. 導入AVFoundation框架
https://ithelp.ithome.com.tw/upload/images/20181026/20091333KUxhaOvB07.png

import AVFoundation //導入AVFoundation框架

Step8. class後方加入AVCaptureMetadataOutputObjectsDelegate協定
https://ithelp.ithome.com.tw/upload/images/20181026/20091333Qxub6wFNt0.png

class ViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {

Step9. 接著宣告兩個等等會用到的常數,元件連結View命名為「CameraView」,Label命名為「ContentValue」
https://ithelp.ithome.com.tw/upload/images/20181026/20091333TtUr0xWzPK.png

    // 協調從接收裝置到輸出元件間的資料動作
    let AVCsession = AVCaptureSession()
    // 即時顯示預覽目前相機接收到的畫面
    let AVCVideoPreviewLayer = AVCaptureVideoPreviewLayer()
    
    @IBOutlet weak var CameraView: UIView!
    @IBOutlet weak var ContentValue: UILabel!

Step10. 接著在viewDidLoad內加入以下Code,內已有註解請觀看理解
https://ithelp.ithome.com.tw/upload/images/20181026/20091333lC4CmOYMoQ.png

        //啟動相機
        AVCsession.startRunning()
        
        // 取得預設的相機裝置(後鏡頭)
        let AVCdevice = AVCaptureDevice.default(for: .video)
        do {
            // 設定資料來源為後鏡頭
            let videoInput = try AVCaptureDeviceInput(device: AVCdevice!)
            AVCsession.addInput(videoInput)
            
            // 設定所取得資料為MetaData物件資料
            let AVCvideoOutput = AVCaptureMetadataOutput()
            AVCsession.addOutput(AVCvideoOutput)
            
            // 接收所有MetaData資料
            AVCvideoOutput.metadataObjectTypes = AVCvideoOutput.availableMetadataObjectTypes
            AVCvideoOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
            
            // 設定瀏覽畫面
            AVCVideoPreviewLayer.session = AVCsession
            AVCVideoPreviewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
            CameraView.layer.addSublayer(AVCVideoPreviewLayer)
        } catch {
            // 拋出錯誤訊息
            print(error)
        }

Step11. 用於Function通知控制器將要佈局view的子控制元件時使用
https://ithelp.ithome.com.tw/upload/images/20181026/20091333Odj4ziUxHv.png

    /*
     Function通知控制器將要佈局view的子控制元件時使用
     每當畫面的bounds改變,view將調整其子控制元件位置
     在控制器生命週期中,該方法可能會被多次使用
     */
    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        AVCVideoPreviewLayer.frame = CameraView.bounds
    }

Step12. 加入輸出訊息的方法
https://ithelp.ithome.com.tw/upload/images/20181026/200913335ikFlcz74r.png

    func metadataOutput(_ captureOutput: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
        for metaData in metadataObjects {
            if let data = metaData as? AVMetadataMachineReadableCodeObject {
                // 條碼內容
                ContentValue.text = data.stringValue
            } else {
                print("error")
            }
        }
    }

Step13. 將模擬器類型挑選到自己的手機名稱(手機要先連接好)後執行->會出現取得權限畫面(這邊如出現問題,請先看下方解決方法)->掃描確認訊息->Finish
https://ithelp.ithome.com.tw/upload/images/20181026/20091333qyf4aaTavI.png

https://ithelp.ithome.com.tw/upload/images/20181026/200913332Ct4WrorXB.png

https://ithelp.ithome.com.tw/upload/images/20181026/20091333UYCslMo9Uo.png

https://ithelp.ithome.com.tw/upload/images/20181026/20091333BDoEwu2VoV.png

==========

各位在執行時,有無出現錯誤訊息呢?
就類似下方圖示(或者閃退):
https://ithelp.ithome.com.tw/upload/images/20181026/20091333Fu3m0bjIUv.png

那是因為我們少說到一個地方,條用相機功能權限解,解決方法:
Step1. 開啟info.plist文件
https://ithelp.ithome.com.tw/upload/images/20181026/200913338A4xrzeO8u.png

Step2. 加入相機權限代碼
https://ithelp.ithome.com.tw/upload/images/20181026/20091333zLcxlF8Q47.png

可參考此資源:https://www.jianshu.com/p/eb9af5982bc0

==========

完整內碼提供:

import UIKit
import AVFoundation //導入AVFoundation框架

/*
 (可查詢UIViewController生命週期)
 (可查詢AVCaptureMetadataOutputObjectsDelegate協定)
 */
class ViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
    // 協調從接收裝置到輸出元件間的資料動作
    let AVCsession = AVCaptureSession()
    // 即時顯示預覽目前相機接收到的畫面
    let AVCVideoPreviewLayer = AVCaptureVideoPreviewLayer()
    
    @IBOutlet weak var CameraView: UIView!
    @IBOutlet weak var ContentValue: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //啟動相機
        AVCsession.startRunning()
        
        // 取得預設的相機裝置(後鏡頭)
        let AVCdevice = AVCaptureDevice.default(for: .video)
        do {
            // 設定資料來源為後鏡頭
            let videoInput = try AVCaptureDeviceInput(device: AVCdevice!)
            AVCsession.addInput(videoInput)
            
            // 設定所取得資料為MetaData物件資料
            let AVCvideoOutput = AVCaptureMetadataOutput()
            AVCsession.addOutput(AVCvideoOutput)
            
            // 接收所有MetaData資料
            AVCvideoOutput.metadataObjectTypes = AVCvideoOutput.availableMetadataObjectTypes
            AVCvideoOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
            
            // 設定瀏覽畫面
            AVCVideoPreviewLayer.session = AVCsession
            AVCVideoPreviewLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill
            CameraView.layer.addSublayer(AVCVideoPreviewLayer)
        } catch {
            // 拋出錯誤訊息
            print(error)
        }
    }
    
    /*
     Function通知控制器將要佈局view的子控制元件時使用
     每當畫面的bounds改變,view將調整其子控制元件位置
     在控制器生命週期中,該方法可能會被多次使用
     */
    override func viewWillLayoutSubviews() {
        super.viewWillLayoutSubviews()
        AVCVideoPreviewLayer.frame = CameraView.bounds
    }

    func metadataOutput(_ captureOutput: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
        for metaData in metadataObjects {
            if let data = metaData as? AVMetadataMachineReadableCodeObject {
                // 條碼內容
                ContentValue.text = data.stringValue
            } else {
                print("error")
            }
        }
    }
}

上一篇
[2019鐵人賽Day9]老蕭咖啡館-小技巧篇,模擬器加入中文輸入
下一篇
[2019鐵人賽Day11]老蕭咖啡館-小技巧篇,iOS App Icons(快速製作各尺寸與設置方法)
系列文
老蕭咖啡館,情境式學習基礎iOS Swift30

尚未有邦友留言

立即登入留言