私はこれをフォローしています tutorial Swift 2.0 to 3.0。しかし、アプリケーションを起動したとき、アプリは動作しません!つまり、何も起こりません!ここに私のコードがあります:
ViewController:
class ViewController: UIViewController ,BarcodeDelegate {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let barcodeViewController: BarcodeViewController = segue.destination as! BarcodeViewController
barcodeViewController.delegate = self
}
func barcodeReaded(barcode: String) {
codeTextView.text = barcode
print(barcode)
}
}
バーコードVC:
import AVFoundation
protocol BarcodeDelegate {
func barcodeReaded(barcode: String)
}
class BarcodeViewController: UIViewController,AVCaptureMetadataOutputObjectsDelegate {
var delegate: BarcodeDelegate?
var captureSession: AVCaptureSession!
var code: String?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
print("works")
self.captureSession = AVCaptureSession();
let videoCaptureDevice: AVCaptureDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
do {
let videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice)
if self.captureSession.canAddInput(videoInput) {
self.captureSession.addInput(videoInput)
} else {
print("Could not add video input")
}
let metadataOutput = AVCaptureMetadataOutput()
if self.captureSession.canAddOutput(metadataOutput) {
self.captureSession.addOutput(metadataOutput)
metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
metadataOutput.metadataObjectTypes = [AVMetadataObjectTypeQRCode,AVMetadataObjectTypeEAN8Code, AVMetadataObjectTypeEAN13Code, AVMetadataObjectTypePDF417Code]
} else {
print("Could not add metadata output")
}
let previewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession)
previewLayer?.frame = self.view.layer.bounds
self.view.layer .addSublayer(previewLayer!)
self.captureSession.startRunning()
} catch let error as NSError {
print("Error while creating vide input device: \(error.localizedDescription)")
}
}
//I THINK THIS METHOD NOT CALL !
private func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {
// This is the delegate'smethod that is called when a code is readed
for metadata in metadataObjects {
let readableObject = metadata as! AVMetadataMachineReadableCodeObject
let code = readableObject.stringValue
// If the code is not empty the code is ready and we call out delegate to pass the code.
if code!.isEmpty {
print("is empty")
}else {
self.captureSession.stopRunning()
self.dismiss(animated: true, completion: nil)
self.delegate?.barcodeReaded(barcode: code!)
}
}
}
出力は次のとおりです。
2016-09-17 18:10:26.000919 BarcodeScaning [2610:674253] [MC]systemgroup.com.Apple.configurationprofilesパスのシステムグループコンテナは/private/var/containers/Shared/SystemGroup/systemgroup.com.Apple.configurationprofiles2016-09-17 18:10:26.007782 BarcodeScaning [2610:674253] [MC]有効な公開ユーザー設定からの読み取り。
最初のステップは、iOS 10の新しい要件であるユーザープライベートデータ型へのアクセスを宣言する必要があります。これは、目的の文字列と共にアプリの_Info.plist
_に使用キーを追加することで実行できます。
次のフレームワークのいずれかを使用していて、使用法の宣言に失敗すると、最初にアクセスしたときにアプリがクラッシュするためです。
連絡先、カレンダー、リマインダー、写真、Bluetooth共有、マイク、カメラ、場所、ヘルス、HomeKit、メディアライブラリ、モーション、CallKit、音声認識、SiriKit、TVプロバイダー。
クラッシュを回避するには、提案されたキーを_Info.plist
_に追加する必要があります。
そして、システムはユーザーにアクセスを許可するように要求するときに目的の文字列を表示します。
詳細については、この記事を使用できます。
以下に示すように、BarcodeViewController
を少し修正して適切に動作するようにしました。
BarcodeViewController
_import UIKit
import AVFoundation
protocol BarcodeDelegate {
func barcodeReaded(barcode: String)
}
class BarcodeViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
var delegate: BarcodeDelegate?
var videoCaptureDevice: AVCaptureDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
var device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeVideo)
var output = AVCaptureMetadataOutput()
var previewLayer: AVCaptureVideoPreviewLayer?
var captureSession = AVCaptureSession()
var code: String?
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = UIColor.clear
self.setupCamera()
}
private func setupCamera() {
let input = try? AVCaptureDeviceInput(device: videoCaptureDevice)
if self.captureSession.canAddInput(input) {
self.captureSession.addInput(input)
}
self.previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
if let videoPreviewLayer = self.previewLayer {
videoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
videoPreviewLayer.frame = self.view.bounds
view.layer.addSublayer(videoPreviewLayer)
}
let metadataOutput = AVCaptureMetadataOutput()
if self.captureSession.canAddOutput(metadataOutput) {
self.captureSession.addOutput(metadataOutput)
metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
metadataOutput.metadataObjectTypes = [AVMetadataObjectTypeQRCode, AVMetadataObjectTypeEAN13Code]
} else {
print("Could not add metadata output")
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if (captureSession.isRunning == false) {
captureSession.startRunning();
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if (captureSession.isRunning == true) {
captureSession.stopRunning();
}
}
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
// This is the delegate's method that is called when a code is read
for metadata in metadataObjects {
let readableObject = metadata as! AVMetadataMachineReadableCodeObject
let code = readableObject.stringValue
self.dismiss(animated: true, completion: nil)
self.delegate?.barcodeReaded(barcode: code!)
print(code!)
}
}
}
_
重要なポイントの1つは、グローバル変数を宣言し、viewWillAppear(:)
およびviewWillDisappear(:)
メソッド内でcaptureSession
を開始および停止することでした。以前のコードでは、バーコードを処理するメソッド内に決して入らないため、まったく呼び出されなかったと思います。
これがお役に立てば幸いです。
Victor Sigler's answer がSwift 4に更新されました。その他の改良。
AVCaptureMetadataOutputObjectsDelegate
のメソッドが
captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!)
に
metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection)
import UIKit
import AVFoundation
protocol BarcodeDelegate: class {
func barcodeRead(barcode: String)
}
class ScannerViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {
weak var delegate: BarcodeDelegate?
var output = AVCaptureMetadataOutput()
var previewLayer: AVCaptureVideoPreviewLayer!
var captureSession = AVCaptureSession()
override func viewDidLoad() {
super.viewDidLoad()
setupCamera()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
DispatchQueue.global(qos: .background).async {
if !self.captureSession.isRunning {
self.captureSession.startRunning()
}
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
DispatchQueue.global(qos: .background).async {
if self.captureSession.isRunning {
self.captureSession.stopRunning()
}
}
}
fileprivate func setupCamera() {
guard let device = AVCaptureDevice.default(for: .video),
let input = try? AVCaptureDeviceInput(device: device) else {
return
}
DispatchQueue.global(qos: .background).async {
if self.captureSession.canAddInput(input) {
self.captureSession.addInput(input)
}
let metadataOutput = AVCaptureMetadataOutput()
if self.captureSession.canAddOutput(metadataOutput) {
self.captureSession.addOutput(metadataOutput)
metadataOutput.setMetadataObjectsDelegate(self, queue: .global(qos: .background))
if Set([.qr, .ean13]).isSubset(of: metadataOutput.availableMetadataObjectTypes) {
metadataOutput.metadataObjectTypes = [.qr, .ean13]
}
} else {
print("Could not add metadata output")
}
self.previewLayer = AVCaptureVideoPreviewLayer(session: self.captureSession)
self.previewLayer.videoGravity = .resizeAspectFill
DispatchQueue.main.async {
self.previewLayer.frame = self.view.bounds
self.view.layer.addSublayer(self.previewLayer)
}
}
}
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
// This is the delegate's method that is called when a code is read
for metadata in metadataObjects {
if let readableObject = metadata as? AVMetadataMachineReadableCodeObject,
let code = readableObject.stringValue {
dismiss(animated: true)
delegate?.barcodeRead(barcode: code)
print(code)
}
}
}
}
以下では、iOSでのバーコードスキャンによるいくつかのアイデアを共有したいと思います。
exposurePointOfInterest
およびfocusPointOfInterest
を設定しますrectOfInterests
を設定しますfocusMode
およびexposureMode
を設定しますlockForConfiguration
で適切にロックします.plistファイルにエントリを追加
Info.plistファイルに次のコードを追加して、アプリケーションがiPhoneのカメラにアクセスできるようにします。
<key>NSCameraUsageDescription</key>
<string>Allow access to camera</string>
ExposurePointOfInterestおよびfocusPointOfInterestを設定しますexposurePointOfInterest
およびfocusPointOfInterest
を使用すると、スキャンの品質が向上し、画面の中心点でカメラの焦点が速くなります。
rectOfInterestsを設定
このプロパティにより、カメラは画面の一部だけに焦点を合わせることができます。このようにして、コードをより速くスキャンし、画面の中央に表示されたコードだけに焦点を当てることができます。これは、他のコードがバックグラウンドで利用できない場合に便利です。
focusModeおよびExposureModeを設定しますプロパティは次のように設定する必要があります。
device.focusMode = .continuousAutoFocus
device.exposureMode = .continuousAutoExposure
これにより、連続的に焦点を合わせ、スキャンコードに合わせて適切に露出を設定できます。
ここで、このアイデアを実装する準備ができたプロジェクトを見つけることができます: https://github.com/lukszar/QuickScanner
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [Any]!, from connection: AVCaptureConnection!) {
print("caught QR code")
for metadata in metadataObjects {
let readableObject = metadata as! AVMetadataMachineReadableCodeObject
let code = readableObject.stringValue
if code!.isEmpty {
print("is empty")
} else {
self.captureSession.stopRunning()
self.dismiss(animated: true, completion: nil)
self.delegate?.gotQRCode(code: code!)
}
}
}
メソッドのシグネチャがSwift 3.で少し変更されたようです。
NSCameraUsageDescriptionをInfo.plistファイルに追加して、機能させる必要があります!
info.plistに行を追加し、NSCameraUsageDescriptionを新しく作成した行に入力し、アプリ内でカメラへのアクセスが必要な理由をユーザーに知らせるための文字列を追加します。
これでうまくいくはずです!