├── codecov.yml ├── web ├── screenshot.jpg └── qrcodereaderviewcontroller_header.png ├── Example ├── QRCodeReaderViewControllerExample.xcodeproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ ├── xcshareddata │ │ └── xcschemes │ │ │ └── QRCodeReaderViewControllerTests.xcscheme │ └── project.pbxproj ├── QRCodeReaderViewControllerTests │ ├── Info.plist │ └── QRCodeReaderTests.m └── QRCodeReaderViewControllerExample │ ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── LaunchImage.launchimage │ │ └── Contents.json │ ├── AppDelegate.h │ ├── ViewController.h │ ├── main.m │ ├── Info.plist │ ├── ViewController.m │ ├── AppDelegate.m │ └── Base.lproj │ └── Main.storyboard ├── .gitignore ├── .travis.yml ├── .github └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── CONTRIBUTORS.md ├── QRCodeReaderViewController.podspec ├── LICENSE ├── QRCodeReaderViewController ├── QRCodeReaderView.h ├── QRCameraSwitchButton.h ├── QRToggleTorchButton.h ├── QRCodeReaderDelegate.h ├── QRCodeReaderView.m ├── QRToggleTorchButton.m ├── QRCodeReader.h ├── QRCameraSwitchButton.m ├── QRCodeReader.m ├── QRCodeReaderViewController.h └── QRCodeReaderViewController.m ├── CHANGELOG.md └── README.md /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | ignore: 3 | - Example/* 4 | - web/* 5 | -------------------------------------------------------------------------------- /web/screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yannickl/QRCodeReaderViewController/HEAD/web/screenshot.jpg -------------------------------------------------------------------------------- /web/qrcodereaderviewcontroller_header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yannickl/QRCodeReaderViewController/HEAD/web/qrcodereaderviewcontroller_header.png -------------------------------------------------------------------------------- /Example/QRCodeReaderViewControllerExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | */build/* 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | profile 14 | *.moved-aside 15 | DerivedData 16 | .idea/ 17 | *.hmap 18 | *.xccheckout 19 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode7.3 3 | before_install: 4 | - gem install xcpretty 5 | script: 6 | - cd Example 7 | - xcodebuild -version 8 | - xcodebuild -project QRCodeReaderViewControllerExample.xcodeproj -scheme QRCodeReaderViewControllerTests -sdk iphonesimulator -destination "platform=iOS Simulator,name=iPhone 6,OS=9.0" -configuration Debug GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES ONLY_ACTIVE_ARCH=YES test | xcpretty -c 9 | after_success: 10 | - bash <(curl -s https://codecov.io/bash) 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | ## Contributors 2 | This is the official list of people who can contribute (and typically have contributed) code to the QRCodeReaderViewController repository. 3 | 4 | Names should be added to this file like so: 5 | ``` * [Firstname Lastname|Nickname](github_page_url)``` 6 | 7 | Please keep the list sorted. 8 | 9 | ### Lead developer 10 | 11 | * [Yannick Loriot](https://github.com/YannickL) 12 | 13 | ### People and companies, who have contributed 14 | 15 | * [Akira Matsuda](https://github.com/0x0c) 16 | * [Andrea Mazzini](https://github.com/andreamazz) 17 | * [Jan](https://github.com/jaltek) 18 | * [Nick Brook](https://github.com/nrbrook) 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Smartphone (please complete the following information):** 21 | - Device: [e.g. iPhone6] 22 | - OS: [e.g. iOS8.1] 23 | - Version [e.g. 22] 24 | 25 | **Additional context** 26 | Add any other context about the problem here. 27 | -------------------------------------------------------------------------------- /Example/QRCodeReaderViewControllerTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /QRCodeReaderViewController.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'QRCodeReaderViewController' 3 | s.version = '4.0.2' 4 | s.license = { :type => 'MIT', :file => 'LICENSE' } 5 | s.summary = 'Simple QRCode reader for iOS 7 and over' 6 | s.description = 'The `QRCodeReaderViewController` is a simple QRCode and bar code reader/scanner based on the `AVFoundation` framework from Apple. It aims to replace ZXing or ZBar for iOS 7 and over.' 7 | s.homepage = 'https://github.com/YannickL/QRCodeReaderViewController' 8 | s.authors = { 'Yannick Loriot' => 'contact@yannickloriot.com' } 9 | s.social_media_url = "https://twitter.com/yannickloriot" 10 | s.source = { :git => 'https://github.com/yannickl/QRCodeReaderViewController.git', 11 | :tag => s.version.to_s } 12 | s.requires_arc = true 13 | s.source_files = ['QRCodeReaderViewController/*.{h,m}'] 14 | s.framework = 'AVFoundation' 15 | s.ios.deployment_target = '7.0' 16 | end 17 | -------------------------------------------------------------------------------- /Example/QRCodeReaderViewControllerExample/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "ipad", 20 | "size" : "29x29", 21 | "scale" : "1x" 22 | }, 23 | { 24 | "idiom" : "ipad", 25 | "size" : "29x29", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "ipad", 30 | "size" : "40x40", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "40x40", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "76x76", 41 | "scale" : "1x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "76x76", 46 | "scale" : "2x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-present Yannick Loriot 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Example/QRCodeReaderViewControllerExample/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "orientation" : "portrait", 20 | "idiom" : "ipad", 21 | "extent" : "full-screen", 22 | "minimum-system-version" : "7.0", 23 | "scale" : "1x" 24 | }, 25 | { 26 | "orientation" : "landscape", 27 | "idiom" : "ipad", 28 | "extent" : "full-screen", 29 | "minimum-system-version" : "7.0", 30 | "scale" : "1x" 31 | }, 32 | { 33 | "orientation" : "portrait", 34 | "idiom" : "ipad", 35 | "extent" : "full-screen", 36 | "minimum-system-version" : "7.0", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "orientation" : "landscape", 41 | "idiom" : "ipad", 42 | "extent" : "full-screen", 43 | "minimum-system-version" : "7.0", 44 | "scale" : "2x" 45 | } 46 | ], 47 | "info" : { 48 | "version" : 1, 49 | "author" : "xcode" 50 | } 51 | } -------------------------------------------------------------------------------- /Example/QRCodeReaderViewControllerExample/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QRCodeReaderViewController 3 | * 4 | * Copyright 2014-present Yannick Loriot. 5 | * http://yannickloriot.com 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | * 25 | */ 26 | 27 | #import 28 | 29 | @interface AppDelegate : UIResponder 30 | 31 | @property (strong, nonatomic) UIWindow *window; 32 | 33 | 34 | @end 35 | 36 | -------------------------------------------------------------------------------- /Example/QRCodeReaderViewControllerExample/ViewController.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QRCodeReaderViewController 3 | * 4 | * Copyright 2014-present Yannick Loriot. 5 | * http://yannickloriot.com 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | * 25 | */ 26 | 27 | #import 28 | #import "QRCodeReaderDelegate.h" 29 | 30 | @interface ViewController : UIViewController 31 | 32 | - (IBAction)scanAction:(id)sender; 33 | 34 | @end 35 | 36 | -------------------------------------------------------------------------------- /QRCodeReaderViewController/QRCodeReaderView.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QRCodeReaderViewController 3 | * 4 | * Copyright 2014-present Yannick Loriot. 5 | * http://yannickloriot.com 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | * 25 | */ 26 | 27 | #import 28 | 29 | /** 30 | * Overlay over the camera view to display the area (a square) where to scan the 31 | * code. 32 | * @since 2.0.0 33 | */ 34 | @interface QRCodeReaderView : UIView 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /Example/QRCodeReaderViewControllerExample/main.m: -------------------------------------------------------------------------------- 1 | /* 2 | * QRCodeReaderViewController 3 | * 4 | * Copyright 2014-present Yannick Loriot. 5 | * http://yannickloriot.com 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | * 25 | */ 26 | 27 | #import 28 | #import "AppDelegate.h" 29 | 30 | int main(int argc, char * argv[]) { 31 | @autoreleasepool { 32 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Example/QRCodeReaderViewControllerExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | QRCode Reader 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 4.0.2 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSRequiresIPhoneOS 26 | 27 | NSCameraUsageDescription 28 | The camera is needed to scan QRCode 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationPortraitUpsideDown 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Example/QRCodeReaderViewControllerExample.xcodeproj/xcshareddata/xcschemes/QRCodeReaderViewControllerTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 14 | 15 | 17 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 39 | 40 | 41 | 42 | 48 | 49 | 51 | 52 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /QRCodeReaderViewController/QRCameraSwitchButton.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QRCodeReaderViewController 3 | * 4 | * Copyright 2014-present Yannick Loriot. 5 | * http://yannickloriot.com 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | * 25 | */ 26 | 27 | #import 28 | 29 | /** 30 | * The camera switch button. 31 | * @since 2.0.0 32 | */ 33 | @interface QRCameraSwitchButton : UIButton 34 | 35 | #pragma mark - Managing Properties 36 | /** @name Managing Properties */ 37 | 38 | /** 39 | * @abstract The edge color of the drawing. 40 | * @discussion The default color is the white. 41 | * @since 2.0.0 42 | */ 43 | @property (nonatomic, strong) UIColor *edgeColor; 44 | 45 | /** 46 | * @abstract The fill color of the drawing. 47 | * @discussion The default color is the darkgray. 48 | * @since 2.0.0 49 | */ 50 | @property (nonatomic, strong) UIColor *fillColor; 51 | 52 | /** 53 | * @abstract The edge color of the drawing when the button is touched. 54 | * @discussion The default color is the white. 55 | * @since 2.0.0 56 | */ 57 | @property (nonatomic, strong) UIColor *edgeHighlightedColor; 58 | 59 | /** 60 | * @abstract The fill color of the drawing when the button is touched. 61 | * @discussion The default color is the black. 62 | * @since 2.0.0 63 | */ 64 | @property (nonatomic, strong) UIColor *fillHighlightedColor; 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /QRCodeReaderViewController/QRToggleTorchButton.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QRCodeReaderViewController 3 | * 4 | * Copyright 2014-present Yannick Loriot. 5 | * http://yannickloriot.com 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | * 25 | */ 26 | 27 | #import 28 | 29 | /** 30 | * The toggle toch button. 31 | * @since 4.0.0 32 | */ 33 | @interface QRToggleTorchButton : UIButton 34 | 35 | #pragma mark - Managing Properties 36 | /** @name Managing Properties */ 37 | 38 | /** 39 | * @abstract The edge color of the drawing. 40 | * @discussion The default color is the white. 41 | * @since 2.0.0 42 | */ 43 | @property (nonatomic, strong) UIColor *edgeColor; 44 | 45 | /** 46 | * @abstract The fill color of the drawing. 47 | * @discussion The default color is the darkgray. 48 | * @since 2.0.0 49 | */ 50 | @property (nonatomic, strong) UIColor *fillColor; 51 | 52 | /** 53 | * @abstract The edge color of the drawing when the button is touched. 54 | * @discussion The default color is the white. 55 | * @since 2.0.0 56 | */ 57 | @property (nonatomic, strong) UIColor *edgeHighlightedColor; 58 | 59 | /** 60 | * @abstract The fill color of the drawing when the button is touched. 61 | * @discussion The default color is the black. 62 | * @since 2.0.0 63 | */ 64 | @property (nonatomic, strong) UIColor *fillHighlightedColor; 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /QRCodeReaderViewController/QRCodeReaderDelegate.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QRCodeReaderViewController 3 | * 4 | * Copyright 2014-present Yannick Loriot. 5 | * http://yannickloriot.com 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | * 25 | */ 26 | 27 | #import 28 | 29 | @class QRCodeReaderViewController; 30 | 31 | /** 32 | * This protocol defines delegate methods for objects that implements the 33 | * `QRCodeReaderDelegate`. The methods of the protocol allow the delegate to be 34 | * notified when the reader did scan result and or when the user wants to stop 35 | * to read some QRCodes. 36 | */ 37 | @protocol QRCodeReaderDelegate 38 | 39 | @optional 40 | 41 | #pragma mark - Listening for Reader Status 42 | /** @name Listening for Reader Status */ 43 | 44 | /** 45 | * @abstract Tells the delegate that the reader did scan a QRCode. 46 | * @param reader The reader view controller that scanned a QRCode. 47 | * @param result The content of the QRCode as a string. 48 | * @since 1.0.0 49 | */ 50 | - (void)reader:(QRCodeReaderViewController *)reader didScanResult:(NSString *)result; 51 | 52 | /** 53 | * @abstract Tells the delegate that the user wants to stop scanning QRCodes. 54 | * @param reader The reader view controller that the user wants to stop. 55 | * @since 1.0.0 56 | */ 57 | - (void)readerDidCancel:(QRCodeReaderViewController *)reader; 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /Example/QRCodeReaderViewControllerTests/QRCodeReaderTests.m: -------------------------------------------------------------------------------- 1 | /* 2 | * QRCodeReaderViewController 3 | * 4 | * Copyright 2014-present Yannick Loriot. 5 | * http://yannickloriot.com 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | * 25 | */ 26 | 27 | #import 28 | #import "QRCodeReaderViewController.h" 29 | 30 | @interface QRCodeReaderTests : XCTestCase 31 | 32 | @end 33 | 34 | @implementation QRCodeReaderTests 35 | 36 | - (void)testMetadataObjectMethod { 37 | QRCodeReader *reader =[[QRCodeReader alloc] init]; 38 | 39 | XCTAssertEqual(reader.metadataObjectTypes.count, 1); 40 | XCTAssertEqual(reader.metadataObjectTypes[0], AVMetadataObjectTypeQRCode); 41 | 42 | reader =[[QRCodeReader alloc] initWithMetadataObjectTypes:@[AVMetadataObjectTypeQRCode, 43 | AVMetadataObjectTypeCode93Code, 44 | AVMetadataObjectTypeDataMatrixCode]]; 45 | 46 | XCTAssertEqual(reader.metadataObjectTypes.count, 3); 47 | XCTAssertEqual(reader.metadataObjectTypes[0], AVMetadataObjectTypeQRCode); 48 | XCTAssertEqual(reader.metadataObjectTypes[1], AVMetadataObjectTypeCode93Code); 49 | XCTAssertEqual(reader.metadataObjectTypes[2], AVMetadataObjectTypeDataMatrixCode); 50 | 51 | reader = [QRCodeReader readerWithMetadataObjectTypes:@[]]; 52 | XCTAssertEqual(reader.metadataObjectTypes.count, 0); 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change log 2 | 3 | ## [Version 4.0.2](https://github.com/yannickl/QRCodeReaderViewController/releases/tag/4.0.2) 4 | Released on 2016-09-23. 5 | 6 | - [FIX] Only sets AVMetadataObjectTypes that are available [#24](https://github.com/yannickl/QRCodeReaderViewController/issues/24) 7 | 8 | ## [Version 4.0.1](https://github.com/yannickl/QRCodeReaderViewController/releases/tag/4.0.1) 9 | Released on 2015-11-07. 10 | 11 | - [FIX] Switch camera and toggle button under status bar [#14](https://github.com/yannickl/QRCodeReaderViewController/issues/14) 12 | 13 | ## [Version 4.0.0](https://github.com/yannickl/QRCodeReaderViewController/releases/tag/4.0.0) 14 | Released on 2015-11-02. 15 | 16 | - [ADD] Availability to disable the switch camera button. 17 | - [ADD] Torch button 18 | - [ADD] `initWithCancelButtonTitle:codeReader:startScanningAtLoad:showSwitchCameraButton:showTorchButton:` method in the `QRCodeReaderViewController` 19 | - [ADD] `isTorchAvailable` and `toggleTorch` methods in the `QRCodeReader` 20 | 21 | ## [Version 3.5.0](https://github.com/yannickl/QRCodeReaderViewController/releases/tag/3.5.0) 22 | Released on 2015-07-10. 23 | 24 | - [UPDATE] Make the `defaultDeviceInput`, the `frontDeviceInput` and the `metadataOutput` properties accessible in read-only mode 25 | 26 | ## [Version 3.4.0](https://github.com/yannickl/QRCodeReaderViewController/releases/tag/3.4.0) 27 | Released on 2015-05-24. 28 | 29 | - [ADD] init param to delay the start of scanning if necessary 30 | 31 | ## [Version 3.3.0](https://github.com/yannickl/QRCodeReaderViewController/releases/tag/3.3.0) 32 | Released on 2015-04-15. 33 | 34 | - [ADD] `running` property 35 | 36 | ## [Version 3.2.0](https://github.com/yannickl/QRCodeReaderViewController/releases/tag/3.2.0) 37 | Released on 2015-03-05. 38 | 39 | - [ADD] `supportsMetadataObjectTypes` method 40 | 41 | ## [Version 3.1.0](https://github.com/yannickl/QRCodeReaderViewController/releases/tag/3.1.0) 42 | Released on 2015-03-01. 43 | 44 | - [REFACTORING] Move orientation method to the appropriate object 45 | 46 | ## [Version 3.0.0](https://github.com/yannickl/QRCodeReaderViewController/releases/tag/3.0.0) 47 | Released on 2015-02-28. 48 | 49 | - [REFACTORING] Split the `QRCodeReaderViewController` and `QRCodeReader` 50 | 51 | ## [Version 2.0.0](https://github.com/yannickl/QRCodeReaderViewController/releases/tag/2.0.0) 52 | Released on 2014-11-15. 53 | 54 | - [ADD] Front camera supports 55 | - [ADD] Overlay view 56 | 57 | ## [Version 1.0.0](https://github.com/yannickl/QRCodeReaderViewController/releases/tag/1.0.0) 58 | Released on 2014-07-29. 59 | 60 | - Initialize with cancel button title 61 | - `isAvailable` method 62 | - Supports only the default camera 63 | - Supports only `AVMetadataObjectTypeQRCode` 64 | - Cocoapods supports 65 | -------------------------------------------------------------------------------- /QRCodeReaderViewController/QRCodeReaderView.m: -------------------------------------------------------------------------------- 1 | /* 2 | * QRCodeReaderViewController 3 | * 4 | * Copyright 2014-present Yannick Loriot. 5 | * http://yannickloriot.com 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | * 25 | */ 26 | 27 | #import "QRCodeReaderView.h" 28 | 29 | @interface QRCodeReaderView () 30 | @property (nonatomic, strong) CAShapeLayer *overlay; 31 | 32 | @end 33 | 34 | @implementation QRCodeReaderView 35 | 36 | - (id)initWithFrame:(CGRect)frame 37 | { 38 | if ((self = [super initWithFrame:frame])) { 39 | [self addOverlay]; 40 | } 41 | 42 | return self; 43 | } 44 | 45 | - (void)drawRect:(CGRect)rect 46 | { 47 | CGRect innerRect = CGRectInset(rect, 50, 50); 48 | 49 | CGFloat minSize = MIN(innerRect.size.width, innerRect.size.height); 50 | if (innerRect.size.width != minSize) { 51 | innerRect.origin.x += (innerRect.size.width - minSize) / 2; 52 | innerRect.size.width = minSize; 53 | } 54 | else if (innerRect.size.height != minSize) { 55 | innerRect.origin.y += (innerRect.size.height - minSize) / 2; 56 | innerRect.size.height = minSize; 57 | } 58 | 59 | CGRect offsetRect = CGRectOffset(innerRect, 0, 15); 60 | 61 | 62 | _overlay.path = [UIBezierPath bezierPathWithRoundedRect:offsetRect cornerRadius:5].CGPath; 63 | } 64 | 65 | #pragma mark - Private Methods 66 | 67 | - (void)addOverlay 68 | { 69 | _overlay = [[CAShapeLayer alloc] init]; 70 | _overlay.backgroundColor = [UIColor clearColor].CGColor; 71 | _overlay.fillColor = [UIColor clearColor].CGColor; 72 | _overlay.strokeColor = [UIColor whiteColor].CGColor; 73 | _overlay.lineWidth = 3; 74 | _overlay.lineDashPattern = @[@7.0, @7.0]; 75 | _overlay.lineDashPhase = 0; 76 | 77 | [self.layer addSublayer:_overlay]; 78 | } 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /Example/QRCodeReaderViewControllerExample/ViewController.m: -------------------------------------------------------------------------------- 1 | /* 2 | * QRCodeReaderViewController 3 | * 4 | * Copyright 2014-present Yannick Loriot. 5 | * http://yannickloriot.com 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | * 25 | */ 26 | 27 | #import "ViewController.h" 28 | #import "QRCodeReaderViewController.h" 29 | #import "QRCodeReader.h" 30 | 31 | @interface ViewController () 32 | 33 | @end 34 | 35 | @implementation ViewController 36 | 37 | - (IBAction)scanAction:(id)sender 38 | { 39 | if ([QRCodeReader supportsMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]]) { 40 | static QRCodeReaderViewController *vc = nil; 41 | static dispatch_once_t onceToken; 42 | 43 | dispatch_once(&onceToken, ^{ 44 | QRCodeReader *reader = [QRCodeReader readerWithMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]]; 45 | vc = [QRCodeReaderViewController readerWithCancelButtonTitle:@"Cancel" codeReader:reader startScanningAtLoad:YES showSwitchCameraButton:YES showTorchButton:YES]; 46 | vc.modalPresentationStyle = UIModalPresentationFormSheet; 47 | }); 48 | vc.delegate = self; 49 | 50 | [vc setCompletionWithBlock:^(NSString *resultAsString) { 51 | NSLog(@"Completion with result: %@", resultAsString); 52 | }]; 53 | 54 | [self presentViewController:vc animated:YES completion:NULL]; 55 | } 56 | else { 57 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Reader not supported by the current device" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; 58 | 59 | [alert show]; 60 | } 61 | } 62 | 63 | #pragma mark - QRCodeReader Delegate Methods 64 | 65 | - (void)reader:(QRCodeReaderViewController *)reader didScanResult:(NSString *)result 66 | { 67 | [reader stopScanning]; 68 | 69 | [self dismissViewControllerAnimated:YES completion:^{ 70 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"QRCodeReader" message:result delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; 71 | [alert show]; 72 | }]; 73 | } 74 | 75 | - (void)readerDidCancel:(QRCodeReaderViewController *)reader 76 | { 77 | [self dismissViewControllerAnimated:YES completion:NULL]; 78 | } 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /Example/QRCodeReaderViewControllerExample/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /* 2 | * QRCodeReaderViewController 3 | * 4 | * Copyright 2014-present Yannick Loriot. 5 | * http://yannickloriot.com 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | * 25 | */ 26 | 27 | #import "AppDelegate.h" 28 | 29 | @interface AppDelegate () 30 | 31 | @end 32 | 33 | @implementation AppDelegate 34 | 35 | 36 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 37 | // Override point for customization after application launch. 38 | return YES; 39 | } 40 | 41 | - (void)applicationWillResignActive:(UIApplication *)application { 42 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 43 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 44 | } 45 | 46 | - (void)applicationDidEnterBackground:(UIApplication *)application { 47 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 48 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 49 | } 50 | 51 | - (void)applicationWillEnterForeground:(UIApplication *)application { 52 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 53 | } 54 | 55 | - (void)applicationDidBecomeActive:(UIApplication *)application { 56 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 57 | } 58 | 59 | - (void)applicationWillTerminate:(UIApplication *)application { 60 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 61 | } 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /Example/QRCodeReaderViewControllerExample/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /QRCodeReaderViewController/QRToggleTorchButton.m: -------------------------------------------------------------------------------- 1 | /* 2 | * QRCodeReaderViewController 3 | * 4 | * Copyright 2014-present Yannick Loriot. 5 | * http://yannickloriot.com 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | * 25 | */ 26 | 27 | #import "QRToggleTorchButton.h" 28 | 29 | @implementation QRToggleTorchButton 30 | 31 | - (id)initWithFrame:(CGRect)frame 32 | { 33 | if ((self = [super initWithFrame:frame])) { 34 | _edgeColor = [UIColor whiteColor]; 35 | _fillColor = [UIColor darkGrayColor]; 36 | _edgeHighlightedColor = [UIColor whiteColor]; 37 | _fillHighlightedColor = [UIColor blackColor]; 38 | } 39 | return self; 40 | } 41 | 42 | - (void)drawRect:(CGRect)rect 43 | { 44 | // Colors 45 | 46 | UIColor *paintColor = (self.state != UIControlStateHighlighted) ? _fillColor : _fillHighlightedColor; 47 | UIColor *strokeColor = (self.state != UIControlStateHighlighted) ? _edgeColor : _edgeHighlightedColor; 48 | 49 | // Torch box 50 | 51 | CGFloat width = rect.size.width; 52 | CGFloat height = rect.size.height; 53 | CGFloat centerX = width / 2; 54 | CGFloat centerY = height / 2; 55 | 56 | CGFloat strokeLineWidth = 2; 57 | CGFloat circleRadius = width / 10; 58 | CGFloat lineLength = width / 10; 59 | CGFloat lineOffset = width / 10; 60 | CGFloat lineOriginFromCenter = circleRadius + lineOffset; 61 | 62 | //Circle 63 | UIBezierPath *circlePath = [UIBezierPath bezierPath]; 64 | [circlePath addArcWithCenter:CGPointMake(centerX, centerY) radius:circleRadius startAngle:0.0 endAngle:M_PI clockwise:YES]; 65 | [circlePath addArcWithCenter:CGPointMake(centerX, centerY) radius:circleRadius startAngle:M_PI endAngle:M_PI * 2 clockwise:YES]; 66 | 67 | // Draw beams 68 | [paintColor setFill]; 69 | 70 | for (int i = 0; i < 8; i++) { 71 | CGFloat angle = ((2 * M_PI) / 8) * i; 72 | 73 | CGPoint startPoint = CGPointMake(centerX + cos(angle) * lineOriginFromCenter, centerY + sin(angle) * lineOriginFromCenter); 74 | CGPoint endPoint = CGPointMake(centerX + cos(angle) * (lineOriginFromCenter + lineLength), centerY + sin(angle) * (lineOriginFromCenter + lineLength)); 75 | 76 | UIBezierPath *beamPath = [self linePathWithStartPoint:startPoint endPoint:endPoint thickness:strokeLineWidth]; 77 | [beamPath stroke]; 78 | } 79 | 80 | // Draw circle 81 | [strokeColor setFill]; 82 | 83 | circlePath.lineWidth = strokeLineWidth; 84 | [circlePath fill]; 85 | [circlePath stroke]; 86 | } 87 | 88 | - (UIBezierPath *)linePathWithStartPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint thickness:(CGFloat)thickness { 89 | UIBezierPath *linePath = [UIBezierPath bezierPath]; 90 | 91 | [linePath moveToPoint:startPoint]; 92 | [linePath addLineToPoint:endPoint]; 93 | 94 | linePath.lineCapStyle = kCGLineCapRound; 95 | linePath.lineWidth = thickness; 96 | 97 | return linePath; 98 | } 99 | 100 | // MARK: - UIResponder Methods 101 | 102 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 103 | { 104 | [super touchesBegan:touches withEvent:event]; 105 | 106 | [self setNeedsDisplay]; 107 | } 108 | 109 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 110 | { 111 | [super touchesMoved:touches withEvent:event]; 112 | 113 | [self setNeedsDisplay]; 114 | } 115 | 116 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 117 | { 118 | [super touchesEnded:touches withEvent:event]; 119 | 120 | [self setNeedsDisplay]; 121 | } 122 | 123 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event 124 | { 125 | [super touchesCancelled:touches withEvent:event]; 126 | 127 | [self setNeedsDisplay]; 128 | } 129 | 130 | @end 131 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![QRCodeReaderViewController](https://github.com/YannickL/QRCodeReaderViewController/blob/master/web/qrcodereaderviewcontroller_header.png) 2 | 3 |

