swift语言编写一个简单的条形码扫描APP

原文地址:appcoda
在处理职员在杂货店的收银台排了很长的队伍,在机场帮助检查背包和旅客,或者在主要的食品供应商,协助处理乏味的存货清单过程,条形码扫描是很简单的处理工具。实际上,他们已经用了这个办法来解决消费者在智能购物,图书分类,等其他目的。因此,让我们来制作一个iPhone版本的条形码扫描工具吧!
对我们来说幸运的是,苹果已经制作了条形码扫描的程序,实现它是一件很简单的事情。我们将要研究进入AV Foundation框架的世界,组建APP,用来读取光盘上的条形码,获取相册上的一些重要信息,以及输出这些信息在APP上查看。读取条形码是很酷和重要的,所以要进一步读取我们收到的条形码号码。不言而喻,但是条形码扫描APP只有在带有相机的设备上才能使用。基于这一点,让我们拿起带有摄像头的IOS设备开始我们的教程吧! ========================== (全都是废话……)

关于 CDBarcodes

今天我们将要制作的APP的名字是CDBarcodes,当我们的设备发现了一个条形码,我们将扫描它并且发送到Discogs音乐数据库获取相册名字、在最近一年的受关注的艺术家。Discogs有一个很庞大的记录音乐的数据库,因此我们可以很好的获取我们所需要的信息。现在就开始下载 CDBarcodes,进行我们的教程吧!

令人印象深刻的数据库,Discogs提供有用的API供开发者调用查询。我们只能接触到一小部分Discogs提供给开发者的功能,但是这对于我们来说,足够开发一些有趣的APP了。

Discogs

开始浏览产看Discogs内容,首先,我们需要登录和注册一个Discogs账号。在登录之后,滚动到屏幕底部。在底部部分,左边的列,点击API链接。如下图:

在**Discogs**API选项中,左边的面板,Database部分,点击 Search。如下图:

我们将要从这里获取专辑的音乐信息,通过titleyear这两个参数。现在我们趁机要记录一个URL地址,在 Constants.swift中,添加https://api.discogs.com/database/search?q=作为常量DISCOGS_AUTH_URL的值。

let DISCOGS_KEY = "your-discogs-key"

现在,在整个APP中用方便的DISCOGS_AUTH_URL来访问我们的搜索RUL,回退Discogs API,创建一个新的APP以及配置一些东西,在顶部页面的导航栏中,点击创建APP。让后点击穿件一个应用程序按钮。如下图:

这里应用名称就输入CDBarcodes,当然你也可以自己适当改下。关于描述,如下:
“This is an iOS app that reads barcodes from CDs and displays information about the albums.”
然后,点击创建应用按钮。
默认生成的屏幕会显示用户条形码的数字证书编号,复制这个唯一的数字号码,粘贴到Constants.swift文件里面的DISCOGS_KEY常量值,然后复制用户秘钥到Constants.swift文件里面的DISCOGS_SECRET值,正如这个URL,我们方便在CDBarodes里面访问这些数值。如图:

CocoaPods

为了使用Discogs API,那么我们通过CocoaPods这个工具,关于更多Discogs的信息,可以去看CocoaPods’ site.网站查看。

通过 CocoaPods集成了AlamofireSwiftyJSON用户访问网络和解析获取到的JSON数据。让我们来开始写这个简单的APP吧。
通过,CocoaPods建立第三方库,需要打开一个控制台,cd到CDBarcodes项目,初始化CocoaPodsXcode项目如下:

cd <your-xcode-project-directory>
pod init

这时候,会在项目内生成Podfile文件,控制台输入:

open -a Xcode Podfile

然后粘贴以下代码:

source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
use_frameworks!pod 'Alamofire', '~> 3.0'target ‘CDBarcodes’ do
pod 'SwiftyJSON', :git => 'https://github.com/SwiftyJSON/SwiftyJSON.git'
end

实际上可以直接在Xcode中编辑Podfile文件,添加以上代码也可以。


