├── CODEOWNERS
├── .gitignore
├── Package.swift
├── Fingertips.podspec
├── Fingertips.xcodeproj
├── Info.plist
├── xcshareddata
│ └── xcschemes
│ │ └── Fingertips.xcscheme
└── project.pbxproj
├── LICENSE.md
├── README.md
└── Sources
└── Fingertips
└── FingerTipWindow.swift
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @OdNairy
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | README-VENDOR-BRANCH.txt
2 |
3 | # Xcode
4 | build/*
5 | *.pbxuser
6 | !default.pbxuser
7 | *.mode1v3
8 | !default.mode1v3
9 | *.mode2v3
10 | !default.mode2v3
11 | *.perspectivev3
12 | !default.perspectivev3
13 | *.xcworkspace
14 | !default.xcworkspace
15 | xcuserdata
16 | profile
17 | *.moved-aside
18 |
19 | Carthage/Build
20 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.0
2 | import PackageDescription
3 |
4 | let package = Package(
5 | name: "Fingertips",
6 | platforms: [.iOS(.v11)],
7 | products: [
8 | .library(name: "Fingertips", targets: ["Fingertips"]),
9 | ],
10 | targets: [
11 | .target(
12 | name: "Fingertips",
13 | dependencies: [],
14 | publicHeadersPath: ".")
15 | ]
16 | )
17 |
--------------------------------------------------------------------------------
/Fingertips.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |f|
2 |
3 | f.name = 'Fingertips'
4 | f.version = '0.6.0'
5 |
6 | f.summary = 'Touch indicators on external displays for iOS applications.'
7 | f.description = 'Touch indicators on external displays for iOS applications, giving you automatic presentation mode using a simple UIWindow subclass.'
8 | f.homepage = 'https://github.com/mapbox/Fingertips'
9 | f.license = 'BSD'
10 | f.author = { 'Mapbox' => 'mobile@mapbox.com' }
11 | f.social_media_url = 'https://twitter.com/Mapbox'
12 |
13 | f.source = { :git => 'https://github.com/mapbox/Fingertips.git', :tag => "v#{f.version.to_s}" }
14 |
15 | f.platform = :ios, '11.0'
16 |
17 | f.source_files = 'Sources/Fingertips/*.{swift}'
18 |
19 | f.swift_version = '5'
20 |
21 | f.framework = 'UIKit'
22 |
23 | end
24 |
--------------------------------------------------------------------------------
/Fingertips.xcodeproj/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 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(CURRENT_PROJECT_VERSION)
23 | NSPrincipalClass
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright (c) 2011-2013, Mapbox, Inc.
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright
11 | notice, this list of conditions and the following disclaimer in the
12 | documentation and/or other materials provided with the distribution.
13 |
14 | * Neither the name of MapBox, Inc., nor the names of its contributors
15 | may be used to endorse or promote products derived from this software
16 | without specific prior written permission.
17 |
18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
22 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 |
--------------------------------------------------------------------------------
/Fingertips.xcodeproj/xcshareddata/xcschemes/Fingertips.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
52 |
53 |
59 |
60 |
66 |
67 |
68 |
69 |
71 |
72 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Fingertips
2 |
3 | [](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmapbox%2FFingertips?ref=badge_shield)
4 |
5 | ## Presentation mode for your iOS app
6 |
7 | Fingertips is a small library (one class) meant for presentations from iOS devices that shows all touches and gestures so that the audience can see them.
8 |
9 | **This library does not do the mirroring or screen recording for you!**
10 |
11 | Just drop in our replacement `UIWindow` subclass and your app will automatically determine when you are in the screen recording or an external screen is available. It will show every touch on-screen with a nice partially-transparent graphic that automatically fades out when the touch ends.
12 |
13 | If you are using storyboards, the easiest way to integrate Fingertips is to override the `window` method of your application delegate like this:
14 |
15 | ```objc
16 | // AppDelegate.m
17 |
18 | - (UIWindow *)window {
19 | if (!_window) {
20 | _window = [[MBFingerTipWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
21 | }
22 | return _window;
23 | }
24 | ```
25 |
26 | ```swift
27 | // AppDelegate.swift (Swift)
28 |
29 | var window: UIWindow? = FingerTipWindow(frame: UIScreen.main.bounds)
30 | ```
31 |
32 | For iOS 13+ with UISceneDelegate:
33 |
34 | ```swift
35 | var windows: [UIWindow] = []
36 |
37 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
38 | guard let windowScene = scene as? UIWindowScene else { return }
39 |
40 | let window = FingerTipWindow(windowScene: windowScene)
41 |
42 | window.rootViewController = // Your root view controller
43 | window.makeKeyAndVisible()
44 |
45 | windows.append(window)
46 | }
47 |
48 | ```
49 |
50 | Fingertips require iOS 11.0 or greater and ARC. It uses **no private API** and is safe for App Store submissions.
51 |
52 | https://github.com/mapbox/Fingertips/assets/735178/833f659e-b549-4e74-ae27-e695f37717b6
53 |
54 | ## Configuration
55 |
56 | You shouldn't need to configure anything, but if you want to tweak some knobs:
57 |
58 | * `touchImage`: pass a `UIImage` to use for showing touches
59 | * `touchAlpha`: change the visible-touch alpha transparency
60 | * `fadeDuration`: change how long lifted touches fade out
61 | * `strokeColor`: change default `touchImage` stroke color (defaults to black)
62 | * `fillColor`: change default `touchImage` fill color (defaults to white)
63 |
64 | If you ever need to debug Fingertips, just set the `DEBUG_FINGERTIP_WINDOW` environment variable to `YES` in Xcode or set the runtime property `alwaysShowTouches` to `YES`.
65 |
66 | ## License
67 |
68 | Copyright (c) 2011-2023 Mapbox, Inc.
69 |
70 | The Fingertips library should be accompanied by a LICENSE file. This file contains the license relevant to this distribution. If no license exists, please contact [Mapbox](http://mapbox.com).
71 |
72 | [](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmapbox%2FFingertips?ref=badge_large)
73 |
--------------------------------------------------------------------------------
/Sources/Fingertips/FingerTipWindow.swift:
--------------------------------------------------------------------------------
1 | // Copyright 2011-2023 Mapbox, Inc. All rights reserved.
2 |
3 | import Foundation
4 | import UIKit
5 |
6 | @objc(MBXFingerTipView)
7 | class FingerTipView: UIImageView {
8 | var timestamp: TimeInterval?
9 | var shouldAutomaticallyRemoveAfterTimeout: Bool?
10 | var fadingOut: Bool = false
11 | }
12 |
13 | @objc (MBXFingerTipOverlayWindow)
14 | class FingerTipOverlayWindow: UIWindow {}
15 |
16 | @objc (MBXFingerTipWindow)
17 | open class FingerTipWindow: UIWindow {
18 |
19 | public static var fingerTipWindow: FingerTipWindow? {
20 | return UIApplication.shared.windows.compactMap({ $0 as? FingerTipWindow }).first
21 | }
22 |
23 | public var touchAlpha: CGFloat = 0.5
24 | public var fadeDuration: TimeInterval = 0.3
25 | public var strokeColor: UIColor = .black
26 | public var fillColor: UIColor = .white
27 |
28 | private var active: Bool = false
29 |
30 | /// Force touch display when no external screen is connected or no video recording is going
31 | public var alwaysShowTouches: Bool = false {
32 | didSet {
33 | if oldValue != alwaysShowTouches {
34 | updateFingertipsAreActive()
35 | }
36 | }
37 | }
38 |
39 | lazy var touchImage: UIImage = {
40 | let clipPath = UIBezierPath(rect: CGRect(x: 0, y: 0, width: 50, height: 50))
41 |
42 | UIGraphicsBeginImageContextWithOptions(clipPath.bounds.size, false, 0)
43 | defer { UIGraphicsEndImageContext() }
44 |
45 | let drawPath = UIBezierPath(arcCenter: CGPoint(x: 25, y: 25), radius: 22, startAngle: 0, endAngle: 2 * .pi, clockwise: true)
46 | drawPath.lineWidth = 2
47 |
48 | strokeColor.setStroke()
49 | fillColor.setFill()
50 |
51 | drawPath.stroke()
52 | drawPath.fill()
53 |
54 | clipPath.addClip()
55 |
56 | return UIGraphicsGetImageFromCurrentImageContext()!
57 | }()
58 |
59 | private var overlayView: UIView {
60 | return overlayWindow.rootViewController!.view
61 | }
62 |
63 | lazy var overlayWindow: UIWindow = {
64 | let window: UIWindow
65 | if #available(iOS 13.0, *), let windowScene = windowScene {
66 | window = FingerTipOverlayWindow(windowScene: windowScene)
67 | } else {
68 | window = FingerTipOverlayWindow(frame: frame)
69 | }
70 | window.rootViewController = UIViewController()
71 | window.isUserInteractionEnabled = false
72 | window.windowLevel = .statusBar
73 | window.backgroundColor = .clear
74 | window.isHidden = false
75 | return window
76 | }()
77 |
78 | var fingerTipRemovalScheduled: Bool = false
79 |
80 | required public init?(coder aDecoder: NSCoder) {
81 | super.init(coder: aDecoder)
82 |
83 | commonInit()
84 | }
85 |
86 | override public init(frame: CGRect) {
87 | super.init(frame: frame)
88 |
89 | commonInit()
90 | }
91 |
92 | @available(iOS 13.0, *)
93 | public override init(windowScene: UIWindowScene) {
94 | super.init(windowScene: windowScene)
95 |
96 | commonInit()
97 | }
98 |
99 | func commonInit() {
100 | NotificationCenter.default.addObserver(self, selector: #selector(updateFingertipsAreActive), name: UIScreen.didConnectNotification, object: nil)
101 | NotificationCenter.default.addObserver(self, selector: #selector(updateFingertipsAreActive), name: UIScreen.didDisconnectNotification, object: nil)
102 | NotificationCenter.default.addObserver(self, selector: #selector(updateFingertipsAreActive), name: UIScreen.capturedDidChangeNotification, object: nil)
103 |
104 | updateFingertipsAreActive()
105 | }
106 |
107 | func anyScreenIsCaptured() -> Bool {
108 | UIScreen.screens.contains(where: \.isCaptured)
109 | }
110 |
111 | @objc func updateFingertipsAreActive() {
112 | let envDebug = (ProcessInfo.processInfo.environment["DEBUG_FINGERTIP_WINDOW"] as? NSString)?.boolValue
113 |
114 | if alwaysShowTouches || envDebug == true {
115 | active = true
116 | } else {
117 | active = anyScreenIsCaptured()
118 | }
119 | }
120 |
121 | public override func sendEvent(_ event: UIEvent) {
122 | defer {
123 | super.sendEvent(event)
124 | scheduleFingerTipRemoval()
125 | }
126 |
127 | guard active else { return }
128 |
129 | guard let allTouches: Set = event.allTouches else { return }
130 |
131 | for touch in allTouches {
132 | switch touch.phase {
133 | case .began, .moved, .stationary:
134 | var touchView = overlayView.viewWithTag(touch.hashValue) as? FingerTipView
135 |
136 | if touch.phase != .stationary && touchView != nil && touchView?.fadingOut == true {
137 | touchView?.removeFromSuperview()
138 | touchView = nil
139 | }
140 |
141 | if touchView == nil && touch.phase != .stationary {
142 | touchView = FingerTipView(image: touchImage)
143 | touchView?.translatesAutoresizingMaskIntoConstraints = false
144 | overlayView.addSubview(touchView!)
145 | }
146 |
147 | if touchView?.fadingOut == false {
148 | touchView?.alpha = touchAlpha
149 | touchView?.center = touch.location(in: overlayView)
150 | touchView?.tag = touch.hashValue
151 | touchView?.timestamp = touch.timestamp
152 | touchView?.shouldAutomaticallyRemoveAfterTimeout = shouldAutomaticallyRemoveFingerTip(for: touch)
153 | }
154 |
155 | case .ended, .cancelled:
156 | removeFingerTip(with: touch.hashValue, animated: true)
157 |
158 | case .regionEntered, .regionMoved, .regionExited:
159 | fallthrough
160 |
161 | @unknown default:
162 | break
163 | }
164 | }
165 | }
166 |
167 | func scheduleFingerTipRemoval() {
168 | if fingerTipRemovalScheduled {
169 | return
170 | }
171 |
172 | fingerTipRemovalScheduled = true
173 | perform(#selector(removeInactiveFingerTips), with: nil, afterDelay: 0.1)
174 | }
175 |
176 | @objc func removeInactiveFingerTips() {
177 | fingerTipRemovalScheduled = false
178 |
179 | let now = ProcessInfo.processInfo.systemUptime
180 | let REMOVAL_DELAY = 0.2
181 |
182 | for case let touchView as FingerTipView in overlayView.subviews {
183 | if touchView.shouldAutomaticallyRemoveAfterTimeout == true && now > touchView.timestamp ?? 0 + REMOVAL_DELAY {
184 | removeFingerTip(with: touchView.tag, animated: true)
185 | }
186 | }
187 |
188 | if overlayView.subviews.count > 0 {
189 | scheduleFingerTipRemoval()
190 | }
191 | }
192 |
193 | func removeFingerTip(with hash: Int, animated: Bool) {
194 | guard let touchView = overlayView.viewWithTag(hash) as? FingerTipView, !touchView.fadingOut else { return }
195 |
196 | UIView.animate(withDuration: animated ? fadeDuration : 0) {
197 | touchView.fadingOut = true
198 | touchView.alpha = 0
199 | touchView.frame = CGRect(x: touchView.center.x - touchView.frame.size.width / 1.5,
200 | y: touchView.center.y - touchView.frame.size.height / 1.5,
201 | width: touchView.frame.size.width * 1.5,
202 | height: touchView.frame.size.height * 1.5)
203 |
204 | } completion: { _ in
205 | touchView.fadingOut = false
206 | touchView.removeFromSuperview()
207 | }
208 | }
209 |
210 | func shouldAutomaticallyRemoveFingerTip(for touch: UITouch) -> Bool {
211 | var view = touch.view
212 | view = view?.hitTest(touch.location(in: view), with: nil)
213 |
214 | while view != nil {
215 | switch view {
216 | case is UITableViewCell:
217 | for recognizer in touch.gestureRecognizers ?? [] {
218 | if recognizer is UISwipeGestureRecognizer {
219 | return true
220 | }
221 | }
222 | case is UITableView:
223 | if touch.gestureRecognizers?.count == 0 {
224 | return true
225 | }
226 | default: break
227 | }
228 |
229 | view = view?.superview
230 | }
231 |
232 | return false
233 | }
234 | }
235 |
236 |
--------------------------------------------------------------------------------
/Fingertips.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 53;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | FE228303298419FD000F6CF4 /* FingerTipWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE228302298419FD000F6CF4 /* FingerTipWindow.swift */; };
11 | /* End PBXBuildFile section */
12 |
13 | /* Begin PBXFileReference section */
14 | BE6B26161CFA17AF001BFB6F /* Fingertips.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Fingertips.framework; sourceTree = BUILT_PRODUCTS_DIR; };
15 | BE6B261B1CFA17AF001BFB6F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Fingertips.xcodeproj/Info.plist; sourceTree = ""; };
16 | FE228302298419FD000F6CF4 /* FingerTipWindow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FingerTipWindow.swift; path = Sources/Fingertips/FingerTipWindow.swift; sourceTree = ""; };
17 | /* End PBXFileReference section */
18 |
19 | /* Begin PBXFrameworksBuildPhase section */
20 | BE6B26121CFA17AF001BFB6F /* Frameworks */ = {
21 | isa = PBXFrameworksBuildPhase;
22 | buildActionMask = 2147483647;
23 | files = (
24 | );
25 | runOnlyForDeploymentPostprocessing = 0;
26 | };
27 | /* End PBXFrameworksBuildPhase section */
28 |
29 | /* Begin PBXGroup section */
30 | BE6B260C1CFA17AF001BFB6F = {
31 | isa = PBXGroup;
32 | children = (
33 | BE6B26181CFA17AF001BFB6F /* Fingertips */,
34 | BE6B26171CFA17AF001BFB6F /* Products */,
35 | );
36 | sourceTree = "";
37 | };
38 | BE6B26171CFA17AF001BFB6F /* Products */ = {
39 | isa = PBXGroup;
40 | children = (
41 | BE6B26161CFA17AF001BFB6F /* Fingertips.framework */,
42 | );
43 | name = Products;
44 | sourceTree = "";
45 | };
46 | BE6B26181CFA17AF001BFB6F /* Fingertips */ = {
47 | isa = PBXGroup;
48 | children = (
49 | FE228302298419FD000F6CF4 /* FingerTipWindow.swift */,
50 | BE6B261B1CFA17AF001BFB6F /* Info.plist */,
51 | );
52 | name = Fingertips;
53 | sourceTree = "";
54 | };
55 | /* End PBXGroup section */
56 |
57 | /* Begin PBXHeadersBuildPhase section */
58 | BE6B26131CFA17AF001BFB6F /* Headers */ = {
59 | isa = PBXHeadersBuildPhase;
60 | buildActionMask = 2147483647;
61 | files = (
62 | );
63 | runOnlyForDeploymentPostprocessing = 0;
64 | };
65 | /* End PBXHeadersBuildPhase section */
66 |
67 | /* Begin PBXNativeTarget section */
68 | BE6B26151CFA17AF001BFB6F /* Fingertips */ = {
69 | isa = PBXNativeTarget;
70 | buildConfigurationList = BE6B261E1CFA17AF001BFB6F /* Build configuration list for PBXNativeTarget "Fingertips" */;
71 | buildPhases = (
72 | BE6B26111CFA17AF001BFB6F /* Sources */,
73 | BE6B26121CFA17AF001BFB6F /* Frameworks */,
74 | BE6B26131CFA17AF001BFB6F /* Headers */,
75 | BE6B26141CFA17AF001BFB6F /* Resources */,
76 | );
77 | buildRules = (
78 | );
79 | dependencies = (
80 | );
81 | name = Fingertips;
82 | productName = Fingertips;
83 | productReference = BE6B26161CFA17AF001BFB6F /* Fingertips.framework */;
84 | productType = "com.apple.product-type.framework";
85 | };
86 | /* End PBXNativeTarget section */
87 |
88 | /* Begin PBXProject section */
89 | BE6B260D1CFA17AF001BFB6F /* Project object */ = {
90 | isa = PBXProject;
91 | attributes = {
92 | BuildIndependentTargetsInParallel = YES;
93 | LastUpgradeCheck = 1430;
94 | ORGANIZATIONNAME = Mapbox;
95 | TargetAttributes = {
96 | BE6B26151CFA17AF001BFB6F = {
97 | CreatedOnToolsVersion = 7.3.1;
98 | LastSwiftMigration = 1420;
99 | };
100 | };
101 | };
102 | buildConfigurationList = BE6B26101CFA17AF001BFB6F /* Build configuration list for PBXProject "Fingertips" */;
103 | compatibilityVersion = "Xcode 3.2";
104 | developmentRegion = en;
105 | hasScannedForEncodings = 0;
106 | knownRegions = (
107 | en,
108 | Base,
109 | );
110 | mainGroup = BE6B260C1CFA17AF001BFB6F;
111 | productRefGroup = BE6B26171CFA17AF001BFB6F /* Products */;
112 | projectDirPath = "";
113 | projectRoot = "";
114 | targets = (
115 | BE6B26151CFA17AF001BFB6F /* Fingertips */,
116 | );
117 | };
118 | /* End PBXProject section */
119 |
120 | /* Begin PBXResourcesBuildPhase section */
121 | BE6B26141CFA17AF001BFB6F /* Resources */ = {
122 | isa = PBXResourcesBuildPhase;
123 | buildActionMask = 2147483647;
124 | files = (
125 | );
126 | runOnlyForDeploymentPostprocessing = 0;
127 | };
128 | /* End PBXResourcesBuildPhase section */
129 |
130 | /* Begin PBXSourcesBuildPhase section */
131 | BE6B26111CFA17AF001BFB6F /* Sources */ = {
132 | isa = PBXSourcesBuildPhase;
133 | buildActionMask = 2147483647;
134 | files = (
135 | FE228303298419FD000F6CF4 /* FingerTipWindow.swift in Sources */,
136 | );
137 | runOnlyForDeploymentPostprocessing = 0;
138 | };
139 | /* End PBXSourcesBuildPhase section */
140 |
141 | /* Begin XCBuildConfiguration section */
142 | BE6B261C1CFA17AF001BFB6F /* Debug */ = {
143 | isa = XCBuildConfiguration;
144 | buildSettings = {
145 | ALWAYS_SEARCH_USER_PATHS = NO;
146 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
147 | CLANG_ANALYZER_NONNULL = YES;
148 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
149 | CLANG_CXX_LIBRARY = "libc++";
150 | CLANG_ENABLE_MODULES = YES;
151 | CLANG_ENABLE_OBJC_ARC = YES;
152 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
153 | CLANG_WARN_BOOL_CONVERSION = YES;
154 | CLANG_WARN_COMMA = YES;
155 | CLANG_WARN_CONSTANT_CONVERSION = YES;
156 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
157 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
158 | CLANG_WARN_EMPTY_BODY = YES;
159 | CLANG_WARN_ENUM_CONVERSION = YES;
160 | CLANG_WARN_INFINITE_RECURSION = YES;
161 | CLANG_WARN_INT_CONVERSION = YES;
162 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
163 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
164 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
165 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
166 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
167 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
168 | CLANG_WARN_STRICT_PROTOTYPES = YES;
169 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
170 | CLANG_WARN_UNREACHABLE_CODE = YES;
171 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
172 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
173 | CURRENT_PROJECT_VERSION = 1;
174 | DEBUG_INFORMATION_FORMAT = dwarf;
175 | ENABLE_STRICT_OBJC_MSGSEND = YES;
176 | ENABLE_TESTABILITY = YES;
177 | GCC_C_LANGUAGE_STANDARD = gnu99;
178 | GCC_DYNAMIC_NO_PIC = NO;
179 | GCC_NO_COMMON_BLOCKS = YES;
180 | GCC_OPTIMIZATION_LEVEL = 0;
181 | GCC_PREPROCESSOR_DEFINITIONS = (
182 | "DEBUG=1",
183 | "$(inherited)",
184 | );
185 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
186 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
187 | GCC_WARN_UNDECLARED_SELECTOR = YES;
188 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
189 | GCC_WARN_UNUSED_FUNCTION = YES;
190 | GCC_WARN_UNUSED_VARIABLE = YES;
191 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
192 | MTL_ENABLE_DEBUG_INFO = YES;
193 | ONLY_ACTIVE_ARCH = YES;
194 | SDKROOT = iphoneos;
195 | TARGETED_DEVICE_FAMILY = "1,2";
196 | VERSIONING_SYSTEM = "apple-generic";
197 | VERSION_INFO_PREFIX = "";
198 | };
199 | name = Debug;
200 | };
201 | BE6B261D1CFA17AF001BFB6F /* Release */ = {
202 | isa = XCBuildConfiguration;
203 | buildSettings = {
204 | ALWAYS_SEARCH_USER_PATHS = NO;
205 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
206 | CLANG_ANALYZER_NONNULL = YES;
207 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
208 | CLANG_CXX_LIBRARY = "libc++";
209 | CLANG_ENABLE_MODULES = YES;
210 | CLANG_ENABLE_OBJC_ARC = YES;
211 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
212 | CLANG_WARN_BOOL_CONVERSION = YES;
213 | CLANG_WARN_COMMA = YES;
214 | CLANG_WARN_CONSTANT_CONVERSION = YES;
215 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
216 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
217 | CLANG_WARN_EMPTY_BODY = YES;
218 | CLANG_WARN_ENUM_CONVERSION = YES;
219 | CLANG_WARN_INFINITE_RECURSION = YES;
220 | CLANG_WARN_INT_CONVERSION = YES;
221 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
222 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
223 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
224 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
225 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
226 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
227 | CLANG_WARN_STRICT_PROTOTYPES = YES;
228 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
229 | CLANG_WARN_UNREACHABLE_CODE = YES;
230 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
231 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
232 | CURRENT_PROJECT_VERSION = 1;
233 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
234 | ENABLE_NS_ASSERTIONS = NO;
235 | ENABLE_STRICT_OBJC_MSGSEND = YES;
236 | GCC_C_LANGUAGE_STANDARD = gnu99;
237 | GCC_NO_COMMON_BLOCKS = YES;
238 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
239 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
240 | GCC_WARN_UNDECLARED_SELECTOR = YES;
241 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
242 | GCC_WARN_UNUSED_FUNCTION = YES;
243 | GCC_WARN_UNUSED_VARIABLE = YES;
244 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
245 | MTL_ENABLE_DEBUG_INFO = NO;
246 | SDKROOT = iphoneos;
247 | SWIFT_COMPILATION_MODE = wholemodule;
248 | TARGETED_DEVICE_FAMILY = "1,2";
249 | VALIDATE_PRODUCT = YES;
250 | VERSIONING_SYSTEM = "apple-generic";
251 | VERSION_INFO_PREFIX = "";
252 | };
253 | name = Release;
254 | };
255 | BE6B261F1CFA17AF001BFB6F /* Debug */ = {
256 | isa = XCBuildConfiguration;
257 | buildSettings = {
258 | CLANG_ENABLE_MODULES = YES;
259 | CODE_SIGN_IDENTITY = "";
260 | DEFINES_MODULE = YES;
261 | DYLIB_COMPATIBILITY_VERSION = 1;
262 | DYLIB_CURRENT_VERSION = 1;
263 | DYLIB_INSTALL_NAME_BASE = "@rpath";
264 | ENABLE_MODULE_VERIFIER = YES;
265 | INFOPLIST_FILE = Fingertips.xcodeproj/Info.plist;
266 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
267 | LD_RUNPATH_SEARCH_PATHS = (
268 | "$(inherited)",
269 | "@executable_path/Frameworks",
270 | "@loader_path/Frameworks",
271 | );
272 | MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11";
273 | PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.Fingertips;
274 | PRODUCT_NAME = "$(TARGET_NAME)";
275 | SKIP_INSTALL = YES;
276 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
277 | SWIFT_VERSION = 5.0;
278 | };
279 | name = Debug;
280 | };
281 | BE6B26201CFA17AF001BFB6F /* Release */ = {
282 | isa = XCBuildConfiguration;
283 | buildSettings = {
284 | CLANG_ENABLE_MODULES = YES;
285 | CODE_SIGN_IDENTITY = "";
286 | DEFINES_MODULE = YES;
287 | DYLIB_COMPATIBILITY_VERSION = 1;
288 | DYLIB_CURRENT_VERSION = 1;
289 | DYLIB_INSTALL_NAME_BASE = "@rpath";
290 | ENABLE_MODULE_VERIFIER = YES;
291 | INFOPLIST_FILE = Fingertips.xcodeproj/Info.plist;
292 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
293 | LD_RUNPATH_SEARCH_PATHS = (
294 | "$(inherited)",
295 | "@executable_path/Frameworks",
296 | "@loader_path/Frameworks",
297 | );
298 | MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu99 gnu++11";
299 | PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.Fingertips;
300 | PRODUCT_NAME = "$(TARGET_NAME)";
301 | SKIP_INSTALL = YES;
302 | SWIFT_VERSION = 5.0;
303 | };
304 | name = Release;
305 | };
306 | /* End XCBuildConfiguration section */
307 |
308 | /* Begin XCConfigurationList section */
309 | BE6B26101CFA17AF001BFB6F /* Build configuration list for PBXProject "Fingertips" */ = {
310 | isa = XCConfigurationList;
311 | buildConfigurations = (
312 | BE6B261C1CFA17AF001BFB6F /* Debug */,
313 | BE6B261D1CFA17AF001BFB6F /* Release */,
314 | );
315 | defaultConfigurationIsVisible = 0;
316 | defaultConfigurationName = Release;
317 | };
318 | BE6B261E1CFA17AF001BFB6F /* Build configuration list for PBXNativeTarget "Fingertips" */ = {
319 | isa = XCConfigurationList;
320 | buildConfigurations = (
321 | BE6B261F1CFA17AF001BFB6F /* Debug */,
322 | BE6B26201CFA17AF001BFB6F /* Release */,
323 | );
324 | defaultConfigurationIsVisible = 0;
325 | defaultConfigurationName = Release;
326 | };
327 | /* End XCConfigurationList section */
328 | };
329 | rootObject = BE6B260D1CFA17AF001BFB6F /* Project object */;
330 | }
331 |
--------------------------------------------------------------------------------