在开启这个旅程以前, 请记住, AVFoundation是一个复杂的工具. 在不少状况下, 我咱们使用苹果默认的API(好比:UIImagePickerController)就足够了. git
在您阅读以前, 请确保您确实使用过AVFoundationgithub
因为swift 版本不一样, 你可能在XCode上面编写时候部分语法有差别,不过相信广大小伙伴们都是能够简单应对的.😆😆😆swift
回话, 设备, 输入和输出api
拍摄照片和视频的核心是CaptureSession(捕获回话). 在苹果的介绍中捕获回话是"an object that manages capture activity and coordinates the flow of data from input devices to capture outputs." 一种管理捕获活动并协调来自输入设备的数据流以捕获输出的对象。另外, 捕获设备用于实际的iOS设备上可用的物理音频和视频捕获设备(即摄像头和麦克风), 若是要使用AVFoundation须要咱们捕获设备(即获取摄像头和麦克风对象).数组
而后经过捕获输入, 提供给回话对象, 在将结果保存在输出中. 通俗说就是同涉嫌头(输入对象) 将拍摄的结果提供给会对对象, 在由回话对象将结果显示屏幕或者其余输出对象中安全
而后在将结果保存在捕获的对象. session
示例图:框架
示例项目异步
若是你想经过本身的手来探索框架, 请您在实例项目上工做, 可是为了让咱们专一于讨论AVFoundation框架, 我附带了一个入门项目, 在继续以前, 请点击下载并快速查看.async
示例项目是当前项目的基础, 里面包含了:
1. Assets.xcassets 包含咱们项目所须要的必要的图像文件. 声明:这些图片来自于互联网. 若是有涉及侵权, 请联系我, 我将第一时间予以删除
2.里面有一个Storyboard文件. 此视图控制器将用于处理咱们的应用程序内全部图片和视频的拍摄
3.一个ViewController控制器,用于处理交互
以下图
好的, 咱们开始吧!
在此咱们将设计一个CameraController, 负责完成拍摄照片和视频录制有关的工做
请在咱们的项目中声明一个类 CameraController 类, 继承NSObject
1 import AVFoundation 2 3 class CameraController: NSObject { }
照片拍摄
首先,咱们将使用后置摄像头实现照片捕捉功能。这将是咱们的基本功能,咱们将添加切换相机,使用闪光灯,并添加到咱们的照片捕捉功能录制视频的能力。因为配置和启动捕获会话是一个相对密集的过程,咱们将解耦它init
并建立一个叫作prepare的函数,准备捕获会话以供使用,并在完成时调用完成处理程序。
1 2 func prepare(completionHandler: @escaping (Error?) -> Void) { }
这个函数将处理新捕获会话的建立和配置。请记住,设置捕获会话由4个步骤组成:
咱们将使用Swift的嵌套函数以可管理的方式封装咱们的代码。首先声明4个空函数prepare
,而后调用它们:
1 func prepare(completionHandler: @escaping (Error?) -> Void) { 2 func createCaptureSession() { } 3 func configureCaptureDevices() throws { } 4 func configureDeviceInputs() throws { } 5 func configurePhotoOutput() throws { } 6 7 DispatchQueue(label: "prepare").async { 8 do { 9 createCaptureSession() 10 try configureCaptureDevices() 11 try configureDeviceInputs() 12 try configurePhotoOutput() 13 } 14 15 catch { 16 DispatchQueue.main.async { 17 completionHandler(error) 18 } 19 20 return 21 } 22 23 DispatchQueue.main.async { 24 completionHandler(nil) 25 } 26 } 27 }
在上面的代码中,咱们建立了样板函数来执行准备AVCaptureSession
照片捕捉的4个关键步骤。咱们还设置了一个异步执行的块,调用这四个函数,必要时捕获任何错误,而后调用完成处理程序。咱们所要作的就是实现这四个功能!咱们开始吧createCaptureSession
。
配置给定以前AVCaptureSession
,咱们须要建立它!将如下属性添加到您的CameraController.swift
文件中:
var captureSession: AVCaptureSession?
接下来,将如下内容添加到createCaptureSession
嵌套在您的函数的主体中prepare
:
self.captureSession = AVCaptureSession()
这是简单的代码; 它只是建立一个新的AVCaptureSession
并将其存储在captureSession
属性中。
如今咱们已经建立了一个AVCaptureSession
,咱们须要建立AVCaptureDevice
对象来表示实际的iOS设备的摄像头。继续并将如下属性添加到您的CameraController
班级。咱们如今要添加frontCamera
和rearCamera
属性,由于咱们将设置多摄像头捕获的基础知识,并实现稍后更改摄像头的功能。
1 var frontCamera: AVCaptureDevice? 2 var rearCamera: AVCaptureDevice?
接下来,在里面声明一个嵌入的类型CameraController.swift
。咱们将使用此嵌入式类型来管理建立捕获会话时可能遇到的各类错误:
enum CameraControllerError: Swift.Error { case captureSessionAlreadyRunning case captureSessionIsMissing case inputsAreInvalid case invalidOperation case noCamerasAvailable case unknown }
如今谈到有趣的部分!让咱们找到设备上可用的相机。咱们能够这样作AVCaptureDeviceDiscoverySession
。将如下内容添加到configureCaptureDevices
:
1 //1 2 let session = AVCaptureDeviceDiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaTypeVideo, position: .unspecified) 3 guard let cameras = (session?.devices.flatMap { $0 }), !cameras.isEmpty else { throw CameraControllerError.noCamerasAvailable } 4 5 //2 6 for camera in cameras { 7 if camera.position == .front { 8 self.frontCamera = camera 9 } 10 11 if camera.position == .back { 12 self.rearCamera = camera 13 14 try camera.lockForConfiguration() 15 camera.focusMode = .continuousAutoFocus 16 camera.unlockForConfiguration() 17 } 18 }
这就是咱们刚刚作的:
AVCaptureDeviceDiscoverySession
查找当前设备上可用的全部广角相机,并将其转换为非可选AVCaptureDevice
实例的数组。若是没有相机可用,咱们会抛出一个错误。咱们曾经AVCaptureDeviceDiscoverySession
在设备上找到可用的摄像机,并将其配置为符合咱们的规格。让咱们将它们链接到咱们的捕获会话。
如今咱们能够建立捕获设备输入,捕获设备并将它们链接到咱们的捕获会话。在咱们这样作以前,添加如下属性CameraController
以确保咱们能够存储咱们的输入:
1 var currentCameraPosition: CameraPosition? 2 var frontCameraInput: AVCaptureDeviceInput? 3 var rearCameraInput: AVCaptureDeviceInput?
咱们的代码不会在这个状态下编译,由于CameraPosition
没有定义。咱们来定义它。将其添加为如下内嵌类型CameraController
:
1 public enum CameraPosition { 2 case front 3 case rear 4 }
如今,咱们拥有存储和管理捕获设备输入的全部必要特性。咱们来实现configureDeviceInputs
:
1 func configureDeviceInputs() throws { 2 //3 3 guard let captureSession = self.captureSession else { throw CameraControllerError.captureSessionIsMissing } 4 5 //4 6 if let rearCamera = self.rearCamera { 7 self.rearCameraInput = try AVCaptureDeviceInput(device: rearCamera) 8 9 if captureSession.canAddInput(self.rearCameraInput!) { captureSession.addInput(self.rearCameraInput!) } 10 11 self.currentCameraPosition = .rear 12 } 13 14 else if let frontCamera = self.frontCamera { 15 self.frontCameraInput = try AVCaptureDeviceInput(device: frontCamera) 16 17 if captureSession.canAddInput(self.frontCameraInput!) { captureSession.addInput(self.frontCameraInput!) } 18 else { throw CameraControllerError.inputsAreInvalid } 19 20 self.currentCameraPosition = .front 21 } 22 23 else { throw CameraControllerError.noCamerasAvailable } 24 }
如下是咱们所作的:
captureSession
存在。若是没有,咱们会抛出一个错误。if
声明负责建立必要的捕捉设备输入以支持照片捕捉。AVFoundation
每次捕捉会话只容许一个基于摄像头的输入。因为后置摄像头传统上是默认的,所以咱们尝试从中建立输入并将其添加到捕获会话中。若是失败了,咱们会回到前置摄像头。若是失败了,咱们会抛出一个错误。直到这一点,咱们已经添加了全部必要的输入captureSession
。如今咱们只须要一种方法从捕获会话中获取必要的数据。幸运的是,咱们有AVCapturePhotoOutput
。添加一个属性到CameraController
:
var photoOutput: AVCapturePhotoOutput?
如今,咱们来实现configurePhotoOutput
这个:
1 func configurePhotoOutput() throws { 2 guard let captureSession = self.captureSession else { throw CameraControllerError.captureSessionIsMissing } 3 4 self.photoOutput = AVCapturePhotoOutput() 5 self.photoOutput!.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey : AVVideoCodecJPEG])], completionHandler: nil) 6 7 if captureSession.canAddOutput(self.photoOutput) { captureSession.addOutput(self.photoOutput) } 8 9 captureSession.startRunning() 10 }
这是一个简单的实现。它只是配置photoOutput
,告诉它使用JPEG文件格式的视频编解码器。而后,它增长photoOutput
了captureSession
。最后,它开始captureSession
。
咱们差很少完成了!你的CameraController.swift
文件应该看起来像这样:
1 import AVFoundation 2 3 class CameraController { 4 var captureSession: AVCaptureSession? 5 6 var currentCameraPosition: CameraPosition? 7 8 var frontCamera: AVCaptureDevice? 9 var frontCameraInput: AVCaptureDeviceInput? 10 11 var photoOutput: AVCapturePhotoOutput? 12 13 var rearCamera: AVCaptureDevice? 14 var rearCameraInput: AVCaptureDeviceInput? 15 } 16 17 extension CameraController { 18 func prepare(completionHandler: @escaping (Error?) -> Void) { 19 func createCaptureSession() { 20 self.captureSession = AVCaptureSession() 21 } 22 23 func configureCaptureDevices() throws { 24 let session = AVCaptureDeviceDiscoverySession(deviceTypes: [.builtInWideAngleCamera], mediaType: AVMediaTypeVideo, position: .unspecified) 25 guard let cameras = (session?.devices.flatMap { $0 }), !cameras.isEmpty else { throw CameraControllerError.noCamerasAvailable } 26 27 for camera in cameras { 28 if camera.position == .front { 29 self.frontCamera = camera 30 } 31 32 if camera.position == .back { 33 self.rearCamera = camera 34 35 try camera.lockForConfiguration() 36 camera.focusMode = .autoFocus 37 camera.unlockForConfiguration() 38 } 39 } 40 } 41 42 func configureDeviceInputs() throws { 43 guard let captureSession = self.captureSession else { throw CameraControllerError.captureSessionIsMissing } 44 45 if let rearCamera = self.rearCamera { 46 self.rearCameraInput = try AVCaptureDeviceInput(device: rearCamera) 47 48 if captureSession.canAddInput(self.rearCameraInput!) { captureSession.addInput(self.rearCameraInput!) } 49 50 self.currentCameraPosition = .rear 51 } 52 53 else if let frontCamera = self.frontCamera { 54 self.frontCameraInput = try AVCaptureDeviceInput(device: frontCamera) 55 56 if captureSession.canAddInput(self.frontCameraInput!) { captureSession.addInput(self.frontCameraInput!) } 57 else { throw CameraControllerError.inputsAreInvalid } 58 59 self.currentCameraPosition = .front 60 } 61 62 else { throw CameraControllerError.noCamerasAvailable } 63 } 64 65 func configurePhotoOutput() throws { 66 guard let captureSession = self.captureSession else { throw CameraControllerError.captureSessionIsMissing } 67 68 self.photoOutput = AVCapturePhotoOutput() 69 self.photoOutput!.setPreparedPhotoSettingsArray([AVCapturePhotoSettings(format: [AVVideoCodecKey : AVVideoCodecJPEG])], completionHandler: nil) 70 71 if captureSession.canAddOutput(self.photoOutput) { captureSession.addOutput(self.photoOutput) } 72 captureSession.startRunning() 73 } 74 75 DispatchQueue(label: "prepare").async { 76 do { 77 createCaptureSession() 78 try configureCaptureDevices() 79 try configureDeviceInputs() 80 try configurePhotoOutput() 81 } 82 83 catch { 84 DispatchQueue.main.async { 85 completionHandler(error) 86 } 87 88 return 89 } 90 91 DispatchQueue.main.async { 92 completionHandler(nil) 93 } 94 } 95 } 96 } 97 98 extension CameraController { 99 enum CameraControllerError: Swift.Error { 100 case captureSessionAlreadyRunning 101 case captureSessionIsMissing 102 case inputsAreInvalid 103 case invalidOperation 104 case noCamerasAvailable 105 case unknown 106 } 107 108 public enum CameraPosition { 109 case front 110 case rear 111 } 112 }
注意:我使用扩展来适当地分割代码。您能够根据我的的编码风格定义,但我认为这是一个很好的作法,由于它使您的代码更易于读写。
如今咱们已经准备好相机设备了,如今是时候显示它在屏幕上捕捉的内容了。添加另外一个函数CameraController
(在prepare
)以外,称之为displayPreview
。它应该有如下签名:
func displayPreview(on view: UIView) throws { }
另外,import UIKit
在你的CameraController.swift
文件中。咱们将须要它来处理UIView
。
顾名思义,这个函数将负责建立一个捕获预览并在提供的视图上显示它。让咱们添加一个属性CameraController
来支持这个功能:
var previewLayer: AVCaptureVideoPreviewLayer?
该属性将保存显示输出的预览图层captureSession
。咱们来实现这个方法:
1 func displayPreview(on view: UIView) throws { 2 guard let captureSession = self.captureSession, captureSession.isRunning else { throw CameraControllerError.captureSessionIsMissing } 3 4 self.previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) 5 self.previewLayer?.videoGravity = AVLayerVideoGravityResizeAspectFill 6 self.previewLayer?.connection?.videoOrientation = .portrait 7 8 view.layer.insertSublayer(self.previewLayer!, at: 0) 9 self.previewLayer?.frame = view.frame 10 }
此功能建立一个AVCaptureVideoPreview
使用captureSession
,将其设置为纵向,并将其添加到提供的视图。
如今,让咱们尝试将全部这些链接到咱们的视图控制器。头向上ViewController.swift
。首先,添加一个属性ViewController.swift
:
let cameraController = CameraController()
而后,添加一个嵌套函数viewDidLoad():
1 func configureCameraController() { 2 cameraController.prepare {(error) in 3 if let error = error { 4 print(error) 5 } 6 7 try? self.cameraController.displayPreview(on: self.capturePreviewView) 8 } 9 } 10 11 configureCameraController()
这个功能简单地准备咱们的相机控制器,就像咱们设计的那样。
不幸的是,咱们还有一步。这是苹果强制执行的安全要求。你必须为用户提供一个理由,解释为何你的应用程序须要使用相机。打开Info.plist
并插入一行:
Privacy - Camera Usage Description
这个键告诉用户当它要求必要的权限时为何使用相机。
你的ViewController.swift
文件如今应该是这样的:
1 import UIKit 2 3 class ViewController: UIViewController { 4 let cameraController = CameraController() 5 6 @IBOutlet fileprivate var captureButton: UIButton! 7 8 ///显示设备摄像机生成的视频输出的预览 9 @IBOutlet fileprivate var capturePreviewView: UIView! 10 11 ///容许用户将相机置于照片模式下。 12 @IBOutlet fileprivate var photoModeButton: UIButton! 13 @IBOutlet fileprivate var toggleCameraButton: UIButton! 14 @IBOutlet fileprivate var toggleFlashButton: UIButton! 15 16 //容许用户将摄像机置于视频模式中。 17 @IBOutlet fileprivate var videoModeButton: UIButton! 18 19 override var prefersStatusBarHidden: Bool { return true } 20 } 21 22 extension ViewController { 23 override func viewDidLoad() { 24 func configureCameraController() { 25 cameraController.prepare {(error) in 26 if let error = error { 27 print(error) 28 } 29 30 try? self.cameraController.displayPreview(on: self.capturePreviewView) 31 } 32 } 33 34 func styleCaptureButton() { 35 captureButton.layer.borderColor = UIColor.black.cgColor 36 captureButton.layer.borderWidth = 2 37 38 captureButton.layer.cornerRadius = min(captureButton.frame.width, captureButton.frame.height) / 2 39 } 40 41 styleCaptureButton() 42 configureCameraController() 43 } 44 }
编译并运行你的项目,当系统提示是否容许使用相机时候点击容许,而后你应该有一个工做捕捉预览。若是没有,请从新检查您的代码,若是您须要帮助,请留下评论。
没错,今天深圳的天气仍是挺好的.北方的小伙伴大家那里天气好吗? 😁😁😁
如今咱们有一个工做预览,让咱们添加更多的功能。大多数相机应用程序容许用户切换相机并启用或禁用闪光灯。让咱们也作这个。咱们这样作后,咱们将添加捕捉图像并将其保存到相机胶卷的功能。
首先,咱们将启用切换闪光灯的功能。将此属性添加到CameraController:
var flashMode = AVCaptureFlashMode.off
如今,转到ViewController
。添加一个@IBAction func
切换闪光灯:
1 @IBAction func toggleFlash(_ sender: UIButton) { 2 if cameraController.flashMode == .on { 3 cameraController.flashMode = .off 4 toggleFlashButton.setImage(#imageLiteral(resourceName: "Flash Off Icon"), for: .normal) 5 } 6 7 else { 8 cameraController.flashMode = .on 9 toggleFlashButton.setImage(#imageLiteral(resourceName: "Flash On Icon"), for: .normal) 10 } 11 }
如今,这就是咱们所要作的。咱们的CameraController
类将处理闪光灯时,咱们捕捉图像。让咱们继续转换摄像机。
在AV基础上切换摄像头是一件很是容易的事情。咱们只须要删除现有摄像头的捕捉输入,并为咱们要切换的摄像头添加一个新的捕捉输入。让咱们添加另外一个功能,咱们的CameraController
切换摄像机:
func switchCameras() throws { }
当咱们切换摄像头时,咱们要么切换到前置摄像头,要么切换到后置摄像头。因此,咱们在下面声明2个嵌套函数switchCameras
:
1 func switchToFrontCamera() throws { } 2 func switchToRearCamera() throws { }
如今,添加如下内容switchCameras()
:
1 //5 2 guard let currentCameraPosition = currentCameraPosition, let captureSession = self.captureSession, captureSession.isRunning else { throw CameraControllerError.captureSessionIsMissing } 3 4 //6 5 captureSession.beginConfiguration() 6 7 func switchToFrontCamera() throws { } 8 func switchToRearCamera() throws { } 9 10 //7 11 switch currentCameraPosition { 12 case .front: 13 try switchToRearCamera() 14 15 case .rear: 16 try switchToFrontCamera() 17 } 18 19 //8 20 captureSession.commitConfiguration()
这就是咱们刚刚作的:
guard
声明确保在尝试切换摄像机以前咱们有一个有效的正在运行的捕获会话。它还验证是否有一个当前活动的摄像头。switch
语句调用switchToRearCamera
或者switchToFrontCamera
,取决于哪一个摄像头当前处于活动状态。咱们如今要作的就是实现switchToFrontCamera
和switchToRearCamera
:
1 func switchToFrontCamera() throws { 2 guard let inputs = captureSession.inputs as? [AVCaptureInput], let rearCameraInput = self.rearCameraInput, inputs.contains(rearCameraInput), 3 let frontCamera = self.frontCamera else { throw CameraControllerError.invalidOperation } 4 5 self.frontCameraInput = try AVCaptureDeviceInput(device: frontCamera) 6 7 captureSession.removeInput(rearCameraInput) 8 9 if captureSession.canAddInput(self.frontCameraInput!) { 10 captureSession.addInput(self.frontCameraInput!) 11 12 self.currentCameraPosition = .front 13 } 14 15 else { throw CameraControllerError.invalidOperation } 16 } 17 18 func switchToRearCamera() throws { 19 guard let inputs = captureSession.inputs as? [AVCaptureInput], let frontCameraInput = self.frontCameraInput, inputs.contains(frontCameraInput), 20 let rearCamera = self.rearCamera else { throw CameraControllerError.invalidOperation } 21 22 self.rearCameraInput = try AVCaptureDeviceInput(device: rearCamera) 23 24 captureSession.removeInput(frontCameraInput) 25 26 if captureSession.canAddInput(self.rearCameraInput!) { 27 captureSession.addInput(self.rearCameraInput!) 28 29 self.currentCameraPosition = .rear 30 } 31 32 else { throw CameraControllerError.invalidOperation } 33 }
两个函数都有很是类似的实现。他们首先得到捕获会话中全部输入的数组,并确保能够切换到请求相机。接下来,他们建立必要的输入设备,删除旧的,并添加新的。最后,他们设定currentCameraPosition
让CameraController
班级知道变化。简单!回到ViewController.swift
咱们能够添加一个功能来切换相机:
1 @IBAction func switchCameras(_ sender: UIButton) { 2 do { 3 try cameraController.switchCameras() 4 } 5 6 catch { 7 print(error) 8 } 9 10 switch cameraController.currentCameraPosition { 11 case .some(.front): 12 toggleCameraButton.setImage(#imageLiteral(resourceName: "Front Camera Icon"), for: .normal) 13 14 case .some(.rear): 15 toggleCameraButton.setImage(#imageLiteral(resourceName: "Rear Camera Icon"), for: .normal) 16 17 case .none: 18 return 19 } 20 }
打开你的故事板,链接必要的插座,并构建和运行应用程序。你应该能够自由切换相机。如今咱们来实现最重要的功能:图像捕捉!
如今咱们能够实现咱们一直在等待的功能:图像捕捉。在咱们进入以前,让咱们快速回顾一下迄今为止所作的一切:
UIViewController
并创建一个轻量级的相机应用程序。咱们所要作的只是捕捉图像!
打开CameraController.swift
,让咱们开始工做。captureImage
用这个签名添加一个函数:
1 func captureImage(completion: (UIImage?, Error?) -> Void) { 2 3 }
顾名思义,这个功能将会使用咱们制做的相机控制器为咱们拍摄一张图像。让咱们来实现它:
1 func captureImage(completion: @escaping (UIImage?, Error?) -> Void) { 2 guard let captureSession = captureSession, captureSession.isRunning else { completion(nil, CameraControllerError.captureSessionIsMissing); return } 3 4 let settings = AVCapturePhotoSettings() 5 settings.flashMode = self.flashMode 6 7 self.photoOutput?.capturePhoto(with: settings, delegate: self) 8 self.photoCaptureCompletionBlock = completion 9 }
这不是一个复杂的实现,但咱们的代码还不能编译,由于咱们没有定义photoCaptureCompletionBlock
和CameraController
不符合AVCapturePhotoCaptureDelegate
。首先,咱们添加一个属性photoCaptureCompletionBlock
来CameraController
:
var photoCaptureCompletionBlock: ((UIImage?, Error?) -> Void)?
如今,咱们来扩展CameraController
以符合AVCapturePhotoCaptureDelegate:
1 extension CameraController: AVCapturePhotoCaptureDelegate { 2 public func capture(_ captureOutput: AVCapturePhotoOutput, didFinishProcessingPhotoSampleBuffer photoSampleBuffer: CMSampleBuffer?, previewPhotoSampleBuffer: CMSampleBuffer?, 3 resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Swift.Error?) { 4 if let error = error { self.photoCaptureCompletionBlock?(nil, error) } 5 6 else if let buffer = photoSampleBuffer, let data = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: buffer, previewPhotoSampleBuffer: nil), 7 let image = UIImage(data: data) { 8 9 self.photoCaptureCompletionBlock?(image, nil) 10 } 11 12 else { 13 self.photoCaptureCompletionBlock?(nil, CameraControllerError.unknown) 14 } 15 } 16 }
如今回头再来ViewController
一次。首先,导入Photos
框架,由于咱们将使用内置的API来保存照片。
import Photos
而后插入如下函数:
1 @IBAction func captureImage(_ sender: UIButton) { 2 cameraController.captureImage {(image, error) in 3 guard let image = image else { 4 print(error ?? "Image capture error") 5 return 6 } 7 8 try? PHPhotoLibrary.shared().performChangesAndWait { 9 PHAssetChangeRequest.creationRequestForAsset(from: image) 10 } 11 } 12 }
咱们只需调用captureImage
相机控制器的方法来拍摄照片,而后使用PHPhotoLibary
该类将图像保存到内置的照片库中。
最后,链接@IBAction func
到故事板中的捕获按钮,而后Info.plist
转到插入一行:
Privacy - Camera Usage Description
这是iOS 10中引入的隐私要求。您必须指定您的应用程序须要访问照片库的缘由。
如今创建并运行应用程序来捕捉照片!以后,打开你的照片库。你应该看到你刚刚拍摄的照片。恭喜,你如今知道如何在您的应用程序中使用AV基金会!祝你好运,并继续关注本教程的第二部分,咱们将学习如何捕获视频。
对于完整的项目,你能够点击下载
特此声明:以上全部信息仅仅提供学习使用, 部分功能若是能够帮助你解决项目中的问题, 我也很开心. 后面我也会将录制视频的功能完善上去.
一个就任于汽车物联网公司的 iOS 开发者