最后执行:

pod install

完成建立AlamofireSwiftyJSON第三方库,是不是很简单呢?此时我们要做的就是回到XCode中,确保从CDBarcodes.xcworkspace打开项目。

The Barcode Reader

AV Foundation 框架提供了工具用于我们组建 barcode reader工具,这里有些说明:
* AVCaptureSession管理相机捕获的数据
* AVCaptureDevice代表物理设备是AV Foundation框架的一个属性,AVCaptureSession接受从AVCaptureDevice获取的输入数据。
* AVCaptureDeviceInput从输入设备中捕获数据。
* AVCaptureMetadataOutput通过一个Delegate对象暴露获取的原始数据,也就是二进制数据。

BarcodeReaderViewController.swift,第一步导入 AVFoundation。

import UIKit
import AVFoundation

实现 AVCaptureMetadataOutputObjectsDelegate代理方法.在viewDidLoad(),获取读取barcode对象。
首先,创建AVCaptureSession对象,并且设置AVCaptureDevice,生成了一个输入对象并添加到AVCaptureSession对象中。

class BarcodeReaderViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate {var session: AVCaptureSession!
var previewLayer: AVCaptureVideoPreviewLayer!override func viewDidLoad() {super.viewDidLoad()// Create a session object.session = AVCaptureSession()// Set the captureDevice.let videoCaptureDevice = AVCaptureDevice.defaultDeviceWithMediaType(AVMediaTypeVideo)// Create input object.let videoInput: AVCaptureDeviceInput?do {videoInput = try AVCaptureDeviceInput(device: videoCaptureDevice)} catch {return}// Add input to the session.if (session.canAddInput(videoInput)) {session.addInput(videoInput)} else {scanningNotPossible()}

有可能,设备没有照相机,扫描将不能进行。因此需要判断扫描失败的情况,看,我们可以提示用户说,扫描的设备必须要有照相机。
这部分代码如下:

func scanningNotPossible() {// Let the user know that scanning isn't possible with the current device.let alert = UIAlertController(title: "Can't Scan.", message: "Let's try a device equipped with a camera.", preferredStyle: .Alert)alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))presentViewController(alert, animated: true, completion: nil)session = nil
}

回到 viewDidLoad()方法中,添加了一个输入的会话后,需要创建一个AVCaptureMetadataOutput输出对象,并要添加到该会话中,我们发送捕获到的数据到代理方法中。
下一步就是设置条形码扫描类型,这里我们需要扫描的条形码是EAN-13类型的,因此并不是要扫描所有的条形码,比如有些UPC-A类型的条形码就会存在一些问题。
苹果转换UPC-A条形码到EAN-13类型是在最前面添加0,UPC-A条形码只有12位数,但EAN-13有13位,好的事情是可以通过metadataObjectTypesAVMetadataObjectTypeEAN13Code设置,来自动转换,但是这种转换会给 Discogs照成一些问题,不用担心,很快我们会开始处理这个问题,再次,如果相机有问题,还将要发送scanningNotPossible()消息给用户。

// Create output object.let metadataOutput = AVCaptureMetadataOutput()// Add output to the session.if (session.canAddOutput(metadataOutput)) {session.addOutput(metadataOutput)// Send captured data to the delegate object via a serial queue.metadataOutput.setMetadataObjectsDelegate(self, queue: dispatch_get_main_queue())// Set barcode type for which to scan: EAN-13.metadataOutput.metadataObjectTypes = [AVMetadataObjectTypeEAN13Code]} else {scanningNotPossible()}

好了,现在需要AVCaptureVideoPreviewLayer类来全屏展示捕获到的视频内容,最后,我们开始捕获数据:

// 添加预览图层,用来展示捕获到的视频内容,就是条形码了.
​        previewLayer = AVCaptureVideoPreviewLayer(session: session);previewLayer.frame = view.layer.bounds;previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;view.layer.addSublayer(previewLayer);// 开始捕获session.startRunning()

captureOutput:didOutputMetadataObjects:fromConnection中,可以发现扫描到的条形码信息。
首先需要获取metadataObjects数组里面的第一个元素并转换为机器可读的代码,然后发送readableCode字符串到barcodeDetected(),接着需要提示用户会话是否成功,可以通过震动手机,最后不要忘了停止我们的会话。

func captureOutput(captureOutput: AVCaptureOutput!, didOutputMetadataObjects metadataObjects: [AnyObject]!, fromConnection connection: AVCaptureConnection!) {// Get the first object from the metadataObjects array.if let barcodeData = metadataObjects.first {// Turn it into machine readable codelet barcodeReadable = barcodeData as? AVMetadataMachineReadableCodeObject;if let readableCode = barcodeReadable {// Send the barcode as a string to barcodeDetected()barcodeDetected(readableCode.stringValue);}// Vibrate the device to give the user some feedback.AudioServicesPlaySystemSound(SystemSoundID(kSystemSoundID_Vibrate))// Avoid a very buzzy device.session.stopRunning()}
}

barcodeDetected()方法中还有些工作需要做,获取到的代码必须要移除空格符号,去掉空格符好之后,确认条形码是EAN-13还是UPC-A,如果是后者,还需要转换为EAN-13类型格式,并返还到最初的状态,也就是没去空格的时候。之前讨论的,苹果处理转换时直接最前面添加0,因此想0是不是开头呢,如果移除掉,没有这一步,Discogs将不会识别出号码,并获取不到数据呢?
获得最终的字符串后,将它发送到BarcodeReaderViewController.swift文件的DataService.searchAPI()方法处理。

func barcodeDetected(code: String) {// Let the user know we've found something.let alert = UIAlertController(title: "Found a Barcode!", message: code, preferredStyle: UIAlertControllerStyle.Alert)alert.addAction(UIAlertAction(title: "Search", style: UIAlertActionStyle.Destructive, handler: { action in// Remove the spaces.let trimmedCode = code.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet())// EAN or UPC?// Check for added "0" at beginning of code.let trimmedCodeString = "\(trimmedCode)"var trimmedCodeNoZero: Stringif trimmedCodeString.hasPrefix("0") && trimmedCodeString.characters.count > 1 {trimmedCodeNoZero = String(trimmedCodeString.characters.dropFirst())// Send the doctored UPC to DataService.searchAPI()DataService.searchAPI(trimmedCodeNoZero)} else {// Send the doctored EAN to DataService.searchAPI()DataService.searchAPI(trimmedCodeString)}self.navigationController?.popViewControllerAnimated(true)}))self.presentViewController(alert, animated: true, completion: nil)
}

在这之前,必须在viewDidLoad()下面,继续添加viewWillAppear()viewWillDisappear()两个方法,viewWillAppear()方法中开始捕获会话的行为,相反viewWillDisappear()就是结束该会话。

override func viewWillAppear(animated: Bool) {super.viewWillAppear(animated)if (session?.running == false) {session.startRunning()}
}override func viewWillDisappear(animated: Bool) {super.viewWillDisappear(animated)if (session?.running == true) {session.stopRunning()}
}

The Data Service

DataService.swift中,导入AlamofireSwiftyJSON模块。然后,声明一些变量用来存储Discogs返回的数据,
感谢 Bionik6建议,设置private(set)用来防止别的类更改这个值。之后,获取网络数据,解析JSON格式,并将获取到的专辑标题和
年份赋值给 ALBUM_FROM_DISCOGSYEAR_FROM_DISCOGS变量。好了,现在我们已经可以获取到数据了,需要将这个消息通知到AlbumDetailsViewController.swift类去,所以需要发送通知到这个类。

import Foundation
import Alamofire
import SwiftyJSONclass DataService {static let dataService = DataService()private(set) var ALBUM_FROM_DISCOGS = ""
private(set) var YEAR_FROM_DISCOGS = ""static func searchAPI(codeNumber: String) {// The URL we will use to get out album data from Discogslet discogsURL = "\(DISCOGS_AUTH_URL)\(codeNumber)&?barcode&key=\(DISCOGS_KEY)&secret=\(DISCOGS_SECRET)"Alamofire.request(.GET, discogsURL).responseJSON { response invar json = JSON(response.result.value!)let albumArtistTitle = "\(json["results"][0]["title"])"let albumYear = "\(json["results"][0]["year"])"self.dataService.ALBUM_FROM_DISCOGS = albumArtistTitleself.dataService.YEAR_FROM_DISCOGS = albumYear// Post a notification to let AlbumDetailsViewController know we have some data.NSNotificationCenter.defaultCenter().postNotificationName("AlbumNotification", object: nil)}
}}

The Album Model

Album.swift模型中,共有两个属性分别是,albumyear,用artistAlbumalbumYear两个参数来初始化对象的两个数值,代码如下:

import Foundationclass Album {        private(set) var album: String!
private(set) var year: String!init(artistAlbum: String, albumYear: String) {// Add a little extra text to the album informationself.album = "Album: \n\(artistAlbum)"self.year = "Released in: \(albumYear)"
}}

Time to Show Album Data!

viewDidLoad()中,需要处理获取到的通知,添加观察者用于接收通知,代码如下:

deinit {NSNotificationCenter.defaultCenter().removeObserver(self)
}override func viewDidLoad() {super.viewDidLoad()artistAlbumLabel.text = "Let's scan an album!"yearLabel.text = ""NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(setLabels(_:)), name: "AlbumNotification", object: nil)
}

当通知接收到的时候,setLabels()会被调用,就会初始化Album专辑信息通过DataService.swift数据的改变。

func setLabels(notification: NSNotification){// Use the data from DataService.swift to initialize the Album.let albumInfo = Album(artistAlbum: DataService.dataService.ALBUM_FROM_DISCOGS, albumYear: DataService.dataService.YEAR_FROM_DISCOGS)artistAlbumLabel.text = "\(albumInfo.album)"yearLabel.text = "\(albumInfo.year)"
}

Testing CDBarcodes

好了,我们已经完成了所有的工作,可以开始测试App了,完整代码下载地址:CDBarcodes,总的来说,原始文章废话有点多,但写的是特别的基础,这点对于新手还是比较不错的。下面还有一些说明,就没翻译了,和技术实现没什么关系!

Swift语言编写一个简单的条形码扫描APP相关推荐

