├── 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 | 
2 |
3 |
4 |
5 |
6 |
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 | 
14 |
15 |
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 |
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 |
--------------------------------------------------------------------------------