4 | Supported Platforms 5 | Version 6 | Build status 7 |

8 | 9 | The _QRCodeReaderViewController_ was initially a simple QRCode reader but it now lets you the possibility to specify the [format type](https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVMetadataMachineReadableCodeObject_Class/index.html#//apple_ref/doc/constant_group/Machine_Readable_Object_Types) you want to decode. It is based on the `AVFoundation` framework from Apple in order to replace ZXing or ZBar for iOS 7 and over. 10 | 11 | It provides a default view controller to display the camera view with the scan area overlay and it also provides a button to switch between the front and the back cameras. 12 | 13 | ![screenshot](http://yannickloriot.com/resources/qrcodereader.swift-screenshot.jpg) 14 | 15 |

16 | UsageInstallationContributionContactLicense 17 |

18 | 19 | ## Usage 20 | 21 | Note that in iOS10+, you will need first to reasoning about the camera use. For that you'll need to add the **Privacy - Camera Usage Description** *(NSCameraUsageDescription)* field in your Info.plist: 22 | 23 |

24 | privacy - camera usage description 25 |

26 | 27 | Now a very simple example how to work with `QRCodeReaderViewController`: 28 | 29 | ```objective-c 30 | // Create the reader object 31 | QRCodeReader *reader = [QRCodeReader readerWithMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]]; 32 | 33 | // Instantiate the view controller 34 | QRCodeReaderViewController *vc = [QRCodeReaderViewController readerWithCancelButtonTitle:@"Cancel" codeReader:_reader startScanningAtLoad:YES showSwitchCameraButton:YES showTorchButton:YES]; 35 | 36 | // Set the presentation style 37 | _vc.modalPresentationStyle = UIModalPresentationFormSheet; 38 | 39 | // Define the delegate receiver 40 | _vc.delegate = self; 41 | 42 | // Or use blocks 43 | [_reader setCompletionWithBlock:^(NSString *resultAsString) { 44 | NSLog(@"%@", resultAsString); 45 | }]; 46 | ``` 47 | 48 | Now when we touch the scan button we need to display the QRCodeReaderViewController: 49 | 50 | ```objective-c 51 | #pragma mark - Action Methods 52 | 53 | - (IBAction)scanAction:(id)sender 54 | { 55 | [self presentViewController:_vc animated:YES completion:NULL]; 56 | } 57 | ``` 58 | 59 | And here the delegate methods: 60 | 61 | ```objective-c 62 | #pragma mark - QRCodeReader Delegate Methods 63 | 64 | - (void)reader:(QRCodeReaderViewController *)reader didScanResult:(NSString *)result 65 | { 66 | [self dismissViewControllerAnimated:YES completion:^{ 67 | NSLog(@"%@", result); 68 | }]; 69 | } 70 | 71 | - (void)readerDidCancel:(QRCodeReaderViewController *)reader 72 | { 73 | [self dismissViewControllerAnimated:YES completion:NULL]; 74 | } 75 | ``` 76 | 77 | *Note that you should check whether the device supports the reader library by using the `[QRCodeReader isAvailable]` or the `[QRCodeReader supportsMetadataObjectTypes:nil]` methods.* 78 | 79 | ### Installation 80 | 81 | The recommended approach to use _QRCodeReaderViewController_ in your project is using the [CocoaPods](http://cocoapods.org/) package manager, as it provides flexible dependency management and dead simple installation. 82 | 83 | #### CocoaPods 84 | 85 | Install CocoaPods if not already available: 86 | 87 | ``` bash 88 | $ [sudo] gem install cocoapods 89 | $ pod setup 90 | ``` 91 | Go to the directory of your Xcode project, and Create and Edit your Podfile and add _QRCodeReaderViewController_: 92 | 93 | ``` bash 94 | $ cd /path/to/MyProject 95 | $ touch Podfile 96 | $ edit Podfile 97 | source 'https://github.com/CocoaPods/Specs.git' 98 | platform :ios, '7.0' 99 | pod 'QRCodeReaderViewController', '~> 4.0.2' 100 | ``` 101 | 102 | Install into your project: 103 | 104 | ``` bash 105 | $ pod install 106 | ``` 107 | 108 | Open your project in Xcode from the .xcworkspace file (not the usual project file) 109 | 110 | ``` bash 111 | $ open MyProject.xcworkspace 112 | ``` 113 | 114 | #### Manually 115 | 116 | [Download](https://github.com/YannickL/QRCodeReaderViewController/archive/master.zip) the project and copy the `QRCodeReaderViewController` folder into your project and then simply `#import "QRCodeReaderViewController.h"` in the file(s) you would like to use it in. 117 | 118 | ## Contribution 119 | 120 | Contributions are welcomed and encouraged *♡*. 121 | 122 | ## Contact 123 | 124 | Yannick Loriot 125 | - [https://twitter.com/yannickloriot](https://twitter.com/yannickloriot) 126 | - [contact@yannickloriot.com](mailto:contact@yannickloriot.com) 127 | 128 | 129 | ## License (MIT) 130 | 131 | Copyright (c) 2014-present - Yannick Loriot 132 | 133 | Permission is hereby granted, free of charge, to any person obtaining a copy 134 | of this software and associated documentation files (the "Software"), to deal 135 | in the Software without restriction, including without limitation the rights 136 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 137 | copies of the Software, and to permit persons to whom the Software is 138 | furnished to do so, subject to the following conditions: 139 | 140 | The above copyright notice and this permission notice shall be included in 141 | all copies or substantial portions of the Software. 142 | 143 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 144 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 145 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 146 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 147 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 148 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 149 | THE SOFTWARE. 150 | -------------------------------------------------------------------------------- /QRCodeReaderViewController/QRCodeReader.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QRCodeReader 3 | * 4 | * Copyright 2014-present Yannick Loriot. 5 | * http://yannickloriot.com 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | * 25 | */ 26 | 27 | #import 28 | #import 29 | #import 30 | 31 | /** 32 | * Reader object base on the `AVCaptureDevice` to read / scan 1D and 2D codes. 33 | */ 34 | @interface QRCodeReader : NSObject 35 | 36 | #pragma mark - Creating and Inializing QRCode Readers 37 | /** @name Creating and Inializing QRCode Readers */ 38 | 39 | /** 40 | * @abstract Initializes a reader with the `QRCode` metadata object type. 41 | * @since 4.1.0 42 | */ 43 | - (nonnull id)init; 44 | 45 | /** 46 | * @abstract Initializes a reader with a list of metadata object types. 47 | * @param metadataObjectTypes An array of strings identifying the types of 48 | * metadata objects to process. 49 | * @since 3.0.0 50 | */ 51 | - (nonnull id)initWithMetadataObjectTypes:(nonnull NSArray *)metadataObjectTypes; 52 | 53 | /** 54 | * @abstract Creates a reader with a list of metadata object types. 55 | * @param metadataObjectTypes An array of strings identifying the types of 56 | * metadata objects to process. 57 | * @see initWithMetadataObjectTypes: 58 | * @since 3.0.0 59 | */ 60 | + (nonnull instancetype)readerWithMetadataObjectTypes:(nonnull NSArray *)metadataObjectTypes; 61 | 62 | #pragma mark - Checking the Reader Availabilities 63 | /** @name Checking the Reader Availabilities */ 64 | 65 | /** 66 | * @abstract Returns whether the reader is available with the current device. 67 | * @return a Boolean value indicating whether the reader is available. 68 | * @since 3.0.0 69 | */ 70 | + (BOOL)isAvailable; 71 | 72 | /** 73 | * @abstract Checks and return whether the given metadata object types are 74 | * supported by the current device. 75 | * @return a Boolean value indicating whether the given metadata object types 76 | * are supported by the current device. 77 | * @since 3.2.0 78 | */ 79 | + (BOOL)supportsMetadataObjectTypes:(nonnull NSArray *)metadataObjectTypes; 80 | 81 | #pragma mark - Checking the Metadata Items Types 82 | /** @name Checking the Metadata Items Types */ 83 | 84 | /** 85 | * @abstract An array of strings identifying the types of metadata objects to 86 | * process. 87 | * @since 3.0.0 88 | */ 89 | @property (strong, nonatomic, readonly) NSArray * _Nonnull metadataObjectTypes; 90 | 91 | #pragma mark - Viewing the Camera 92 | /** @name Viewing the Camera */ 93 | 94 | /** 95 | * @abstract CALayer that you use to display video as it is being captured 96 | * by an input device. 97 | * @since 3.0.0 98 | */ 99 | @property (strong, nonatomic, readonly) AVCaptureVideoPreviewLayer * _Nonnull previewLayer; 100 | 101 | #pragma mark - Controlling the Reader 102 | /** @name Controlling the Reader */ 103 | 104 | /** 105 | * @abstract Starts scanning the codes. 106 | * @since 3.0.0 107 | */ 108 | - (void)startScanning; 109 | 110 | /** 111 | * @abstract Stops scanning the codes. 112 | * @since 3.0.0 113 | */ 114 | - (void)stopScanning; 115 | 116 | /** 117 | * @abstract Indicates whether the session is currently running. 118 | * @discussion The value of this property is a Bool indicating whether the 119 | * receiver is running. 120 | * Clients can key value observe the value of this property to be notified 121 | * when the session automatically starts or stops running. 122 | * @since 3.3.0 123 | */ 124 | - (BOOL)running; 125 | 126 | /** 127 | * @abstract Switch between the back and the front camera. 128 | * @since 3.0.0 129 | */ 130 | - (void)switchDeviceInput; 131 | 132 | /** 133 | * @abstract Returns true whether a front device is available. 134 | * @return true whether a front device is available. 135 | * @since 3.0.0 136 | */ 137 | - (BOOL)hasFrontDevice; 138 | 139 | /** 140 | * @abstract Returns true whether a torch is available. 141 | * @return true if a torch is available. 142 | * @since 4.0.0 143 | */ 144 | - (BOOL)isTorchAvailable; 145 | 146 | /** 147 | * @abstract Toggles torch on the default device. 148 | * @since 4.0.0 149 | */ 150 | - (void)toggleTorch; 151 | 152 | #pragma mark - Getting Inputs and Outputs 153 | /** @name Getting Inputs and Outputs */ 154 | 155 | /** 156 | * @abstract Accessing to the `AVCaptureDeviceInput` object representing 157 | * the default device input (generally the back camera). 158 | * @since 3.5.0 159 | */ 160 | @property (readonly) AVCaptureDeviceInput * _Nonnull defaultDeviceInput; 161 | 162 | /** 163 | * @abstract Accessing to the `AVCaptureDeviceInput` object representing 164 | * the front device input. 165 | * @since 3.5.0 166 | */ 167 | @property (readonly) AVCaptureDeviceInput * _Nullable frontDeviceInput; 168 | 169 | /** 170 | * @abstract Accessing to the `AVCaptureMetadataOutput` object. 171 | * @discussion It allows you to configure the scanner to restrict the area of 172 | * the scan to the overlay one for example. 173 | * @since 3.5.0 174 | */ 175 | @property (readonly) AVCaptureMetadataOutput * _Nonnull metadataOutput; 176 | 177 | #pragma mark - Managing the Orientation 178 | /** @name Managing the Orientation */ 179 | 180 | /** 181 | * @abstract Returns the video orientation correspongind to the given interface 182 | * orientation. 183 | * @param interfaceOrientation An interface orientation. 184 | * @return the video orientation correspongind to the given device orientation. 185 | * @since 3.1.0 186 | */ 187 | + (AVCaptureVideoOrientation)videoOrientationFromInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation; 188 | 189 | #pragma mark - Managing the Block 190 | /** @name Managing the Block */ 191 | 192 | /** 193 | * @abstract Sets the completion with a block that executes when a QRCode 194 | * or when the user did stopped the scan. 195 | * @param completionBlock The block to be executed. This block has no 196 | * return value and takes one argument: the `resultAsString`. If the user 197 | * stop the scan and that there is no response the `resultAsString` argument 198 | * is nil. 199 | * @since 3.0.0 200 | */ 201 | - (void)setCompletionWithBlock:(nullable void (^) (NSString * _Nullable resultAsString))completionBlock; 202 | 203 | @end 204 | -------------------------------------------------------------------------------- /QRCodeReaderViewController/QRCameraSwitchButton.m: -------------------------------------------------------------------------------- 1 | /* 2 | * QRCodeReaderViewController 3 | * 4 | * Copyright 2014-present Yannick Loriot. 5 | * http://yannickloriot.com 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | * 25 | */ 26 | 27 | #import "QRCameraSwitchButton.h" 28 | 29 | @implementation QRCameraSwitchButton 30 | 31 | - (id)initWithFrame:(CGRect)frame 32 | { 33 | if ((self = [super initWithFrame:frame])) { 34 | _edgeColor = [UIColor whiteColor]; 35 | _fillColor = [UIColor darkGrayColor]; 36 | _edgeHighlightedColor = [UIColor whiteColor]; 37 | _fillHighlightedColor = [UIColor blackColor]; 38 | } 39 | return self; 40 | } 41 | 42 | - (void)drawRect:(CGRect)rect 43 | { 44 | CGFloat width = rect.size.width; 45 | CGFloat height = rect.size.height; 46 | CGFloat center = width / 2; 47 | CGFloat middle = height / 2; 48 | 49 | CGFloat strokeLineWidth = 2; 50 | 51 | // Colors 52 | 53 | UIColor *paintColor = (self.state != UIControlStateHighlighted) ? _fillColor : _fillHighlightedColor; 54 | UIColor *strokeColor = (self.state != UIControlStateHighlighted) ? _edgeColor : _edgeHighlightedColor; 55 | 56 | // Camera box 57 | 58 | CGFloat cameraWidth = width * 0.4; 59 | CGFloat cameraHeight = cameraWidth * 0.6; 60 | CGFloat cameraX = center - cameraWidth / 2; 61 | CGFloat cameraY = middle - cameraHeight / 2; 62 | CGFloat cameraRadius = cameraWidth / 80; 63 | 64 | UIBezierPath *boxPath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(cameraX, cameraY, cameraWidth, cameraHeight) cornerRadius:cameraRadius]; 65 | 66 | // Camera lens 67 | 68 | CGFloat outerLensSize = cameraHeight * 0.8; 69 | CGFloat outerLensX = center - outerLensSize / 2; 70 | CGFloat outerLensY = middle - outerLensSize / 2; 71 | 72 | CGFloat innerLensSize = outerLensSize * 0.7; 73 | CGFloat innerLensX = center - innerLensSize / 2; 74 | CGFloat innerLensY = middle - innerLensSize / 2; 75 | 76 | UIBezierPath *outerLensPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(outerLensX, outerLensY, outerLensSize, outerLensSize)]; 77 | UIBezierPath *innerLensPath = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(innerLensX, innerLensY, innerLensSize, innerLensSize)]; 78 | 79 | // Draw flash box 80 | 81 | CGFloat flashBoxWidth = cameraWidth * 0.8; 82 | CGFloat flashBoxHeight = cameraHeight * 0.17; 83 | CGFloat flashBoxDeltaWidth = flashBoxWidth * 0.14; 84 | CGFloat flashLeftMostX = cameraX + (cameraWidth - flashBoxWidth) * 0.5; 85 | CGFloat flashBottomMostY = cameraY; 86 | 87 | UIBezierPath *flashPath = [UIBezierPath bezierPath]; 88 | [flashPath moveToPoint:CGPointMake(flashLeftMostX, flashBottomMostY)]; 89 | [flashPath addLineToPoint:CGPointMake(flashLeftMostX + flashBoxWidth, flashBottomMostY)]; 90 | [flashPath addLineToPoint:CGPointMake(flashLeftMostX + flashBoxWidth - flashBoxDeltaWidth, flashBottomMostY - flashBoxHeight)]; 91 | [flashPath addLineToPoint:CGPointMake(flashLeftMostX + flashBoxDeltaWidth, flashBottomMostY - flashBoxHeight)]; 92 | [flashPath closePath]; 93 | 94 | flashPath.lineCapStyle = kCGLineCapRound; 95 | flashPath.lineJoinStyle = kCGLineJoinRound; 96 | 97 | // Arrows 98 | 99 | CGFloat arrowHeadHeigth = cameraHeight * 0.5; 100 | CGFloat arrowHeadWidth = ((width - cameraWidth) / 2) * 0.3; 101 | CGFloat arrowTailHeigth = arrowHeadHeigth * 0.6; 102 | CGFloat arrowTailWidth = ((width - cameraWidth) / 2) * 0.7; 103 | 104 | // Draw left arrow 105 | 106 | CGFloat arrowLeftX = center - cameraWidth * 0.2; 107 | CGFloat arrowLeftY = middle + cameraHeight * 0.45; 108 | 109 | UIBezierPath *leftArrowPath = [UIBezierPath bezierPath]; 110 | [leftArrowPath moveToPoint:CGPointMake(arrowLeftX, arrowLeftY)]; 111 | [leftArrowPath addLineToPoint:CGPointMake(arrowLeftX - arrowHeadWidth, arrowLeftY - arrowHeadHeigth / 2)]; 112 | [leftArrowPath addLineToPoint:CGPointMake(arrowLeftX - arrowHeadWidth, arrowLeftY - arrowTailHeigth / 2)]; 113 | [leftArrowPath addLineToPoint:CGPointMake(arrowLeftX - arrowHeadWidth - arrowTailWidth, arrowLeftY - arrowTailHeigth / 2)]; 114 | [leftArrowPath addLineToPoint:CGPointMake(arrowLeftX - arrowHeadWidth - arrowTailWidth, arrowLeftY + arrowTailHeigth / 2)]; 115 | [leftArrowPath addLineToPoint:CGPointMake(arrowLeftX - arrowHeadWidth, arrowLeftY + arrowTailHeigth / 2)]; 116 | [leftArrowPath addLineToPoint:CGPointMake(arrowLeftX - arrowHeadWidth, arrowLeftY + arrowHeadHeigth / 2)]; 117 | [leftArrowPath closePath]; 118 | 119 | // Right arrow 120 | 121 | CGFloat arrowRightX = center + cameraWidth * 0.2; 122 | CGFloat arrowRightY = middle + cameraHeight * 0.60; 123 | 124 | UIBezierPath *rigthArrowPath = [UIBezierPath bezierPath]; 125 | [rigthArrowPath moveToPoint:CGPointMake(arrowRightX, arrowRightY)]; 126 | [rigthArrowPath addLineToPoint:CGPointMake(arrowRightX + arrowHeadWidth, arrowRightY - arrowHeadHeigth / 2)]; 127 | [rigthArrowPath addLineToPoint:CGPointMake(arrowRightX + arrowHeadWidth, arrowRightY - arrowTailHeigth / 2)]; 128 | [rigthArrowPath addLineToPoint:CGPointMake(arrowRightX + arrowHeadWidth + arrowTailWidth, arrowRightY - arrowTailHeigth / 2)]; 129 | [rigthArrowPath addLineToPoint:CGPointMake(arrowRightX + arrowHeadWidth + arrowTailWidth, arrowRightY + arrowTailHeigth / 2)]; 130 | [rigthArrowPath addLineToPoint:CGPointMake(arrowRightX + arrowHeadWidth, arrowRightY + arrowTailHeigth / 2)]; 131 | [rigthArrowPath addLineToPoint:CGPointMake(arrowRightX + arrowHeadWidth, arrowRightY + arrowHeadHeigth / 2)]; 132 | [rigthArrowPath closePath]; 133 | 134 | // Drawing 135 | 136 | [paintColor setFill]; 137 | [rigthArrowPath fill]; 138 | [strokeColor setStroke]; 139 | rigthArrowPath.lineWidth = strokeLineWidth; 140 | [rigthArrowPath stroke]; 141 | 142 | [paintColor setFill]; 143 | [boxPath fill]; 144 | [strokeColor setStroke]; 145 | boxPath.lineWidth = strokeLineWidth; 146 | [boxPath stroke]; 147 | 148 | [strokeColor setFill]; 149 | [outerLensPath fill]; 150 | 151 | [paintColor setFill]; 152 | [innerLensPath fill]; 153 | 154 | [paintColor setFill]; 155 | [flashPath fill]; 156 | [strokeColor setStroke]; 157 | flashPath.lineWidth = strokeLineWidth; 158 | [flashPath stroke]; 159 | 160 | [paintColor setFill]; 161 | [leftArrowPath fill]; 162 | [strokeColor setStroke]; 163 | leftArrowPath.lineWidth = strokeLineWidth; 164 | [leftArrowPath stroke]; 165 | } 166 | 167 | // MARK: - UIResponder Methods 168 | 169 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 170 | { 171 | [super touchesBegan:touches withEvent:event]; 172 | 173 | [self setNeedsDisplay]; 174 | } 175 | 176 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 177 | { 178 | [super touchesMoved:touches withEvent:event]; 179 | 180 | [self setNeedsDisplay]; 181 | } 182 | 183 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 184 | { 185 | [super touchesEnded:touches withEvent:event]; 186 | 187 | [self setNeedsDisplay]; 188 | } 189 | 190 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event 191 | { 192 | [super touchesCancelled:touches withEvent:event]; 193 | 194 | [self setNeedsDisplay]; 195 | } 196 | 197 | @end 198 | -------------------------------------------------------------------------------- /QRCodeReaderViewController/QRCodeReader.m: -------------------------------------------------------------------------------- 1 | /* 2 | * QRCodeReader 3 | * 4 | * Copyright 2014-present Yannick Loriot. 5 | * http://yannickloriot.com 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | * 25 | */ 26 | 27 | #import "QRCodeReader.h" 28 | 29 | @interface QRCodeReader () 30 | @property (strong, nonatomic) AVCaptureDevice *defaultDevice; 31 | @property (strong, nonatomic) AVCaptureDeviceInput *defaultDeviceInput; 32 | @property (strong, nonatomic) AVCaptureDevice *frontDevice; 33 | @property (strong, nonatomic) AVCaptureDeviceInput *frontDeviceInput; 34 | @property (strong, nonatomic) AVCaptureMetadataOutput *metadataOutput; 35 | @property (strong, nonatomic) AVCaptureSession *session; 36 | @property (strong, nonatomic) AVCaptureVideoPreviewLayer *previewLayer; 37 | 38 | @property (copy, nonatomic) void (^completionBlock) (NSString *); 39 | 40 | @end 41 | 42 | @implementation QRCodeReader 43 | 44 | - (id)init 45 | { 46 | if ((self = [super init])) { 47 | _metadataObjectTypes = @[AVMetadataObjectTypeQRCode]; 48 | 49 | [self setupAVComponents]; 50 | [self configureDefaultComponents]; 51 | } 52 | return self; 53 | } 54 | 55 | - (id)initWithMetadataObjectTypes:(NSArray *)metadataObjectTypes 56 | { 57 | if ((self = [super init])) { 58 | _metadataObjectTypes = metadataObjectTypes; 59 | 60 | [self setupAVComponents]; 61 | [self configureDefaultComponents]; 62 | } 63 | return self; 64 | } 65 | 66 | + (instancetype)readerWithMetadataObjectTypes:(NSArray *)metadataObjectTypes 67 | { 68 | return [[self alloc] initWithMetadataObjectTypes:metadataObjectTypes]; 69 | } 70 | 71 | #pragma mark - Initializing the AV Components 72 | 73 | - (void)setupAVComponents 74 | { 75 | self.defaultDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; 76 | 77 | if (_defaultDevice) { 78 | self.defaultDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:_defaultDevice error:nil]; 79 | self.metadataOutput = [[AVCaptureMetadataOutput alloc] init]; 80 | self.session = [[AVCaptureSession alloc] init]; 81 | self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.session]; 82 | 83 | for (AVCaptureDevice *device in [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]) { 84 | if (device.position == AVCaptureDevicePositionFront) { 85 | self.frontDevice = device; 86 | } 87 | } 88 | 89 | if (_frontDevice) { 90 | self.frontDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:_frontDevice error:nil]; 91 | } 92 | } 93 | } 94 | 95 | - (void)configureDefaultComponents 96 | { 97 | [_session addOutput:_metadataOutput]; 98 | 99 | if (_defaultDeviceInput) { 100 | [_session addInput:_defaultDeviceInput]; 101 | } 102 | 103 | [_metadataOutput setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()]; 104 | NSMutableSet *available = [NSMutableSet setWithArray:[_metadataOutput availableMetadataObjectTypes]]; 105 | NSSet *desired = [NSSet setWithArray:_metadataObjectTypes]; 106 | [available intersectSet:desired]; 107 | [_metadataOutput setMetadataObjectTypes:available.allObjects]; 108 | [_previewLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill]; 109 | } 110 | 111 | - (void)switchDeviceInput 112 | { 113 | if (_frontDeviceInput) { 114 | [_session beginConfiguration]; 115 | 116 | AVCaptureDeviceInput *currentInput = [_session.inputs firstObject]; 117 | [_session removeInput:currentInput]; 118 | 119 | AVCaptureDeviceInput *newDeviceInput = (currentInput.device.position == AVCaptureDevicePositionFront) ? _defaultDeviceInput : _frontDeviceInput; 120 | [_session addInput:newDeviceInput]; 121 | 122 | [_session commitConfiguration]; 123 | } 124 | } 125 | 126 | - (BOOL)hasFrontDevice 127 | { 128 | return _frontDevice != nil; 129 | } 130 | 131 | - (BOOL)isTorchAvailable 132 | { 133 | return _defaultDevice.hasTorch; 134 | } 135 | 136 | - (void)toggleTorch 137 | { 138 | NSError *error = nil; 139 | 140 | [_defaultDevice lockForConfiguration:&error]; 141 | 142 | if (error == nil) { 143 | AVCaptureTorchMode mode = _defaultDevice.torchMode; 144 | 145 | _defaultDevice.torchMode = mode == AVCaptureTorchModeOn ? AVCaptureTorchModeOff : AVCaptureTorchModeOn; 146 | } 147 | 148 | [_defaultDevice unlockForConfiguration]; 149 | } 150 | 151 | #pragma mark - Controlling Reader 152 | 153 | - (void)startScanning 154 | { 155 | if (![self.session isRunning]) { 156 | [self.session startRunning]; 157 | } 158 | } 159 | 160 | - (void)stopScanning 161 | { 162 | if ([self.session isRunning]) { 163 | [self.session stopRunning]; 164 | } 165 | } 166 | 167 | - (BOOL)running { 168 | return self.session.running; 169 | } 170 | 171 | #pragma mark - Managing the Orientation 172 | 173 | + (AVCaptureVideoOrientation)videoOrientationFromInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation 174 | { 175 | switch (interfaceOrientation) { 176 | case UIInterfaceOrientationLandscapeLeft: 177 | return AVCaptureVideoOrientationLandscapeLeft; 178 | case UIInterfaceOrientationLandscapeRight: 179 | return AVCaptureVideoOrientationLandscapeRight; 180 | case UIInterfaceOrientationPortrait: 181 | return AVCaptureVideoOrientationPortrait; 182 | default: 183 | return AVCaptureVideoOrientationPortraitUpsideDown; 184 | } 185 | } 186 | 187 | #pragma mark - Checking the Reader Availabilities 188 | 189 | + (BOOL)isAvailable 190 | { 191 | @autoreleasepool { 192 | AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; 193 | 194 | if (!captureDevice) { 195 | return NO; 196 | } 197 | 198 | NSError *error; 199 | AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:&error]; 200 | 201 | if (!deviceInput || error) { 202 | return NO; 203 | } 204 | 205 | return YES; 206 | } 207 | } 208 | 209 | + (BOOL)supportsMetadataObjectTypes:(NSArray *)metadataObjectTypes 210 | { 211 | if (![self isAvailable]) { 212 | return NO; 213 | } 214 | 215 | @autoreleasepool { 216 | // Setup components 217 | AVCaptureDevice *captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; 218 | AVCaptureDeviceInput *deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:captureDevice error:nil]; 219 | AVCaptureMetadataOutput *output = [[AVCaptureMetadataOutput alloc] init]; 220 | AVCaptureSession *session = [[AVCaptureSession alloc] init]; 221 | 222 | [session addInput:deviceInput]; 223 | [session addOutput:output]; 224 | 225 | if (metadataObjectTypes == nil || metadataObjectTypes.count == 0) { 226 | // Check the QRCode metadata object type by default 227 | metadataObjectTypes = @[AVMetadataObjectTypeQRCode]; 228 | } 229 | 230 | for (NSString *metadataObjectType in metadataObjectTypes) { 231 | if (![output.availableMetadataObjectTypes containsObject:metadataObjectType]) { 232 | return NO; 233 | } 234 | } 235 | 236 | return YES; 237 | } 238 | } 239 | 240 | #pragma mark - Managing the Block 241 | 242 | - (void)setCompletionWithBlock:(void (^) (NSString *resultAsString))completionBlock 243 | { 244 | self.completionBlock = completionBlock; 245 | } 246 | 247 | #pragma mark - AVCaptureMetadataOutputObjects Delegate Methods 248 | 249 | - (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection 250 | { 251 | for (AVMetadataObject *current in metadataObjects) { 252 | if ([current isKindOfClass:[AVMetadataMachineReadableCodeObject class]] 253 | && [_metadataObjectTypes containsObject:current.type]) { 254 | NSString *scannedResult = [(AVMetadataMachineReadableCodeObject *)current stringValue]; 255 | 256 | if (_completionBlock) { 257 | _completionBlock(scannedResult); 258 | } 259 | 260 | break; 261 | } 262 | } 263 | } 264 | 265 | @end 266 | -------------------------------------------------------------------------------- /QRCodeReaderViewController/QRCodeReaderViewController.h: -------------------------------------------------------------------------------- 1 | /* 2 | * QRCodeReaderViewController 3 | * 4 | * Copyright 2014-present Yannick Loriot. 5 | * http://yannickloriot.com 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | * 25 | */ 26 | 27 | #import 28 | #import "QRCodeReaderDelegate.h" 29 | #import "QRCodeReader.h" 30 | 31 | /** 32 | * Convenient controller to display a view to scan/read 1D or 2D bar codes like 33 | * the QRCodes. It is based on the `AVFoundation` framework from Apple. It aims 34 | * to replace ZXing or ZBar for iOS 7 and over. 35 | */ 36 | @interface QRCodeReaderViewController : UIViewController 37 | 38 | #pragma mark - Creating and Inializing QRCodeReader Controllers 39 | /** @name Creating and Inializing QRCode Reader Controllers */ 40 | 41 | /** 42 | * @abstract Initializes a view controller to read QRCodes from a displayed 43 | * video preview and a cancel button to be go back. 44 | * @param cancelTitle The title of the cancel button. 45 | * @discussion This convenient method is used to instanciate a reader with 46 | * only one supported metadata object types: the QRCode. 47 | * @see initWithCancelButtonTitle:metadataObjectTypes: 48 | * @since 1.0.0 49 | */ 50 | - (nonnull id)initWithCancelButtonTitle:(nullable NSString *)cancelTitle; 51 | 52 | /** 53 | * @abstract Creates a view controller to read QRCodes from a displayed 54 | * video preview and a cancel button to be go back. 55 | * @param cancelTitle The title of the cancel button. 56 | * @see initWithCancelButtonTitle: 57 | * @since 1.0.0 58 | */ 59 | + (nonnull instancetype)readerWithCancelButtonTitle:(nullable NSString *)cancelTitle; 60 | 61 | /** 62 | * @abstract Initializes a reader view controller with a list of metadata 63 | * object types. 64 | * @param metadataObjectTypes An array of strings identifying the types of 65 | * metadata objects to process. 66 | * @see initWithCancelButtonTitle:metadataObjectTypes: 67 | * @since 3.0.0 68 | */ 69 | - (nonnull id)initWithMetadataObjectTypes:(nonnull NSArray *)metadataObjectTypes; 70 | 71 | /** 72 | * @abstract Creates a reader view controller with a list of metadata object 73 | * types. 74 | * @param metadataObjectTypes An array of strings identifying the types of 75 | * metadata objects to process. 76 | * @see initWithMetadataObjectTypes: 77 | * @since 3.0.0 78 | */ 79 | + (nonnull instancetype)readerWithMetadataObjectTypes:(nonnull NSArray *)metadataObjectTypes; 80 | 81 | /** 82 | * @abstract Initializes a view controller to read wanted metadata object 83 | * types from a displayed video preview and a cancel button to be go back. 84 | * @param cancelTitle The title of the cancel button. 85 | * @param metadataObjectTypes The type (“symbology”) of barcode to scan. 86 | * @see initWithCancelButtonTitle:codeReader: 87 | * @since 2.0.0 88 | */ 89 | - (nonnull id)initWithCancelButtonTitle:(nullable NSString *)cancelTitle metadataObjectTypes:(nonnull NSArray *)metadataObjectTypes; 90 | 91 | /** 92 | * @abstract Creates a view controller to read wanted metadata object types 93 | * from a displayed video preview and a cancel button to be go back. 94 | * @param cancelTitle The title of the cancel button. 95 | * @param metadataObjectTypes The type (“symbology”) of barcode to scan. 96 | * @see initWithCancelButtonTitle:metadataObjectTypes: 97 | * @since 2.0.0 98 | */ 99 | + (nonnull instancetype)readerWithCancelButtonTitle:(nullable NSString *)cancelTitle metadataObjectTypes:(nonnull NSArray *)metadataObjectTypes; 100 | 101 | /** 102 | * @abstract Initializes a view controller using a cancel button title and 103 | * a code reader. 104 | * @param cancelTitle The title of the cancel button. 105 | * @param codeReader The reader to decode the codes. 106 | * @see initWithCancelButtonTitle:codeReader:startScanningAtLoad: 107 | * @since 3.0.0 108 | */ 109 | - (nonnull id)initWithCancelButtonTitle:(nullable NSString *)cancelTitle codeReader:(nonnull QRCodeReader *)codeReader; 110 | 111 | /** 112 | * @abstract Initializes a view controller using a cancel button title and 113 | * a code reader. 114 | * @param cancelTitle The title of the cancel button. 115 | * @param codeReader The reader to decode the codes. 116 | * @see initWithCancelButtonTitle:codeReader: 117 | * @since 3.0.0 118 | */ 119 | + (nonnull instancetype)readerWithCancelButtonTitle:(nullable NSString *)cancelTitle codeReader:(nonnull QRCodeReader *)codeReader; 120 | 121 | /** 122 | * @abstract Initializes a view controller using a cancel button title and 123 | * a code reader. 124 | * @param cancelTitle The title of the cancel button. 125 | * @param codeReader The reader to decode the codes. 126 | * @param startScanningAtLoad Flag to know whether the view controller start 127 | * scanning the codes when the view will appear. 128 | * @see initWithCancelButtonTitle:codeReader: 129 | * @since 3.0.0 130 | */ 131 | - (nonnull id)initWithCancelButtonTitle:(nullable NSString *)cancelTitle codeReader:(nonnull QRCodeReader *)codeReader startScanningAtLoad:(BOOL)startScanningAtLoad; 132 | 133 | /** 134 | * @abstract Initializes a view controller using a cancel button title and 135 | * a code reader. 136 | * @param cancelTitle The title of the cancel button. 137 | * @param codeReader The reader to decode the codes. 138 | * @param startScanningAtLoad Flag to know whether the view controller start 139 | * scanning the codes when the view will appear. 140 | * @see initWithCancelButtonTitle:codeReader:startScanningAtLoad:showSwitchCameraButton:showTorchButton: 141 | * @since 3.0.0 142 | */ 143 | + (nonnull instancetype)readerWithCancelButtonTitle:(nullable NSString *)cancelTitle codeReader:(nonnull QRCodeReader *)codeReader startScanningAtLoad:(BOOL)startScanningAtLoad; 144 | 145 | /** 146 | * @abstract Initializes a view controller using a cancel button title and 147 | * a code reader. 148 | * @param cancelTitle The title of the cancel button. 149 | * @param codeReader The reader to decode the codes. 150 | * @param startScanningAtLoad Flag to know whether the view controller start 151 | * scanning the codes when the view will appear. 152 | * @param showSwitchCameraButton Flag to display the switch camera button. 153 | * @param showTorchButton Flag to know whether the view controller start 154 | * scanning the codes when the view will appear. 155 | * @since 4.0.0 156 | */ 157 | - (nonnull id)initWithCancelButtonTitle:(nullable NSString *)cancelTitle codeReader:(nonnull QRCodeReader *)codeReader startScanningAtLoad:(BOOL)startScanningAtLoad showSwitchCameraButton:(BOOL)showSwitchCameraButton showTorchButton:(BOOL)showTorchButton; 158 | 159 | /** 160 | * @abstract Initializes a view controller using a cancel button title and 161 | * a code reader. 162 | * @param cancelTitle The title of the cancel button. 163 | * @param codeReader The reader to decode the codes. 164 | * @param startScanningAtLoad Flag to know whether the view controller start 165 | * scanning the codes when the view will appear. 166 | * @param showSwitchCameraButton Flag to display the switch camera button. 167 | * @param showTorchButton Flag to know whether the view controller start 168 | * scanning the codes when the view will appear. 169 | * @see initWithCancelButtonTitle:codeReader:startScanningAtLoad:showSwitchCameraButton:showTorchButton: 170 | * @since 4.0.0 171 | */ 172 | + (nonnull instancetype)readerWithCancelButtonTitle:(nullable NSString *)cancelTitle codeReader:(nonnull QRCodeReader *)codeReader startScanningAtLoad:(BOOL)startScanningAtLoad showSwitchCameraButton:(BOOL)showSwitchCameraButton showTorchButton:(BOOL)showTorchButton; 173 | 174 | #pragma mark - Controlling the Reader 175 | /** @name Controlling the Reader */ 176 | 177 | /** 178 | * @abstract Starts scanning the codes. 179 | * @since 3.0.0 180 | */ 181 | - (void)startScanning; 182 | 183 | /** 184 | * @abstract Stops scanning the codes. 185 | * @since 3.0.0 186 | */ 187 | - (void)stopScanning; 188 | 189 | #pragma mark - Managing the Delegate 190 | /** @name Managing the Delegate */ 191 | 192 | /** 193 | * @abstract The object that acts as the delegate of the receiving QRCode 194 | * reader. 195 | * @since 1.0.0 196 | */ 197 | @property (nonatomic, weak) id __nullable delegate; 198 | 199 | /** 200 | * @abstract Sets the completion with a block that executes when a QRCode 201 | * or when the user did stopped the scan. 202 | * @param completionBlock The block to be executed. This block has no 203 | * return value and takes one argument: the `resultAsString`. If the user 204 | * stop the scan and that there is no response the `resultAsString` argument 205 | * is nil. 206 | * @since 1.0.1 207 | */ 208 | - (void)setCompletionWithBlock:(nullable void (^) (NSString * __nullable resultAsString))completionBlock; 209 | 210 | #pragma mark - Managing the Reader 211 | /** @name Managing the Reader */ 212 | 213 | /** 214 | * @abstract The default code reader created with the controller. 215 | * @since 3.0.0 216 | */ 217 | @property (strong, nonatomic, readonly) QRCodeReader * __nonnull codeReader; 218 | 219 | @end 220 | -------------------------------------------------------------------------------- /QRCodeReaderViewController/QRCodeReaderViewController.m: -------------------------------------------------------------------------------- 1 | /* 2 | * QRCodeReaderViewController 3 | * 4 | * Copyright 2014-present Yannick Loriot. 5 | * http://yannickloriot.com 6 | * 7 | * Permission is hereby granted, free of charge, to any person obtaining a copy 8 | * of this software and associated documentation files (the "Software"), to deal 9 | * in the Software without restriction, including without limitation the rights 10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | * copies of the Software, and to permit persons to whom the Software is 12 | * furnished to do so, subject to the following conditions: 13 | * 14 | * The above copyright notice and this permission notice shall be included in 15 | * all copies or substantial portions of the Software. 16 | * 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | * THE SOFTWARE. 24 | * 25 | */ 26 | 27 | #import "QRCodeReaderViewController.h" 28 | #import "QRCameraSwitchButton.h" 29 | #import "QRCodeReaderView.h" 30 | #import "QRToggleTorchButton.h" 31 | 32 | @interface QRCodeReaderViewController () 33 | @property (strong, nonatomic) QRCameraSwitchButton *switchCameraButton; 34 | @property (strong, nonatomic) QRToggleTorchButton *toggleTorchButton; 35 | @property (strong, nonatomic) QRCodeReaderView *cameraView; 36 | @property (strong, nonatomic) UIButton *cancelButton; 37 | @property (strong, nonatomic) QRCodeReader *codeReader; 38 | @property (assign, nonatomic) BOOL startScanningAtLoad; 39 | @property (assign, nonatomic) BOOL showSwitchCameraButton; 40 | @property (assign, nonatomic) BOOL showTorchButton; 41 | 42 | @property (copy, nonatomic) void (^completionBlock) (NSString * __nullable); 43 | 44 | @end 45 | 46 | @implementation QRCodeReaderViewController 47 | 48 | - (void)dealloc 49 | { 50 | [self stopScanning]; 51 | 52 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 53 | } 54 | 55 | - (id)init 56 | { 57 | return [self initWithCancelButtonTitle:nil]; 58 | } 59 | 60 | - (id)initWithCancelButtonTitle:(NSString *)cancelTitle 61 | { 62 | return [self initWithCancelButtonTitle:cancelTitle metadataObjectTypes:@[AVMetadataObjectTypeQRCode]]; 63 | } 64 | 65 | - (id)initWithMetadataObjectTypes:(NSArray *)metadataObjectTypes 66 | { 67 | return [self initWithCancelButtonTitle:nil metadataObjectTypes:metadataObjectTypes]; 68 | } 69 | 70 | - (id)initWithCancelButtonTitle:(NSString *)cancelTitle metadataObjectTypes:(NSArray *)metadataObjectTypes 71 | { 72 | QRCodeReader *reader = [QRCodeReader readerWithMetadataObjectTypes:metadataObjectTypes]; 73 | 74 | return [self initWithCancelButtonTitle:cancelTitle codeReader:reader]; 75 | } 76 | 77 | - (id)initWithCancelButtonTitle:(NSString *)cancelTitle codeReader:(QRCodeReader *)codeReader 78 | { 79 | return [self initWithCancelButtonTitle:cancelTitle codeReader:codeReader startScanningAtLoad:true]; 80 | } 81 | 82 | - (id)initWithCancelButtonTitle:(NSString *)cancelTitle codeReader:(QRCodeReader *)codeReader startScanningAtLoad:(BOOL)startScanningAtLoad 83 | { 84 | return [self initWithCancelButtonTitle:cancelTitle codeReader:codeReader startScanningAtLoad:startScanningAtLoad showSwitchCameraButton:YES showTorchButton:NO]; 85 | } 86 | 87 | - (id)initWithCancelButtonTitle:(nullable NSString *)cancelTitle codeReader:(nonnull QRCodeReader *)codeReader startScanningAtLoad:(BOOL)startScanningAtLoad showSwitchCameraButton:(BOOL)showSwitchCameraButton showTorchButton:(BOOL)showTorchButton 88 | { 89 | if ((self = [super init])) { 90 | self.view.backgroundColor = [UIColor blackColor]; 91 | self.codeReader = codeReader; 92 | self.startScanningAtLoad = startScanningAtLoad; 93 | self.showSwitchCameraButton = showSwitchCameraButton; 94 | self.showTorchButton = showTorchButton; 95 | 96 | if (cancelTitle == nil) { 97 | cancelTitle = NSLocalizedString(@"Cancel", @"Cancel"); 98 | } 99 | 100 | [self setupUIComponentsWithCancelButtonTitle:cancelTitle]; 101 | [self setupAutoLayoutConstraints]; 102 | 103 | [_cameraView.layer insertSublayer:_codeReader.previewLayer atIndex:0]; 104 | 105 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil]; 106 | 107 | __weak __typeof__(self) weakSelf = self; 108 | 109 | [codeReader setCompletionWithBlock:^(NSString *resultAsString) { 110 | if (weakSelf.completionBlock != nil) { 111 | weakSelf.completionBlock(resultAsString); 112 | } 113 | 114 | if (weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(reader:didScanResult:)]) { 115 | [weakSelf.delegate reader:weakSelf didScanResult:resultAsString]; 116 | } 117 | }]; 118 | } 119 | return self; 120 | } 121 | 122 | + (instancetype)readerWithCancelButtonTitle:(NSString *)cancelTitle 123 | { 124 | return [[self alloc] initWithCancelButtonTitle:cancelTitle]; 125 | } 126 | 127 | + (instancetype)readerWithMetadataObjectTypes:(NSArray *)metadataObjectTypes 128 | { 129 | return [[self alloc] initWithMetadataObjectTypes:metadataObjectTypes]; 130 | } 131 | 132 | + (instancetype)readerWithCancelButtonTitle:(NSString *)cancelTitle metadataObjectTypes:(NSArray *)metadataObjectTypes 133 | { 134 | return [[self alloc] initWithCancelButtonTitle:cancelTitle metadataObjectTypes:metadataObjectTypes]; 135 | } 136 | 137 | + (instancetype)readerWithCancelButtonTitle:(NSString *)cancelTitle codeReader:(QRCodeReader *)codeReader 138 | { 139 | return [[self alloc] initWithCancelButtonTitle:cancelTitle codeReader:codeReader]; 140 | } 141 | 142 | + (instancetype)readerWithCancelButtonTitle:(NSString *)cancelTitle codeReader:(QRCodeReader *)codeReader startScanningAtLoad:(BOOL)startScanningAtLoad 143 | { 144 | return [[self alloc] initWithCancelButtonTitle:cancelTitle codeReader:codeReader startScanningAtLoad:startScanningAtLoad]; 145 | } 146 | 147 | + (instancetype)readerWithCancelButtonTitle:(NSString *)cancelTitle codeReader:(QRCodeReader *)codeReader startScanningAtLoad:(BOOL)startScanningAtLoad showSwitchCameraButton:(BOOL)showSwitchCameraButton showTorchButton:(BOOL)showTorchButton 148 | { 149 | return [[self alloc] initWithCancelButtonTitle:cancelTitle codeReader:codeReader startScanningAtLoad:startScanningAtLoad showSwitchCameraButton:showSwitchCameraButton showTorchButton:showTorchButton]; 150 | } 151 | 152 | - (void)viewWillAppear:(BOOL)animated 153 | { 154 | [super viewWillAppear:animated]; 155 | 156 | if (_startScanningAtLoad) { 157 | [self startScanning]; 158 | } 159 | } 160 | 161 | - (void)viewWillDisappear:(BOOL)animated 162 | { 163 | [self stopScanning]; 164 | 165 | [super viewWillDisappear:animated]; 166 | } 167 | 168 | - (void)viewWillLayoutSubviews 169 | { 170 | [super viewWillLayoutSubviews]; 171 | 172 | _codeReader.previewLayer.frame = self.view.bounds; 173 | } 174 | 175 | - (BOOL)shouldAutorotate 176 | { 177 | return YES; 178 | } 179 | 180 | #pragma mark - Controlling the Reader 181 | 182 | - (void)startScanning { 183 | [_codeReader startScanning]; 184 | } 185 | 186 | - (void)stopScanning { 187 | [_codeReader stopScanning]; 188 | } 189 | 190 | #pragma mark - Managing the Orientation 191 | 192 | - (void)orientationChanged:(NSNotification *)notification 193 | { 194 | [_cameraView setNeedsDisplay]; 195 | 196 | if (_codeReader.previewLayer.connection.isVideoOrientationSupported) { 197 | UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; 198 | 199 | _codeReader.previewLayer.connection.videoOrientation = [QRCodeReader videoOrientationFromInterfaceOrientation: 200 | orientation]; 201 | } 202 | } 203 | 204 | #pragma mark - Managing the Block 205 | 206 | - (void)setCompletionWithBlock:(void (^) (NSString *resultAsString))completionBlock 207 | { 208 | self.completionBlock = completionBlock; 209 | } 210 | 211 | #pragma mark - Initializing the AV Components 212 | 213 | - (void)setupUIComponentsWithCancelButtonTitle:(NSString *)cancelButtonTitle 214 | { 215 | self.cameraView = [[QRCodeReaderView alloc] init]; 216 | _cameraView.translatesAutoresizingMaskIntoConstraints = NO; 217 | _cameraView.clipsToBounds = YES; 218 | [self.view addSubview:_cameraView]; 219 | 220 | [_codeReader.previewLayer setFrame:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)]; 221 | 222 | if ([_codeReader.previewLayer.connection isVideoOrientationSupported]) { 223 | UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; 224 | 225 | _codeReader.previewLayer.connection.videoOrientation = [QRCodeReader videoOrientationFromInterfaceOrientation:orientation]; 226 | } 227 | 228 | if (_showSwitchCameraButton && [_codeReader hasFrontDevice]) { 229 | _switchCameraButton = [[QRCameraSwitchButton alloc] init]; 230 | 231 | [_switchCameraButton setTranslatesAutoresizingMaskIntoConstraints:false]; 232 | [_switchCameraButton addTarget:self action:@selector(switchCameraAction:) forControlEvents:UIControlEventTouchUpInside]; 233 | [self.view addSubview:_switchCameraButton]; 234 | } 235 | 236 | if (_showTorchButton && [_codeReader isTorchAvailable]) { 237 | _toggleTorchButton = [[QRToggleTorchButton alloc] init]; 238 | 239 | [_toggleTorchButton setTranslatesAutoresizingMaskIntoConstraints:false]; 240 | [_toggleTorchButton addTarget:self action:@selector(toggleTorchAction:) forControlEvents:UIControlEventTouchUpInside]; 241 | [self.view addSubview:_toggleTorchButton]; 242 | } 243 | 244 | self.cancelButton = [[UIButton alloc] init]; 245 | _cancelButton.translatesAutoresizingMaskIntoConstraints = NO; 246 | [_cancelButton setTitle:cancelButtonTitle forState:UIControlStateNormal]; 247 | [_cancelButton setTitleColor:[UIColor grayColor] forState:UIControlStateHighlighted]; 248 | [_cancelButton addTarget:self action:@selector(cancelAction:) forControlEvents:UIControlEventTouchUpInside]; 249 | [self.view addSubview:_cancelButton]; 250 | } 251 | 252 | - (void)setupAutoLayoutConstraints 253 | { 254 | NSLayoutYAxisAnchor * topLayoutAnchor; 255 | NSLayoutYAxisAnchor * bottomLayoutAnchor; 256 | NSLayoutXAxisAnchor * leftLayoutAnchor; 257 | NSLayoutXAxisAnchor * rightLayoutAnchor; 258 | if (@available(iOS 11.0, *)) { 259 | topLayoutAnchor = self.view.safeAreaLayoutGuide.topAnchor; 260 | bottomLayoutAnchor = self.view.safeAreaLayoutGuide.bottomAnchor; 261 | leftLayoutAnchor = self.view.safeAreaLayoutGuide.leftAnchor; 262 | rightLayoutAnchor = self.view.safeAreaLayoutGuide.rightAnchor; 263 | } else { 264 | topLayoutAnchor = self.topLayoutGuide.topAnchor; 265 | bottomLayoutAnchor = self.bottomLayoutGuide.bottomAnchor; 266 | leftLayoutAnchor = self.view.leftAnchor; 267 | rightLayoutAnchor = self.view.rightAnchor; 268 | } 269 | 270 | NSDictionary *views = NSDictionaryOfVariableBindings(_cameraView, _cancelButton); 271 | 272 | [self.view addConstraints: 273 | [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[_cameraView][_cancelButton(40)]" options:0 metrics:nil views:views]]; 274 | [[bottomLayoutAnchor constraintEqualToAnchor:_cancelButton.bottomAnchor] setActive:YES]; 275 | [self.view addConstraints: 276 | [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[_cameraView]|" options:0 metrics:nil views:views]]; 277 | [self.view addConstraints: 278 | [NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[_cancelButton]-|" options:0 metrics:nil views:views]]; 279 | 280 | if (_switchCameraButton) { 281 | [NSLayoutConstraint activateConstraints:@[ 282 | [topLayoutAnchor constraintEqualToAnchor:_switchCameraButton.topAnchor], 283 | [rightLayoutAnchor constraintEqualToAnchor:_switchCameraButton.rightAnchor], 284 | [_switchCameraButton.heightAnchor constraintEqualToConstant:50], 285 | [_switchCameraButton.widthAnchor constraintEqualToConstant:70] 286 | ]]; 287 | } 288 | 289 | if (_toggleTorchButton) { 290 | [NSLayoutConstraint activateConstraints:@[ 291 | [topLayoutAnchor constraintEqualToAnchor:_toggleTorchButton.topAnchor], 292 | [leftLayoutAnchor constraintEqualToAnchor:_toggleTorchButton.leftAnchor], 293 | [_toggleTorchButton.heightAnchor constraintEqualToConstant:50], 294 | [_toggleTorchButton.widthAnchor constraintEqualToConstant:70] 295 | ]]; 296 | } 297 | } 298 | 299 | - (void)switchDeviceInput 300 | { 301 | [_codeReader switchDeviceInput]; 302 | } 303 | 304 | #pragma mark - Catching Button Events 305 | 306 | - (void)cancelAction:(UIButton *)button 307 | { 308 | [_codeReader stopScanning]; 309 | 310 | if (_completionBlock) { 311 | _completionBlock(nil); 312 | } 313 | 314 | if (_delegate && [_delegate respondsToSelector:@selector(readerDidCancel:)]) { 315 | [_delegate readerDidCancel:self]; 316 | } 317 | } 318 | 319 | - (void)switchCameraAction:(UIButton *)button 320 | { 321 | [self switchDeviceInput]; 322 | } 323 | 324 | - (void)toggleTorchAction:(UIButton *)button 325 | { 326 | [_codeReader toggleTorch]; 327 | } 328 | 329 | @end 330 | -------------------------------------------------------------------------------- /Example/QRCodeReaderViewControllerExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | CE29601E1987F124008FA93B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = CE29601D1987F124008FA93B /* main.m */; }; 11 | CE2960211987F124008FA93B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = CE2960201987F124008FA93B /* AppDelegate.m */; }; 12 | CE2960241987F124008FA93B /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE2960231987F124008FA93B /* ViewController.m */; }; 13 | CE2960271987F124008FA93B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CE2960251987F124008FA93B /* Main.storyboard */; }; 14 | CE2960291987F124008FA93B /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CE2960281987F124008FA93B /* Images.xcassets */; }; 15 | CE2960421987F140008FA93B /* QRCodeReaderViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE2960411987F140008FA93B /* QRCodeReaderViewController.m */; }; 16 | CE99CEFD1A9BCA1100CB8AD8 /* QRCodeReader.m in Sources */ = {isa = PBXBuildFile; fileRef = CE99CEFC1A9BCA1100CB8AD8 /* QRCodeReader.m */; }; 17 | CEAE68221D3EB66400A77AB2 /* QRCodeReaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CEAE68211D3EB66400A77AB2 /* QRCodeReaderTests.m */; }; 18 | CEAE68291D3EB78300A77AB2 /* QRCodeReaderViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = CE2960411987F140008FA93B /* QRCodeReaderViewController.m */; }; 19 | CEAE682A1D3EB78300A77AB2 /* QRCodeReaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = CEAF7A651A16A31600991CF8 /* QRCodeReaderView.m */; }; 20 | CEAE682B1D3EB78300A77AB2 /* QRCodeReader.m in Sources */ = {isa = PBXBuildFile; fileRef = CE99CEFC1A9BCA1100CB8AD8 /* QRCodeReader.m */; }; 21 | CEAE682C1D3EB78300A77AB2 /* QRCameraSwitchButton.m in Sources */ = {isa = PBXBuildFile; fileRef = CEAF7A681A16B05400991CF8 /* QRCameraSwitchButton.m */; }; 22 | CEAE682D1D3EB78300A77AB2 /* QRToggleTorchButton.m in Sources */ = {isa = PBXBuildFile; fileRef = CEF6D1631BE7B2B0006D575D /* QRToggleTorchButton.m */; }; 23 | CEAF7A661A16A31600991CF8 /* QRCodeReaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = CEAF7A651A16A31600991CF8 /* QRCodeReaderView.m */; }; 24 | CEAF7A691A16B05400991CF8 /* QRCameraSwitchButton.m in Sources */ = {isa = PBXBuildFile; fileRef = CEAF7A681A16B05400991CF8 /* QRCameraSwitchButton.m */; }; 25 | CEF6D1641BE7B2B0006D575D /* QRToggleTorchButton.m in Sources */ = {isa = PBXBuildFile; fileRef = CEF6D1631BE7B2B0006D575D /* QRToggleTorchButton.m */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXContainerItemProxy section */ 29 | CEAE68241D3EB66400A77AB2 /* PBXContainerItemProxy */ = { 30 | isa = PBXContainerItemProxy; 31 | containerPortal = CE2960101987F124008FA93B /* Project object */; 32 | proxyType = 1; 33 | remoteGlobalIDString = CE2960171987F124008FA93B; 34 | remoteInfo = QRCodeReaderViewControllerExample; 35 | }; 36 | /* End PBXContainerItemProxy section */ 37 | 38 | /* Begin PBXFileReference section */ 39 | CE2960181987F124008FA93B /* QRCodeReaderViewControllerExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = QRCodeReaderViewControllerExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 40 | CE29601C1987F124008FA93B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 41 | CE29601D1987F124008FA93B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 42 | CE29601F1987F124008FA93B /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 43 | CE2960201987F124008FA93B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 44 | CE2960221987F124008FA93B /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 45 | CE2960231987F124008FA93B /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 46 | CE2960261987F124008FA93B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 47 | CE2960281987F124008FA93B /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 48 | CE29603F1987F140008FA93B /* QRCodeReaderDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QRCodeReaderDelegate.h; sourceTree = ""; }; 49 | CE2960401987F140008FA93B /* QRCodeReaderViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QRCodeReaderViewController.h; sourceTree = ""; }; 50 | CE2960411987F140008FA93B /* QRCodeReaderViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QRCodeReaderViewController.m; sourceTree = ""; }; 51 | CE99CEFB1A9BCA1100CB8AD8 /* QRCodeReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QRCodeReader.h; sourceTree = ""; }; 52 | CE99CEFC1A9BCA1100CB8AD8 /* QRCodeReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QRCodeReader.m; sourceTree = ""; }; 53 | CEAE681F1D3EB66400A77AB2 /* QRCodeReaderViewControllerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = QRCodeReaderViewControllerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 54 | CEAE68211D3EB66400A77AB2 /* QRCodeReaderTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = QRCodeReaderTests.m; sourceTree = ""; }; 55 | CEAE68231D3EB66400A77AB2 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 56 | CEAF7A641A16A31600991CF8 /* QRCodeReaderView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QRCodeReaderView.h; sourceTree = ""; }; 57 | CEAF7A651A16A31600991CF8 /* QRCodeReaderView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QRCodeReaderView.m; sourceTree = ""; }; 58 | CEAF7A671A16B05400991CF8 /* QRCameraSwitchButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QRCameraSwitchButton.h; sourceTree = ""; }; 59 | CEAF7A681A16B05400991CF8 /* QRCameraSwitchButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QRCameraSwitchButton.m; sourceTree = ""; }; 60 | CEF6D1621BE7B2B0006D575D /* QRToggleTorchButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QRToggleTorchButton.h; sourceTree = ""; }; 61 | CEF6D1631BE7B2B0006D575D /* QRToggleTorchButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QRToggleTorchButton.m; sourceTree = ""; }; 62 | /* End PBXFileReference section */ 63 | 64 | /* Begin PBXFrameworksBuildPhase section */ 65 | CE2960151987F124008FA93B /* Frameworks */ = { 66 | isa = PBXFrameworksBuildPhase; 67 | buildActionMask = 2147483647; 68 | files = ( 69 | ); 70 | runOnlyForDeploymentPostprocessing = 0; 71 | }; 72 | CEAE681C1D3EB66400A77AB2 /* Frameworks */ = { 73 | isa = PBXFrameworksBuildPhase; 74 | buildActionMask = 2147483647; 75 | files = ( 76 | ); 77 | runOnlyForDeploymentPostprocessing = 0; 78 | }; 79 | /* End PBXFrameworksBuildPhase section */ 80 | 81 | /* Begin PBXGroup section */ 82 | CE29600F1987F124008FA93B = { 83 | isa = PBXGroup; 84 | children = ( 85 | CE29603E1987F140008FA93B /* QRCodeReaderViewController */, 86 | CE29601A1987F124008FA93B /* QRCodeReaderViewControllerExample */, 87 | CEAE68201D3EB66400A77AB2 /* QRCodeReaderViewControllerTests */, 88 | CE2960191987F124008FA93B /* Products */, 89 | ); 90 | sourceTree = ""; 91 | }; 92 | CE2960191987F124008FA93B /* Products */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | CE2960181987F124008FA93B /* QRCodeReaderViewControllerExample.app */, 96 | CEAE681F1D3EB66400A77AB2 /* QRCodeReaderViewControllerTests.xctest */, 97 | ); 98 | name = Products; 99 | sourceTree = ""; 100 | }; 101 | CE29601A1987F124008FA93B /* QRCodeReaderViewControllerExample */ = { 102 | isa = PBXGroup; 103 | children = ( 104 | CE29601F1987F124008FA93B /* AppDelegate.h */, 105 | CE2960201987F124008FA93B /* AppDelegate.m */, 106 | CE2960221987F124008FA93B /* ViewController.h */, 107 | CE2960231987F124008FA93B /* ViewController.m */, 108 | CE2960251987F124008FA93B /* Main.storyboard */, 109 | CE2960281987F124008FA93B /* Images.xcassets */, 110 | CE29601B1987F124008FA93B /* Supporting Files */, 111 | ); 112 | path = QRCodeReaderViewControllerExample; 113 | sourceTree = ""; 114 | }; 115 | CE29601B1987F124008FA93B /* Supporting Files */ = { 116 | isa = PBXGroup; 117 | children = ( 118 | CE29601C1987F124008FA93B /* Info.plist */, 119 | CE29601D1987F124008FA93B /* main.m */, 120 | ); 121 | name = "Supporting Files"; 122 | sourceTree = ""; 123 | }; 124 | CE29603E1987F140008FA93B /* QRCodeReaderViewController */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | CE29603F1987F140008FA93B /* QRCodeReaderDelegate.h */, 128 | CE2960401987F140008FA93B /* QRCodeReaderViewController.h */, 129 | CE2960411987F140008FA93B /* QRCodeReaderViewController.m */, 130 | CEAF7A641A16A31600991CF8 /* QRCodeReaderView.h */, 131 | CEAF7A651A16A31600991CF8 /* QRCodeReaderView.m */, 132 | CE99CEFB1A9BCA1100CB8AD8 /* QRCodeReader.h */, 133 | CE99CEFC1A9BCA1100CB8AD8 /* QRCodeReader.m */, 134 | CEAF7A671A16B05400991CF8 /* QRCameraSwitchButton.h */, 135 | CEAF7A681A16B05400991CF8 /* QRCameraSwitchButton.m */, 136 | CEF6D1621BE7B2B0006D575D /* QRToggleTorchButton.h */, 137 | CEF6D1631BE7B2B0006D575D /* QRToggleTorchButton.m */, 138 | ); 139 | name = QRCodeReaderViewController; 140 | path = ../QRCodeReaderViewController; 141 | sourceTree = ""; 142 | }; 143 | CEAE68201D3EB66400A77AB2 /* QRCodeReaderViewControllerTests */ = { 144 | isa = PBXGroup; 145 | children = ( 146 | CEAE68211D3EB66400A77AB2 /* QRCodeReaderTests.m */, 147 | CEAE68231D3EB66400A77AB2 /* Info.plist */, 148 | ); 149 | path = QRCodeReaderViewControllerTests; 150 | sourceTree = ""; 151 | }; 152 | /* End PBXGroup section */ 153 | 154 | /* Begin PBXNativeTarget section */ 155 | CE2960171987F124008FA93B /* QRCodeReaderViewControllerExample */ = { 156 | isa = PBXNativeTarget; 157 | buildConfigurationList = CE2960381987F125008FA93B /* Build configuration list for PBXNativeTarget "QRCodeReaderViewControllerExample" */; 158 | buildPhases = ( 159 | CE2960141987F124008FA93B /* Sources */, 160 | CE2960151987F124008FA93B /* Frameworks */, 161 | CE2960161987F124008FA93B /* Resources */, 162 | ); 163 | buildRules = ( 164 | ); 165 | dependencies = ( 166 | ); 167 | name = QRCodeReaderViewControllerExample; 168 | productName = QRCodeReaderViewControllerExample; 169 | productReference = CE2960181987F124008FA93B /* QRCodeReaderViewControllerExample.app */; 170 | productType = "com.apple.product-type.application"; 171 | }; 172 | CEAE681E1D3EB66400A77AB2 /* QRCodeReaderViewControllerTests */ = { 173 | isa = PBXNativeTarget; 174 | buildConfigurationList = CEAE68281D3EB66400A77AB2 /* Build configuration list for PBXNativeTarget "QRCodeReaderViewControllerTests" */; 175 | buildPhases = ( 176 | CEAE681B1D3EB66400A77AB2 /* Sources */, 177 | CEAE681C1D3EB66400A77AB2 /* Frameworks */, 178 | CEAE681D1D3EB66400A77AB2 /* Resources */, 179 | ); 180 | buildRules = ( 181 | ); 182 | dependencies = ( 183 | CEAE68251D3EB66400A77AB2 /* PBXTargetDependency */, 184 | ); 185 | name = QRCodeReaderViewControllerTests; 186 | productName = QRCodeReaderViewControllerTests; 187 | productReference = CEAE681F1D3EB66400A77AB2 /* QRCodeReaderViewControllerTests.xctest */; 188 | productType = "com.apple.product-type.bundle.unit-test"; 189 | }; 190 | /* End PBXNativeTarget section */ 191 | 192 | /* Begin PBXProject section */ 193 | CE2960101987F124008FA93B /* Project object */ = { 194 | isa = PBXProject; 195 | attributes = { 196 | LastUpgradeCheck = 0710; 197 | ORGANIZATIONNAME = "Yannick Loriot"; 198 | TargetAttributes = { 199 | CE2960171987F124008FA93B = { 200 | CreatedOnToolsVersion = 6.0; 201 | }; 202 | CEAE681E1D3EB66400A77AB2 = { 203 | CreatedOnToolsVersion = 7.3; 204 | TestTargetID = CE2960171987F124008FA93B; 205 | }; 206 | }; 207 | }; 208 | buildConfigurationList = CE2960131987F124008FA93B /* Build configuration list for PBXProject "QRCodeReaderViewControllerExample" */; 209 | compatibilityVersion = "Xcode 3.2"; 210 | developmentRegion = English; 211 | hasScannedForEncodings = 0; 212 | knownRegions = ( 213 | en, 214 | Base, 215 | ); 216 | mainGroup = CE29600F1987F124008FA93B; 217 | productRefGroup = CE2960191987F124008FA93B /* Products */; 218 | projectDirPath = ""; 219 | projectRoot = ""; 220 | targets = ( 221 | CE2960171987F124008FA93B /* QRCodeReaderViewControllerExample */, 222 | CEAE681E1D3EB66400A77AB2 /* QRCodeReaderViewControllerTests */, 223 | ); 224 | }; 225 | /* End PBXProject section */ 226 | 227 | /* Begin PBXResourcesBuildPhase section */ 228 | CE2960161987F124008FA93B /* Resources */ = { 229 | isa = PBXResourcesBuildPhase; 230 | buildActionMask = 2147483647; 231 | files = ( 232 | CE2960271987F124008FA93B /* Main.storyboard in Resources */, 233 | CE2960291987F124008FA93B /* Images.xcassets in Resources */, 234 | ); 235 | runOnlyForDeploymentPostprocessing = 0; 236 | }; 237 | CEAE681D1D3EB66400A77AB2 /* Resources */ = { 238 | isa = PBXResourcesBuildPhase; 239 | buildActionMask = 2147483647; 240 | files = ( 241 | ); 242 | runOnlyForDeploymentPostprocessing = 0; 243 | }; 244 | /* End PBXResourcesBuildPhase section */ 245 | 246 | /* Begin PBXSourcesBuildPhase section */ 247 | CE2960141987F124008FA93B /* Sources */ = { 248 | isa = PBXSourcesBuildPhase; 249 | buildActionMask = 2147483647; 250 | files = ( 251 | CE2960241987F124008FA93B /* ViewController.m in Sources */, 252 | CEF6D1641BE7B2B0006D575D /* QRToggleTorchButton.m in Sources */, 253 | CEAF7A691A16B05400991CF8 /* QRCameraSwitchButton.m in Sources */, 254 | CE99CEFD1A9BCA1100CB8AD8 /* QRCodeReader.m in Sources */, 255 | CE2960211987F124008FA93B /* AppDelegate.m in Sources */, 256 | CEAF7A661A16A31600991CF8 /* QRCodeReaderView.m in Sources */, 257 | CE29601E1987F124008FA93B /* main.m in Sources */, 258 | CE2960421987F140008FA93B /* QRCodeReaderViewController.m in Sources */, 259 | ); 260 | runOnlyForDeploymentPostprocessing = 0; 261 | }; 262 | CEAE681B1D3EB66400A77AB2 /* Sources */ = { 263 | isa = PBXSourcesBuildPhase; 264 | buildActionMask = 2147483647; 265 | files = ( 266 | CEAE682A1D3EB78300A77AB2 /* QRCodeReaderView.m in Sources */, 267 | CEAE682D1D3EB78300A77AB2 /* QRToggleTorchButton.m in Sources */, 268 | CEAE68221D3EB66400A77AB2 /* QRCodeReaderTests.m in Sources */, 269 | CEAE682C1D3EB78300A77AB2 /* QRCameraSwitchButton.m in Sources */, 270 | CEAE682B1D3EB78300A77AB2 /* QRCodeReader.m in Sources */, 271 | CEAE68291D3EB78300A77AB2 /* QRCodeReaderViewController.m in Sources */, 272 | ); 273 | runOnlyForDeploymentPostprocessing = 0; 274 | }; 275 | /* End PBXSourcesBuildPhase section */ 276 | 277 | /* Begin PBXTargetDependency section */ 278 | CEAE68251D3EB66400A77AB2 /* PBXTargetDependency */ = { 279 | isa = PBXTargetDependency; 280 | target = CE2960171987F124008FA93B /* QRCodeReaderViewControllerExample */; 281 | targetProxy = CEAE68241D3EB66400A77AB2 /* PBXContainerItemProxy */; 282 | }; 283 | /* End PBXTargetDependency section */ 284 | 285 | /* Begin PBXVariantGroup section */ 286 | CE2960251987F124008FA93B /* Main.storyboard */ = { 287 | isa = PBXVariantGroup; 288 | children = ( 289 | CE2960261987F124008FA93B /* Base */, 290 | ); 291 | name = Main.storyboard; 292 | sourceTree = ""; 293 | }; 294 | /* End PBXVariantGroup section */ 295 | 296 | /* Begin XCBuildConfiguration section */ 297 | CE2960361987F125008FA93B /* Debug */ = { 298 | isa = XCBuildConfiguration; 299 | buildSettings = { 300 | ALWAYS_SEARCH_USER_PATHS = NO; 301 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 302 | CLANG_CXX_LIBRARY = "libc++"; 303 | CLANG_ENABLE_MODULES = YES; 304 | CLANG_ENABLE_OBJC_ARC = YES; 305 | CLANG_WARN_BOOL_CONVERSION = YES; 306 | CLANG_WARN_CONSTANT_CONVERSION = YES; 307 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 308 | CLANG_WARN_EMPTY_BODY = YES; 309 | CLANG_WARN_ENUM_CONVERSION = YES; 310 | CLANG_WARN_INT_CONVERSION = YES; 311 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 312 | CLANG_WARN_UNREACHABLE_CODE = YES; 313 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 314 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 315 | COPY_PHASE_STRIP = NO; 316 | ENABLE_STRICT_OBJC_MSGSEND = YES; 317 | ENABLE_TESTABILITY = YES; 318 | GCC_C_LANGUAGE_STANDARD = gnu99; 319 | GCC_DYNAMIC_NO_PIC = NO; 320 | GCC_OPTIMIZATION_LEVEL = 0; 321 | GCC_PREPROCESSOR_DEFINITIONS = ( 322 | "DEBUG=1", 323 | "$(inherited)", 324 | ); 325 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 326 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 327 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 328 | GCC_WARN_UNDECLARED_SELECTOR = YES; 329 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 330 | GCC_WARN_UNUSED_FUNCTION = YES; 331 | GCC_WARN_UNUSED_VARIABLE = YES; 332 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 333 | MTL_ENABLE_DEBUG_INFO = YES; 334 | ONLY_ACTIVE_ARCH = YES; 335 | SDKROOT = iphoneos; 336 | TARGETED_DEVICE_FAMILY = "1,2"; 337 | }; 338 | name = Debug; 339 | }; 340 | CE2960371987F125008FA93B /* Release */ = { 341 | isa = XCBuildConfiguration; 342 | buildSettings = { 343 | ALWAYS_SEARCH_USER_PATHS = NO; 344 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 345 | CLANG_CXX_LIBRARY = "libc++"; 346 | CLANG_ENABLE_MODULES = YES; 347 | CLANG_ENABLE_OBJC_ARC = YES; 348 | CLANG_WARN_BOOL_CONVERSION = YES; 349 | CLANG_WARN_CONSTANT_CONVERSION = YES; 350 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 351 | CLANG_WARN_EMPTY_BODY = YES; 352 | CLANG_WARN_ENUM_CONVERSION = YES; 353 | CLANG_WARN_INT_CONVERSION = YES; 354 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 355 | CLANG_WARN_UNREACHABLE_CODE = YES; 356 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 357 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 358 | COPY_PHASE_STRIP = YES; 359 | ENABLE_NS_ASSERTIONS = NO; 360 | ENABLE_STRICT_OBJC_MSGSEND = YES; 361 | GCC_C_LANGUAGE_STANDARD = gnu99; 362 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 363 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 364 | GCC_WARN_UNDECLARED_SELECTOR = YES; 365 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 366 | GCC_WARN_UNUSED_FUNCTION = YES; 367 | GCC_WARN_UNUSED_VARIABLE = YES; 368 | IPHONEOS_DEPLOYMENT_TARGET = 7.0; 369 | MTL_ENABLE_DEBUG_INFO = NO; 370 | SDKROOT = iphoneos; 371 | TARGETED_DEVICE_FAMILY = "1,2"; 372 | VALIDATE_PRODUCT = YES; 373 | }; 374 | name = Release; 375 | }; 376 | CE2960391987F125008FA93B /* Debug */ = { 377 | isa = XCBuildConfiguration; 378 | buildSettings = { 379 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 380 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 381 | CODE_SIGN_IDENTITY = "iPhone Developer"; 382 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 383 | DEVELOPMENT_TEAM = ""; 384 | INFOPLIST_FILE = QRCodeReaderViewControllerExample/Info.plist; 385 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 386 | PRODUCT_BUNDLE_IDENTIFIER = "com.yannickloriot.${PRODUCT_NAME:rfc1034identifier}"; 387 | PRODUCT_NAME = "$(TARGET_NAME)"; 388 | PROVISIONING_PROFILE = ""; 389 | }; 390 | name = Debug; 391 | }; 392 | CE29603A1987F125008FA93B /* Release */ = { 393 | isa = XCBuildConfiguration; 394 | buildSettings = { 395 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 396 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 397 | CODE_SIGN_IDENTITY = "iPhone Developer"; 398 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 399 | DEVELOPMENT_TEAM = ""; 400 | INFOPLIST_FILE = QRCodeReaderViewControllerExample/Info.plist; 401 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 402 | PRODUCT_BUNDLE_IDENTIFIER = "com.yannickloriot.${PRODUCT_NAME:rfc1034identifier}"; 403 | PRODUCT_NAME = "$(TARGET_NAME)"; 404 | PROVISIONING_PROFILE = ""; 405 | }; 406 | name = Release; 407 | }; 408 | CEAE68261D3EB66400A77AB2 /* Debug */ = { 409 | isa = XCBuildConfiguration; 410 | buildSettings = { 411 | BUNDLE_LOADER = "$(TEST_HOST)"; 412 | CLANG_ANALYZER_NONNULL = YES; 413 | DEBUG_INFORMATION_FORMAT = dwarf; 414 | GCC_NO_COMMON_BLOCKS = YES; 415 | INFOPLIST_FILE = QRCodeReaderViewControllerTests/Info.plist; 416 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 417 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 418 | PRODUCT_BUNDLE_IDENTIFIER = com.yannickloriot.QRCodeReaderViewControllerTests; 419 | PRODUCT_NAME = "$(TARGET_NAME)"; 420 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/QRCodeReaderViewControllerExample.app/QRCodeReaderViewControllerExample"; 421 | }; 422 | name = Debug; 423 | }; 424 | CEAE68271D3EB66400A77AB2 /* Release */ = { 425 | isa = XCBuildConfiguration; 426 | buildSettings = { 427 | BUNDLE_LOADER = "$(TEST_HOST)"; 428 | CLANG_ANALYZER_NONNULL = YES; 429 | COPY_PHASE_STRIP = NO; 430 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 431 | GCC_NO_COMMON_BLOCKS = YES; 432 | INFOPLIST_FILE = QRCodeReaderViewControllerTests/Info.plist; 433 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 434 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 435 | PRODUCT_BUNDLE_IDENTIFIER = com.yannickloriot.QRCodeReaderViewControllerTests; 436 | PRODUCT_NAME = "$(TARGET_NAME)"; 437 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/QRCodeReaderViewControllerExample.app/QRCodeReaderViewControllerExample"; 438 | }; 439 | name = Release; 440 | }; 441 | /* End XCBuildConfiguration section */ 442 | 443 | /* Begin XCConfigurationList section */ 444 | CE2960131987F124008FA93B /* Build configuration list for PBXProject "QRCodeReaderViewControllerExample" */ = { 445 | isa = XCConfigurationList; 446 | buildConfigurations = ( 447 | CE2960361987F125008FA93B /* Debug */, 448 | CE2960371987F125008FA93B /* Release */, 449 | ); 450 | defaultConfigurationIsVisible = 0; 451 | defaultConfigurationName = Release; 452 | }; 453 | CE2960381987F125008FA93B /* Build configuration list for PBXNativeTarget "QRCodeReaderViewControllerExample" */ = { 454 | isa = XCConfigurationList; 455 | buildConfigurations = ( 456 | CE2960391987F125008FA93B /* Debug */, 457 | CE29603A1987F125008FA93B /* Release */, 458 | ); 459 | defaultConfigurationIsVisible = 0; 460 | defaultConfigurationName = Release; 461 | }; 462 | CEAE68281D3EB66400A77AB2 /* Build configuration list for PBXNativeTarget "QRCodeReaderViewControllerTests" */ = { 463 | isa = XCConfigurationList; 464 | buildConfigurations = ( 465 | CEAE68261D3EB66400A77AB2 /* Debug */, 466 | CEAE68271D3EB66400A77AB2 /* Release */, 467 | ); 468 | defaultConfigurationIsVisible = 0; 469 | defaultConfigurationName = Release; 470 | }; 471 | /* End XCConfigurationList section */ 472 | }; 473 | rootObject = CE2960101987F124008FA93B /* Project object */; 474 | } 475 | --------------------------------------------------------------------------------