  1. c语言编写一个简单的答题系统

    利用c语言编写一个简单的答题系统. 思路是先设计好题目和答案,再输入自己的答案,利用输入的答案与正确答案对比,从而得出你回答的对错. (一)捆绑题目和答案 我们可以利用结构体对一个题目捆绑上一个答案. ...

  2. C语言编写一个简单的扫雷

    C语言编写一个简单的扫雷 # include <stdio.h> # include <stdlib.h> # include <math.h> # include ...

  3. 使用Flutter编写一个简单的天气查询App

    使用Flutter编写一个简单的天气查询App Flutter项目目录分析 入口函数 home:主页面 编写天气应用 网络请求 数据解析 布局编写 Flutter里基础的Widget 上 中 下 Fl ...

  4. 用 C 语言编写一个简单的垃圾回收器

    人们似乎认为编写垃圾回收机制是很难的,是一种只有少数智者和Hans Boehm(et al)才能理解的高深魔法.我认为编写垃圾回收最难的地方就是内存分配,这和阅读K&R所写的malloc样例难 ...

  5. python语言的记事本在哪_用python语言编写一个简单记事本

    看了一点python的基础教程,忍不住手就痒了,找来一个题目练一下喽. 题目:编写一个功能简单的记事本. 编写记事本就要用到GUI的功能,最常用的当然是wxpython,那么我们就用这个来写一个记事本 ...

