{"id":3322,"date":"2021-06-30T14:19:00","date_gmt":"2021-06-30T06:19:00","guid":{"rendered":"http:\/\/123.57.164.21\/?p=3322"},"modified":"2021-06-30T14:19:00","modified_gmt":"2021-06-30T06:19:00","slug":"swift-%e8%a7%86%e9%a2%91%e5%bd%95%e5%88%b6%e6%95%99%e7%a8%8b1%ef%bc%88%e8%b0%83%e7%94%a8%e6%91%84%e5%83%8f%e5%a4%b4%e5%bd%95%e5%83%8f%ef%bc%8c%e5%b9%b6%e4%bf%9d%e5%ad%98%e5%88%b0%e7%b3%bb%e7%bb%9f","status":"publish","type":"post","link":"https:\/\/92it.top\/?p=3322","title":{"rendered":"Swift &#8211; \u89c6\u9891\u5f55\u5236\u6559\u7a0b1\uff08\u8c03\u7528\u6444\u50cf\u5934\u5f55\u50cf\uff0c\u5e76\u4fdd\u5b58\u5230\u7cfb\u7edf\u76f8\u518c\uff09"},"content":{"rendered":"\n<p><strong>1\uff0c\u6280\u672f\u4ecb\u7ecd<\/strong><\/p>\n\n\n\n<ul><li>\uff081\uff09AVFoundation.framework \u6846\u67b6\u63d0\u4f9b\u4e86 AVCaptureSession \u7c7b\u3002\u4f7f\u7528\u5b83\u53ef\u4ee5\u5b9e\u73b0\u89c6\u9891\u6355\u83b7\u529f\u80fd\u3002<\/li><li>\uff082\uff09\u4f7f\u7528 AVCaptureVideoPreviewLayer \u53ef\u4ee5\u5c06\u6444\u50cf\u5934\u62cd\u6444\u7684\u753b\u9762\u5b9e\u65f6\u663e\u793a\u5728 ViewController \u4e0a\u3002<\/li><li>\uff083\uff09\u5bf9\u4e8e\u6355\u83b7\u5230\u7684\u89c6\u9891\uff0c\u6211\u4eec\u4f7f\u7528 AVCaptureMovieFileOutput \u5c06\u5176\u8f93\u51fa\u5230\u6587\u4ef6\u4e2d\u3002<\/li><\/ul>\n\n\n\n<p><strong>2\uff0c\u4e0b\u9762\u5b9e\u73b0\u4e00\u4e2a\u5f55\u50cf\u529f\u80fd<\/strong><\/p>\n\n\n\n<ul><li>\uff081\uff09\u70b9\u51fb\u201c\u5f00\u59cb\u201d\u6309\u94ae\uff0c\u5f00\u59cb\u5f55\u5236\u89c6\u9891\u3002\u9ed8\u8ba4\u5148\u4fdd\u5b58\u5230 Documents \u76ee\u5f55\u4e0b\uff0c\u547d\u540d\u4e3a temp.mp4\u3002<\/li><li>\uff082\uff09\u70b9\u51fb\u201c\u505c\u6b62\u201d\u6309\u94ae\uff0c\u505c\u6b62\u89c6\u9891\u5f55\u5236\u3002\u5c06\u5f55\u5236\u597d\u7684\u5f55\u50cf\u518d\u8f6c\u5b58\u5230\u7cfb\u7edf\u7167\u7247\u5e93\u4e2d\u3002<\/li><\/ul>\n\n\n\n<p><strong>3\uff0c\u6548\u679c\u56fe\u5982\u4e0b\uff1a<\/strong><\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2021\/06\/image-87-1024x603.png\" alt=\"\" class=\"wp-image-3323\" width=\"614\" height=\"361\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2021\/06\/image-87-1024x603.png 1024w, https:\/\/92it.top\/wp-content\/uploads\/2021\/06\/image-87-300x177.png 300w, https:\/\/92it.top\/wp-content\/uploads\/2021\/06\/image-87-768x452.png 768w, https:\/\/92it.top\/wp-content\/uploads\/2021\/06\/image-87-830x489.png 830w, https:\/\/92it.top\/wp-content\/uploads\/2021\/06\/image-87-230x135.png 230w, https:\/\/92it.top\/wp-content\/uploads\/2021\/06\/image-87-350x206.png 350w, https:\/\/92it.top\/wp-content\/uploads\/2021\/06\/image-87-480x283.png 480w, https:\/\/92it.top\/wp-content\/uploads\/2021\/06\/image-87.png 1522w\" sizes=\"(max-width: 614px) 100vw, 614px\" \/><\/figure><\/div>\n\n\n\n<p><strong>4\uff0cInfo.plist \u914d\u7f6e\u00a0<\/strong><\/p>\n\n\n\n<p>\u7531\u4e8e\u82f9\u679c\u5b89\u5168\u7b56\u7565\u66f4\u65b0\uff0c\u5728\u4f7f\u7528\u00a0<strong>Xcode8\u00a0<\/strong>\u5f00\u53d1\u65f6\uff0c\u9700\u8981\u5728\u00a0<strong>Info.plist<\/strong>\u00a0\u914d\u7f6e\u8bf7\u6c42\u6444\u50cf\u5934\u3001\u9ea6\u514b\u98ce\u3001\u76f8\u518c\u6743\u9650\u7684\u63cf\u8ff0\u5b57\u6bb5\uff1a\u00a0<\/p>\n\n\n\n<ul><li><strong>Privacy &#8211; Camera Usage Description<\/strong><\/li><li><strong>Privacy &#8211; Microphone Usage Description<\/strong><\/li><li><strong>Privacy &#8211; Photo Library Usage Description<\/strong><\/li><\/ul>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/123.57.164.21\/wp-content\/uploads\/2021\/06\/image-88-1024x745.png\" alt=\"\" class=\"wp-image-3324\" width=\"548\" height=\"399\" srcset=\"https:\/\/92it.top\/wp-content\/uploads\/2021\/06\/image-88-1024x745.png 1024w, https:\/\/92it.top\/wp-content\/uploads\/2021\/06\/image-88-300x218.png 300w, https:\/\/92it.top\/wp-content\/uploads\/2021\/06\/image-88-768x559.png 768w, https:\/\/92it.top\/wp-content\/uploads\/2021\/06\/image-88-830x604.png 830w, https:\/\/92it.top\/wp-content\/uploads\/2021\/06\/image-88-550x400.png 550w, https:\/\/92it.top\/wp-content\/uploads\/2021\/06\/image-88-230x167.png 230w, https:\/\/92it.top\/wp-content\/uploads\/2021\/06\/image-88-350x255.png 350w, https:\/\/92it.top\/wp-content\/uploads\/2021\/06\/image-88-480x349.png 480w, https:\/\/92it.top\/wp-content\/uploads\/2021\/06\/image-88.png 1160w\" sizes=\"(max-width: 548px) 100vw, 548px\" \/><\/figure><\/div>\n\n\n\n<p><strong>5\uff0c\u6837\u4f8b\u4ee3\u7801<\/strong><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">import UIKit\nimport AVFoundation\nimport Photos\n \nclass ViewController: UIViewController , AVCaptureFileOutputRecordingDelegate {\n     \n    \/\/\u89c6\u9891\u6355\u83b7\u4f1a\u8bdd\u3002\u5b83\u662finput\u548coutput\u7684\u6865\u6881\u3002\u5b83\u534f\u8c03\u7740intput\u5230output\u7684\u6570\u636e\u4f20\u8f93\n    let captureSession = AVCaptureSession()\n    \/\/\u89c6\u9891\u8f93\u5165\u8bbe\u5907\n    let videoDevice = AVCaptureDevice.default(for: AVMediaType.video)\n    \/\/\u97f3\u9891\u8f93\u5165\u8bbe\u5907\n    let audioDevice = AVCaptureDevice.default(for: AVMediaType.audio)\n    \/\/\u5c06\u6355\u83b7\u5230\u7684\u89c6\u9891\u8f93\u51fa\u5230\u6587\u4ef6\n    let fileOutput = AVCaptureMovieFileOutput()\n     \n    \/\/\u5f00\u59cb\u3001\u505c\u6b62\u6309\u94ae\n    var startButton, stopButton : UIButton!\n    \/\/\u8868\u793a\u5f53\u65f6\u662f\u5426\u5728\u5f55\u50cf\u4e2d\n    var isRecording = false\n     \n    override func viewDidLoad() {\n        super.viewDidLoad()\n         \n        \/\/\u6dfb\u52a0\u89c6\u9891\u3001\u97f3\u9891\u8f93\u5165\u8bbe\u5907\n        let videoInput = try! AVCaptureDeviceInput(device: self.videoDevice!)\n        self.captureSession.addInput(videoInput)\n        let audioInput = try! AVCaptureDeviceInput(device: self.audioDevice!)\n        self.captureSession.addInput(audioInput);\n         \n        \/\/\u6dfb\u52a0\u89c6\u9891\u6355\u83b7\u8f93\u51fa\n        self.captureSession.addOutput(self.fileOutput)\n         \n        \/\/\u4f7f\u7528AVCaptureVideoPreviewLayer\u53ef\u4ee5\u5c06\u6444\u50cf\u5934\u7684\u62cd\u6444\u7684\u5b9e\u65f6\u753b\u9762\u663e\u793a\u5728ViewController\u4e0a\n        let videoLayer = AVCaptureVideoPreviewLayer(session: self.captureSession)\n        videoLayer.frame = self.view.bounds\n        videoLayer.videoGravity = AVLayerVideoGravity.resizeAspectFill\n        self.view.layer.addSublayer(videoLayer)\n         \n        \/\/\u521b\u5efa\u6309\u94ae\n        self.setupButton()\n        \/\/\u542f\u52a8session\u4f1a\u8bdd\n        self.captureSession.startRunning()\n    }\n     \n    \/\/\u521b\u5efa\u6309\u94ae\n    func setupButton(){\n        \/\/\u521b\u5efa\u5f00\u59cb\u6309\u94ae\n        self.startButton = UIButton(frame: CGRect(x:0,y:0,width:120,height:50))\n        self.startButton.backgroundColor = UIColor.red\n        self.startButton.layer.masksToBounds = true\n        self.startButton.setTitle(\"\u5f00\u59cb\", for: .normal)\n        self.startButton.layer.cornerRadius = 20.0\n        self.startButton.layer.position = CGPoint(x:self.view.bounds.width\/2 - 70,\n                                                  y:self.view.bounds.height-50)\n        self.startButton.addTarget(self, action: #selector(onClickStartButton(_:)),\n                                   for: .touchUpInside)\n         \n        \/\/\u521b\u5efa\u505c\u6b62\u6309\u94ae\n        self.stopButton = UIButton(frame: CGRect(x:0,y:0,width:120,height:50))\n        self.stopButton.backgroundColor = UIColor.gray\n        self.stopButton.layer.masksToBounds = true\n        self.stopButton.setTitle(\"\u505c\u6b62\", for: .normal)\n        self.stopButton.layer.cornerRadius = 20.0\n         \n        self.stopButton.layer.position = CGPoint(x: self.view.bounds.width\/2 + 70,\n                                                 y:self.view.bounds.height-50)\n        self.stopButton.addTarget(self, action: #selector(onClickStopButton(_:)),\n                                  for: .touchUpInside)\n         \n        \/\/\u6dfb\u52a0\u6309\u94ae\u5230\u89c6\u56fe\u4e0a\n        self.view.addSubview(self.startButton)\n        self.view.addSubview(self.stopButton)\n    }\n     \n    \/\/\u5f00\u59cb\u6309\u94ae\u70b9\u51fb\uff0c\u5f00\u59cb\u5f55\u50cf\n    @objc func onClickStartButton(_ sender: UIButton){\n        if !self.isRecording {\n            \/\/\u8bbe\u7f6e\u5f55\u50cf\u7684\u4fdd\u5b58\u5730\u5740\uff08\u5728Documents\u76ee\u5f55\u4e0b\uff0c\u540d\u4e3atemp.mp4\uff09\n            let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory,\n                                                            .userDomainMask, true)\n            let documentsDirectory = paths[0] as String\n            let filePath = \"\\(documentsDirectory)\/temp.mp4\"\n            let fileURL = URL(fileURLWithPath: filePath)\n            \/\/\u542f\u52a8\u89c6\u9891\u7f16\u7801\u8f93\u51fa\n            fileOutput.startRecording(to: fileURL, recordingDelegate: self)\n             \n            \/\/\u8bb0\u5f55\u72b6\u6001\uff1a\u5f55\u50cf\u4e2d...\n            self.isRecording = true\n            \/\/\u5f00\u59cb\u3001\u7ed3\u675f\u6309\u94ae\u989c\u8272\u6539\u53d8\n            self.changeButtonColor(target: self.startButton, color: .gray)\n            self.changeButtonColor(target: self.stopButton, color: .red)\n        }\n    }\n     \n    \/\/\u505c\u6b62\u6309\u94ae\u70b9\u51fb\uff0c\u505c\u6b62\u5f55\u50cf\n    @objc func onClickStopButton(_ sender: UIButton){\n        if self.isRecording {\n            \/\/\u505c\u6b62\u89c6\u9891\u7f16\u7801\u8f93\u51fa\n            fileOutput.stopRecording()\n             \n            \/\/\u8bb0\u5f55\u72b6\u6001\uff1a\u5f55\u50cf\u7ed3\u675f\n            self.isRecording = false\n            \/\/\u5f00\u59cb\u3001\u7ed3\u675f\u6309\u94ae\u989c\u8272\u6539\u53d8\n            self.changeButtonColor(target: self.startButton, color: .red)\n            self.changeButtonColor(target: self.stopButton, color: .gray)\n        }\n    }\n     \n    \/\/\u4fee\u6539\u6309\u94ae\u7684\u989c\u8272\n    func changeButtonColor(target: UIButton, color: UIColor){\n        target.backgroundColor = color\n    }\n     \n    \/\/\u5f55\u50cf\u5f00\u59cb\u7684\u4ee3\u7406\u65b9\u6cd5\n    func fileOutput(_ output: AVCaptureFileOutput,\n                    didStartRecordingTo fileURL: URL,\n                    from connections: [AVCaptureConnection]) {\n    }\n     \n    \/\/\u5f55\u50cf\u7ed3\u675f\u7684\u4ee3\u7406\u65b9\u6cd5\n    func fileOutput(_ output: AVCaptureFileOutput,\n                    didFinishRecordingTo outputFileURL: URL,\n                    from connections: [AVCaptureConnection], error: Error?) {\n        var message:String!\n        \/\/\u5c06\u5f55\u5236\u597d\u7684\u5f55\u50cf\u4fdd\u5b58\u5230\u7167\u7247\u5e93\u4e2d\n        PHPhotoLibrary.shared().performChanges({\n            PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: outputFileURL)\n        }, completionHandler: { (isSuccess: Bool, error: Error?) in\n            if isSuccess {\n                message = \"\u4fdd\u5b58\u6210\u529f!\"\n            } else{\n                message = \"\u4fdd\u5b58\u5931\u8d25\uff1a\\(error!.localizedDescription)\"\n            }\n             \n            DispatchQueue.main.async {\n                \/\/\u5f39\u51fa\u63d0\u793a\u6846\n                let alertController = UIAlertController(title: message, message: nil,\n                                                        preferredStyle: .alert)\n                let cancelAction = UIAlertAction(title: \"\u786e\u5b9a\", style: .cancel, handler: nil)\n                alertController.addAction(cancelAction)\n                self.present(alertController, animated: true, completion: nil)\n            }\n        })\n    }\n}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>1\uff0c\u6280\u672f\u4ecb\u7ecd \uff081\uff09AVFoundation.framework \u6846\u67b6\u63d0\u4f9b\u4e86 AVCaptureSession [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,8],"tags":[],"_links":{"self":[{"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/posts\/3322"}],"collection":[{"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/92it.top\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3322"}],"version-history":[{"count":1,"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/posts\/3322\/revisions"}],"predecessor-version":[{"id":3325,"href":"https:\/\/92it.top\/index.php?rest_route=\/wp\/v2\/posts\/3322\/revisions\/3325"}],"wp:attachment":[{"href":"https:\/\/92it.top\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3322"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/92it.top\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3322"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/92it.top\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3322"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}