  6. 用C语言编写一个“简单”的程序答题系统

    上个星期我们老师给我们布置一道他认为很简单的题,其实就想考考我们,要我们写一个简单的答题系统.开始一看只有一道题我直呼:"仰天大笑出门去,我辈岂是蓬蒿人" 以为老师放我一马,结果点 ...

  7. 用GO语言编写一个简单的区块链

    区块链的大致概念. 按照个人理解来说,区块,就是保存一个一个数据的模块,然后区块链,是每个区块相连的链表那种,同时区块链实现之所以公平,是采用加密,且不可倒置等的机制,也就是,数据只要成功加载到区块链 ...

  8. linux编写一个简单的端口扫描程序,小弟我在linux下写了个简单的多线程端口扫描程序,运行时出现有关问题,请问一下(2)...

    当前位置:我的异常网» Linux/Unix » 小弟我在linux下写了个简单的多线程端口扫描程序, 小弟我在linux下写了个简单的多线程端口扫描程序,运行时出现有关问题,请问一下(2) www. ...

  9. 【无标题】C语言编写一个简单答题系统

    这是蒟蒻写的第一个博客,将就看看吧! 首先,我写的是一个填空题答题系统,填空题数目为20. 其次,需要随机出题,题目出现顺序要不一致. (1) 产生随机数 1~20 (2)  解决运气不好的问题1-1 ...

  10. c语言整点报时,C语言编写一个简单整点报时工具源代码

    (1)用数字逻辑集成块实现: (2)时间以24小时为一个周期,显示时.分.秒: (3)计时过程具有报时功能,当时间到达整点前5秒进行蜂鸣报时: (4)为了保证计时的稳定及准确须由晶体振荡器提供表针时间 ...

最新文章

  1. 20-flutter下拉刷新与上拉加载
  2. 服务差,信号不好真的是联通用户下滑的原因吗?
  3. iqooz1手机能搭载鸿蒙吗,我最近看中2款手机,iQOOZ1x和荣耀30青春版选谁更好?你们知道吗...
  4. java sql变更跟踪_如何使用Spring动态跟踪数据库更改?
  5. 【图论】【斜率优化】前往大都会(loj 2769)
  6. [置顶] 再谈学习方法
  7. java生成flash_针对 Flash 开发者的最新 Capuchin 计划资源
  8. 服务器硬件oid,HPE ProLiant DL580 Gen10 服务器
  9. 开发VR游戏的基本要求
  10. java窗体与Flash交互
  11. ListView实现多种item布局的方法和注意事项
  12. file.delete删除不了文件_非常实用的文件服务系统
  13. 数据库sql创建标量值函数_使用JSON_VALUE()从JSON数据中提取标量值
  14. Go编程笔记(28)
  15. 笔记本打开计算机,笔记本打开黑屏怎么办_笔记本电脑开机黑屏的解决步骤-win7之家...
  16. java 工资如何_Java编写员工薪资表
  17. .join()用法 | python学习
  18. 1.1 机器人学之空间描述和变换
  19. 苹果6手机服务器停止响应,iphone6被停用怎么办?苹果6被停用解决方法汇总
  20. tab s2 android 8,mini 3一边去!三星GalaxyTab S2 8.0评测

热门文章

  1. (三)五款常用的java开发工具(快来看看吧)
  2. 知识分享 | 卡方分析的入门小知识
  3. XTUOJ-1281-Cute String
  4. 解决问题#Word导出PDF出现空白页
  5. 计算机PS属性怎么改,如何更改ps设计图尺寸
  6. java无法解析类型数据,”无法解析类型 这是简介引用的类文件要求 从必需的 .class 文件间接引用了“——解决方法...
  7. MATLAB对数坐标图和统计图(semilogy/loglog)
  8. 《赖氏经典英语语法》第三集
  9. Android以太网框架情景分析之NetworkManagementService和netd交互深入分析二
  10. 关查找我的iphone时显示服务器连接超时,iPhone 屏幕镜像无法关闭,一直显示“正在查找 Apple TV”怎么办?...