├── Example
├── App
│ ├── Sounds
│ │ └── Success.m4a
│ ├── AppDelegate.swift
│ ├── Info.plist
│ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── Assets.xcassets
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ └── ViewController.swift
└── FeedbackEffect.xcodeproj
│ ├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ ├── xcshareddata
│ └── xcschemes
│ │ └── Example.xcscheme
│ └── project.pbxproj
├── Sources
└── FeedbackEffect
│ ├── URL+SoundEmitting.swift
│ ├── SoundEffect.swift
│ ├── VibrationFeedback.swift
│ ├── MessageTone.swift
│ ├── FeedbackEffect.swift
│ └── HapticFeedback.swift
├── CHANGELOG.md
├── FeedbackEffect.podspec
├── Package.swift
├── LICENSE
├── .gitignore
└── README.md
/Example/App/Sounds/Success.m4a:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mergesort/FeedbackEffect/HEAD/Example/App/Sounds/Success.m4a
--------------------------------------------------------------------------------
/Example/FeedbackEffect.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Example/FeedbackEffect.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Example/App/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // FeedbackEffect
4 | //
5 | // Created by Joe Fabisevich on 9/7/17.
6 | // Copyright © 2017 Mergesort. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/Sources/FeedbackEffect/URL+SoundEmitting.swift:
--------------------------------------------------------------------------------
1 | import AVFoundation
2 | import Foundation
3 |
4 | extension URL: SoundEmitting {
5 |
6 | public func makeSound() {
7 | FeedbackEffect.player.removeAllItems()
8 | let item = AVPlayerItem(url: self)
9 | FeedbackEffect.player.insert(item, after: nil)
10 | FeedbackEffect.player.play()
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/Sources/FeedbackEffect/SoundEffect.swift:
--------------------------------------------------------------------------------
1 | import AudioToolbox
2 |
3 | /// A set of sound effects that iOS provides through the `AudioServicesPlaySystemSound` subsystem.
4 | public enum SoundEffect: Int {
5 | case tap = 1104
6 | }
7 |
8 | extension SoundEffect: SoundEmitting {
9 |
10 | public func makeSound() {
11 | AudioServicesPlaySystemSound(UInt32(self.rawValue))
12 | }
13 |
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 | # 1.5.0 (2019-07-14)
4 |
5 | - Adding Swift 5 support.
6 |
7 | - Adding SPM support.
8 |
9 | - Adding support for `.soft`, `.rigid` haptics available in iOS 13.
10 |
11 | # 1.4 (2017-10-17)
12 |
13 | - Adding Swift 4.2 support.
14 |
15 | # 1.3 (2017-10-17)
16 |
17 | - Users can now specify a `UIImpactFeedbackStyle` as such.
18 |
19 | # 1.2 (2017-09-25)
20 |
21 | - Adding the ability to `prepare()` a `UIImpactGenerator`.
22 |
23 | # 1.1 (2017-09-08)
24 |
25 | - Added the ability to specify which level of `UIImpactFeedbackStyle` you want.
26 |
27 | Supporting:
28 | - `.light`
29 | - `.medium`
30 | - `.heavy`
31 |
32 | # 1.0 (2016-12-08)
33 |
34 | - Initial release.
35 |
--------------------------------------------------------------------------------
/FeedbackEffect.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |spec|
2 | spec.name = 'FeedbackEffect'
3 | spec.version = '1.5.0'
4 | spec.license = { :type => 'MIT', :file => 'LICENSE' }
5 | spec.homepage = 'https://github.com/mergesort/FeedbackEffect'
6 | spec.authors = { 'Joe Fabisevich' => 'github@fabisevi.ch' }
7 | spec.summary = 'A μ library for playing sounds and providing haptic feedback with ease.'
8 | spec.source = { :git => 'https://github.com/mergesort/FeedbackEffect.git', :tag => "#{spec.version}" }
9 | spec.source_files = 'Sources/FeedbackEffect/*.swift'
10 | spec.framework = 'AudioToolbox', 'AVFoundation', 'UIKit'
11 | spec.requires_arc = true
12 | spec.social_media_url = 'https://twitter.com/mergesort'
13 | spec.ios.deployment_target = '10.0'
14 | spec.swift_version = '5.0'
15 | end
16 |
--------------------------------------------------------------------------------
/Sources/FeedbackEffect/VibrationFeedback.swift:
--------------------------------------------------------------------------------
1 | import AudioToolbox
2 |
3 | /// A set of vibration patterns that iOS uses through the `AudioServicesPlaySystemSound` subsystem
4 | /// to generate vibrations on devices that do not have a taptic engine.
5 | public enum VibrationFeedback {
6 | case selection
7 | case impact
8 | case notification
9 | }
10 |
11 | private extension VibrationFeedback {
12 |
13 | var audioServicesCode: UInt32 {
14 | switch self {
15 |
16 | case .selection:
17 | return 1519
18 |
19 | case .impact:
20 | return 1520
21 |
22 | case .notification:
23 | return 1521
24 |
25 | }
26 | }
27 |
28 | }
29 |
30 | extension VibrationFeedback: HapticEmitting {
31 |
32 | public func generateFeedback() {
33 | AudioServicesPlaySystemSound(self.audioServicesCode)
34 | }
35 |
36 | }
37 |
38 |
39 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.0
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "FeedbackEffect",
8 | platforms: [
9 | .iOS(.v10)
10 | ],
11 | products: [
12 | // Products define the executables and libraries produced by a package, and make them visible to other packages.
13 | .library(
14 | name: "FeedbackEffect",
15 | targets: ["FeedbackEffect"]),
16 | ],
17 | dependencies: [
18 | // Dependencies declare other packages that this package depends on.
19 | // .package(url: /* package url */, from: "1.0.0"),
20 | ],
21 | targets: [
22 | // Targets are the basic building blocks of a package. A target can define a module or a test suite.
23 | // Targets can depend on other targets in this package, and on products in packages which this package depends on.
24 | .target(
25 | name: "FeedbackEffect",
26 | dependencies: [])
27 | ]
28 | )
29 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Joe Fabisevich
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, 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,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Sources/FeedbackEffect/MessageTone.swift:
--------------------------------------------------------------------------------
1 | import AudioToolbox
2 |
3 | /// A set of text message sound effects that iOS provides through the `AudioServicesPlaySystemSound` subsystem.
4 | public enum MessageTone: Int {
5 | case note = 1375
6 | case aurora = 1366
7 | case bamboo = 1361
8 | case chord = 1312
9 | case circles = 1368
10 | case complete = 1362
11 | case hello = 1363
12 | case input = 1369
13 | case keys = 1367
14 | case popcorn = 1364
15 | case pulse = 1120
16 | case synth = 1365
17 | case alert = 1005
18 | case anticipate = 1020
19 | case bell = 1013
20 | case bloom = 1021
21 | case calypso = 1022
22 | case chime = 1008
23 | case choochoo = 1023
24 | case descent = 1024
25 | case ding = 1000
26 | case electronic = 1014
27 | case fanfare = 1025
28 | case glass = 1009
29 | case horn = 1010
30 | case ladder = 1026
31 | case minuet = 1027
32 | case newsflash = 1028
33 | case noir = 1029
34 | case sherwoodforest = 1030
35 | case spell = 1031
36 | case suspence = 1032
37 | case swish = 1018
38 | case swoosh = 1001
39 | case telegraph = 1033
40 | case tiptoes = 1034
41 | case tritone = 1002
42 | case tweet = 1016
43 | case typewriters = 1035
44 | case update = 1036
45 | }
46 |
47 | extension MessageTone: SoundEmitting {
48 |
49 | public func makeSound() {
50 | AudioServicesPlaySystemSound(UInt32(self.rawValue))
51 | }
52 |
53 | }
54 |
55 |
--------------------------------------------------------------------------------
/Sources/FeedbackEffect/FeedbackEffect.swift:
--------------------------------------------------------------------------------
1 | import AVFoundation
2 | import UIKit
3 |
4 | /// A protocol for encapsulating the different ways that sound can be created, for use in `FeedbackEffect`.
5 | public protocol SoundEmitting {
6 | func makeSound()
7 | }
8 |
9 | /// A protocol for encapsulating the different ways that haptic feedback can be created, for use in `FeedbackEffect`.
10 | public protocol HapticEmitting {
11 | func generateFeedback()
12 | }
13 |
14 | /// A type which encapsulates sound and haptic feedback. This is useful for providing feedback on user
15 | /// interaction, or when an app would like to signal a noteworthy event.
16 | public struct FeedbackEffect {
17 |
18 | // The player needs to be retained, so we make it a property.
19 | static let player = AVQueuePlayer()
20 |
21 | /// A function that allows a user to provide feedback to a user.
22 | ///
23 | /// - Parameters:
24 | /// - sound: A `SoundEmitting` type to play when feedback occurs.
25 | /// - feedback: A `HapticEmitting` type to play when feedback occurs.
26 | public static func play(sound: SoundEmitting?, feedback: HapticEmitting? = nil) {
27 | if let sound = sound {
28 | do {
29 | try AVAudioSession.sharedInstance().setCategory(.ambient, mode: .default, options: .mixWithOthers)
30 | sound.makeSound()
31 | } catch {
32 | print("Couldn't play a sound")
33 | }
34 | }
35 |
36 | if let feedback = feedback {
37 | feedback.generateFeedback()
38 | }
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/Example/App/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xccheckout
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 | *.dSYM.zip
29 | *.dSYM
30 |
31 | ## Playgrounds
32 | timeline.xctimeline
33 | playground.xcworkspace
34 |
35 | # Swift Package Manager
36 | #
37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
38 | # Packages/
39 | # Package.pins
40 | .build/
41 |
42 | # CocoaPods
43 | #
44 | # We recommend against adding the Pods directory to your .gitignore. However
45 | # you should judge for yourself, the pros and cons are mentioned at:
46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
47 | #
48 | # Pods/
49 |
50 | # Carthage
51 | #
52 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
53 | # Carthage/Checkouts
54 |
55 | Carthage/Build
56 |
57 | # fastlane
58 | #
59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
60 | # screenshots whenever they are needed.
61 | # For more information about the recommended setup visit:
62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
63 |
64 | fastlane/report.xml
65 | fastlane/Preview.html
66 | fastlane/screenshots
67 | fastlane/test_output
68 |
--------------------------------------------------------------------------------
/Example/App/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/Example/App/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/Example/App/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // FeedbackEffect
4 | //
5 | // Created by Joe Fabisevich on 9/7/17.
6 | // Copyright © 2017 Mergesort. All rights reserved.
7 | //
8 |
9 | import FeedbackEffect
10 | import UIKit
11 |
12 | class ViewController: UIViewController {
13 |
14 | // These are just 4 combos, you can mix and match and make tons of your own!
15 |
16 | @IBAction func urlAndHaptics(_ sender: Any) {
17 | // Uses the haptic feedback built into iOS along with an
18 | // alert sound to make a user feel they've finished a unit of work.
19 |
20 | let notificationFeedback = HapticFeedback.notification(.success)
21 |
22 | // We can optionally prepare the generator that relates to the feedback we're trying to activate.
23 | notificationFeedback.prepare()
24 |
25 | let soundUrl = Bundle.main.url(forResource: "Success", withExtension: "m4a")
26 | FeedbackEffect.play(sound: soundUrl, feedback: notificationFeedback)
27 | }
28 |
29 | @IBAction func urlAndVibration(_ sender: Any) {
30 | // Uses the vibration feedback fallback (for users without 3D Touch devices)
31 | // built into iOS along with an alert sound to make a user feel they've finished
32 | // a unit of work.
33 |
34 | let selectionVibration = VibrationFeedback.notification
35 | let soundUrl = Bundle.main.url(forResource: "Success", withExtension: "m4a")
36 | FeedbackEffect.play(sound: soundUrl, feedback: selectionVibration)
37 | }
38 |
39 | @IBAction func toneAndHaptics(_ sender: Any) {
40 | // Uses the haptic feedback built into iOS along with the tap sound
41 | // to make a user feel like they're really tapping a button.
42 |
43 | let selectionFeedback = HapticFeedback.selection
44 | selectionFeedback.prepare()
45 | let tapSound = SoundEffect.tap
46 | FeedbackEffect.play(sound: tapSound, feedback: selectionFeedback)
47 | }
48 |
49 | @IBAction func toneAndVibration(_ sender: Any) {
50 | // Uses the vibration feedback fallback (for users without 3D Touch devices)
51 | // built into iOS along with an alert sound to make a user feel they've finished
52 | // a unit of work.
53 |
54 | let vibration = VibrationFeedback.notification
55 | let sound = MessageTone.tweet
56 | FeedbackEffect.play(sound: sound, feedback: vibration)
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/Example/FeedbackEffect.xcodeproj/xcshareddata/xcschemes/Example.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
45 |
51 |
52 |
53 |
54 |
60 |
62 |
68 |
69 |
70 |
71 |
73 |
74 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/Sources/FeedbackEffect/HapticFeedback.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | /// An enum describing the different kinds of haptic feedback the taptic engine is capable of producing.
4 | /// For use in `FeedbackEffect`, to give the user feedback when it's desired.
5 | ///
6 | /// - impact: Used for calling `UIImpactFeedbackGenerator(impactStyle).impactOccurred()`.
7 | /// - selection: Used for calling `UISelectionFeedbackGenerator().selectionChanged()`.
8 | /// - notification: Used for calling `UINotificationFeedbackGenerator().notificationOccurred(notificationType)`.
9 | public enum HapticFeedback: HapticEmitting {
10 |
11 | fileprivate static let lightImpactGenerator = UIImpactFeedbackGenerator()
12 | fileprivate static let mediumImpactGenerator = UIImpactFeedbackGenerator()
13 | fileprivate static let heavyImpactGenerator = UIImpactFeedbackGenerator()
14 | fileprivate static let softImpactGenerator = UIImpactFeedbackGenerator()
15 | fileprivate static let rigidImpactGenerator = UIImpactFeedbackGenerator()
16 | fileprivate static let selectionGenerator = UISelectionFeedbackGenerator()
17 | fileprivate static let notificationGenerator = UINotificationFeedbackGenerator()
18 |
19 | case impact(UIImpactFeedbackGenerator.FeedbackStyle)
20 | case selection
21 | case notification(UINotificationFeedbackGenerator.FeedbackType)
22 |
23 | }
24 |
25 | extension HapticFeedback {
26 |
27 | public func prepare() {
28 | switch self {
29 |
30 | case .impact(let style):
31 | switch style {
32 |
33 | case .light:
34 | HapticFeedback.lightImpactGenerator.prepare()
35 |
36 | case .medium:
37 | HapticFeedback.mediumImpactGenerator.prepare()
38 |
39 | case .heavy:
40 | HapticFeedback.heavyImpactGenerator.prepare()
41 |
42 | case .soft:
43 | HapticFeedback.softImpactGenerator.prepare()
44 |
45 | case .rigid:
46 | HapticFeedback.rigidImpactGenerator.prepare()
47 |
48 | @unknown default:
49 | return
50 |
51 | }
52 |
53 | case .selection:
54 | HapticFeedback.selectionGenerator.prepare()
55 |
56 | case .notification:
57 | HapticFeedback.notificationGenerator.prepare()
58 |
59 | }
60 | }
61 |
62 | public func generateFeedback() {
63 | switch self {
64 |
65 | case .impact(let style):
66 | switch style {
67 |
68 | case .light:
69 | HapticFeedback.lightImpactGenerator.impactOccurred()
70 |
71 | case .medium:
72 | HapticFeedback.mediumImpactGenerator.impactOccurred()
73 |
74 | case .heavy:
75 | HapticFeedback.heavyImpactGenerator.impactOccurred()
76 |
77 | case .soft:
78 | HapticFeedback.softImpactGenerator.impactOccurred()
79 |
80 | case .rigid:
81 | HapticFeedback.rigidImpactGenerator.impactOccurred()
82 |
83 | @unknown default:
84 | return
85 |
86 | }
87 |
88 | case .selection:
89 | HapticFeedback.selectionGenerator.selectionChanged()
90 |
91 | case .notification(let notificationType):
92 | HapticFeedback.notificationGenerator.notificationOccurred(notificationType)
93 |
94 | }
95 | }
96 |
97 | }
98 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FeedbackEffect
2 |
3 | ### A μ library for playing sound effects and providing haptic feedback… with ease.
4 |
5 | [](https://dashboard.buddybuild.com/apps/59b1c96ebb97170001f8ebd4/build/latest?branch=master)
6 | [](https://cocoapods.org/)
7 | 
8 | 
9 | 
10 |
11 | ### Your app should be special. Other people's apps suck. How do we make your app extra awesome? Feedback and sound effects my friend.
12 |
13 | Until now there has not been a unified API to allow you to integrate sound effects _and_ haptic feedback with ease. If you're guessing that now there is, then you're right… now there is.
14 |
15 | ---
16 |
17 | ### The API couldn't be simpler.
18 |
19 | ```swift
20 | let selectionFeedback = HapticFeedback.notification(.success)
21 | let soundUrl = Bundle.main.url(forResource: "Success", withExtension: "m4a")
22 | FeedbackEffect.play(sound: soundUrl, feedback: selectionFeedback)
23 | ```
24 |
25 | ---
26 |
27 | ### Q&A time
28 |
29 | **Q: Is that all?**
30 |
31 | A: Yep.
32 |
33 | **Q: Really?**
34 |
35 | A: Fine, let's go into more detail.
36 |
37 | ---
38 |
39 | ### SoundEmitting
40 |
41 | There are two kinds of `SoundEmitting`. You can provide a URL to any resource that iOS can play (such as an m4a), or use some common sounds from iOS pre-configured.
42 |
43 | Three types conform to `SoundEmitting` out of the box:
44 |
45 | - URL
46 | - MessageTone
47 | - SoundEffect
48 |
49 | If you'd like to add some more, all you have to do is conform to the protocol. If you find some more that are built into iOS, feel free to file a PR and it'll gladly be accepted.
50 |
51 | ---
52 |
53 | ### HapticEmitting
54 |
55 | There are two ways to provide a user with haptic feedback. Both `HapticFeedback` and `VibrationFeedback` conform to `HapticEmitting`.
56 |
57 | - **HapticFeedback**: Uses iOS's built in `UIFeedbackGenerator` to generate feedback effects. You can use this just how you would normally use `UIImpactGenerator`, `UISelectionGenerator`, and `UINotificationFeedbackGenerator`.
58 |
59 | - **VibrationFeedback**: For older devices which do not have a taptic engine. It will generate similar vibration patterns to the `UIFeedbackGenerator`, which unfortunately do not match `UIFeedbackGenerator` exactly one for one but are rather close.
60 |
61 | ---
62 |
63 | ### Q&A part II
64 |
65 | **Q: Is that it?**
66 |
67 | A: Yep. You're on your own from here padawan. Let's leave you with a few more examples to make you feel safe though.
68 |
69 | ---
70 |
71 | ### Examples
72 |
73 | Uses the haptic feedback built into iOS along with the tap sound to make a user feel like they're really tapping a button.
74 |
75 | ```swift
76 | let notificationFeedback = HapticFeedback.selection
77 | let tapSound = SoundEffect.tap
78 | FeedbackEffect.play(sound: tapSound, feedback: notificationFeedback)
79 | ```
80 |
81 | Uses the haptic feedback built into iOS along with an success sound to make a user feel they've completed a unit of work successfully.
82 |
83 | ```swift
84 | let selectionFeedback = HapticFeedback.notification(.success)
85 | let soundUrl = Bundle.main.url(forResource: "Success", withExtension: "m4a")
86 | FeedbackEffect.play(sound: soundUrl, feedback: selectionFeedback)
87 | ```
88 |
89 | Uses the vibration feedback fallback (for users without 3D Touch devices) built into iOS along with a pre-configured sound effect.
90 |
91 | ```swift
92 | let vibration = VibrationFeedback.notification
93 | let sound = MessageTone.tweet
94 | FeedbackEffect.play(sound: sound, feedback: vibration)
95 | ```
96 |
97 | You can use just one at a time too if you wish. Just provide haptics and leave the sound parameter nil. You can also do the opposite and provide a sound with no haptics.
98 |
99 | ```swift
100 | let vibration = HapticFeedback.notification(.error)
101 | FeedbackEffect.play(sound: nil, feedback: vibration)
102 | ```
103 |
104 | ---
105 |
106 | ## Requirements
107 |
108 | - iOS 10.0+
109 | - Xcode 8.0+
110 |
111 | ## Installation
112 |
113 | SPM will be the default supported installation method from version 1.5.0 and higher, so please integrate by using SPM.
114 |
115 | If you're still using [CocoaPods](http://cocoapods.org/) for version 1.5.0 or below you can install `FeedbackEffect` by adding it to your `Podfile`:
116 |
117 | ```ruby
118 | platform :ios, '10.0'
119 | use_frameworks!
120 |
121 | pod 'FeedbackEffect'
122 | ```
123 |
124 | Or install it manually by downloading `FeedbackEffect.swift` and dropping it in your project.
125 |
126 | ## About me
127 |
128 | Hi, I'm [Joe](http://fabisevi.ch) everywhere on the web, but especially on [Twitter](https://twitter.com/mergesort).
129 |
130 | ## License
131 |
132 | See the [license](LICENSE) for more information about how you can use TypedNotifications.
133 |
--------------------------------------------------------------------------------
/Example/App/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
34 |
45 |
56 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/Example/FeedbackEffect.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 52;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | B73F346A22DBCD08003AFC57 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B73F346022DBCD08003AFC57 /* ViewController.swift */; };
11 | B73F346B22DBCD08003AFC57 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B73F346122DBCD08003AFC57 /* Assets.xcassets */; };
12 | B73F346C22DBCD08003AFC57 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B73F346222DBCD08003AFC57 /* LaunchScreen.storyboard */; };
13 | B73F346D22DBCD08003AFC57 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B73F346422DBCD08003AFC57 /* Main.storyboard */; };
14 | B73F346E22DBCD08003AFC57 /* Success.m4a in Resources */ = {isa = PBXBuildFile; fileRef = B73F346722DBCD08003AFC57 /* Success.m4a */; };
15 | B73F346F22DBCD08003AFC57 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B73F346822DBCD08003AFC57 /* AppDelegate.swift */; };
16 | B73F347A22DBCF85003AFC57 /* FeedbackEffect in Frameworks */ = {isa = PBXBuildFile; productRef = B73F347922DBCF85003AFC57 /* FeedbackEffect */; };
17 | /* End PBXBuildFile section */
18 |
19 | /* Begin PBXFileReference section */
20 | B721D0FE1F61DF880088DC13 /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
21 | B73F346022DBCD08003AFC57 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
22 | B73F346122DBCD08003AFC57 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
23 | B73F346322DBCD08003AFC57 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
24 | B73F346522DBCD08003AFC57 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
25 | B73F346722DBCD08003AFC57 /* Success.m4a */ = {isa = PBXFileReference; lastKnownFileType = file; path = Success.m4a; sourceTree = ""; };
26 | B73F346822DBCD08003AFC57 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
27 | B73F346922DBCD08003AFC57 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
28 | B73F347722DBCEAB003AFC57 /* FeedbackEffect */ = {isa = PBXFileReference; lastKnownFileType = folder; name = FeedbackEffect; path = ..; sourceTree = ""; };
29 | /* End PBXFileReference section */
30 |
31 | /* Begin PBXFrameworksBuildPhase section */
32 | B721D0FB1F61DF880088DC13 /* Frameworks */ = {
33 | isa = PBXFrameworksBuildPhase;
34 | buildActionMask = 2147483647;
35 | files = (
36 | B73F347A22DBCF85003AFC57 /* FeedbackEffect in Frameworks */,
37 | );
38 | runOnlyForDeploymentPostprocessing = 0;
39 | };
40 | /* End PBXFrameworksBuildPhase section */
41 |
42 | /* Begin PBXGroup section */
43 | B721D0F51F61DF880088DC13 = {
44 | isa = PBXGroup;
45 | children = (
46 | B73F347722DBCEAB003AFC57 /* FeedbackEffect */,
47 | B73F345F22DBCD08003AFC57 /* App */,
48 | B721D0FF1F61DF880088DC13 /* Products */,
49 | );
50 | sourceTree = "";
51 | };
52 | B721D0FF1F61DF880088DC13 /* Products */ = {
53 | isa = PBXGroup;
54 | children = (
55 | B721D0FE1F61DF880088DC13 /* Example.app */,
56 | );
57 | name = Products;
58 | sourceTree = "";
59 | };
60 | B73F345F22DBCD08003AFC57 /* App */ = {
61 | isa = PBXGroup;
62 | children = (
63 | B73F346022DBCD08003AFC57 /* ViewController.swift */,
64 | B73F346122DBCD08003AFC57 /* Assets.xcassets */,
65 | B73F346222DBCD08003AFC57 /* LaunchScreen.storyboard */,
66 | B73F346422DBCD08003AFC57 /* Main.storyboard */,
67 | B73F346622DBCD08003AFC57 /* Sounds */,
68 | B73F346822DBCD08003AFC57 /* AppDelegate.swift */,
69 | B73F346922DBCD08003AFC57 /* Info.plist */,
70 | );
71 | path = App;
72 | sourceTree = "";
73 | };
74 | B73F346622DBCD08003AFC57 /* Sounds */ = {
75 | isa = PBXGroup;
76 | children = (
77 | B73F346722DBCD08003AFC57 /* Success.m4a */,
78 | );
79 | path = Sounds;
80 | sourceTree = "";
81 | };
82 | /* End PBXGroup section */
83 |
84 | /* Begin PBXNativeTarget section */
85 | B721D0FD1F61DF880088DC13 /* Example */ = {
86 | isa = PBXNativeTarget;
87 | buildConfigurationList = B721D11B1F61DF890088DC13 /* Build configuration list for PBXNativeTarget "Example" */;
88 | buildPhases = (
89 | B721D0FA1F61DF880088DC13 /* Sources */,
90 | B721D0FB1F61DF880088DC13 /* Frameworks */,
91 | B721D0FC1F61DF880088DC13 /* Resources */,
92 | );
93 | buildRules = (
94 | );
95 | dependencies = (
96 | );
97 | name = Example;
98 | packageProductDependencies = (
99 | B73F347922DBCF85003AFC57 /* FeedbackEffect */,
100 | );
101 | productName = FeedbackEffect;
102 | productReference = B721D0FE1F61DF880088DC13 /* Example.app */;
103 | productType = "com.apple.product-type.application";
104 | };
105 | /* End PBXNativeTarget section */
106 |
107 | /* Begin PBXProject section */
108 | B721D0F61F61DF880088DC13 /* Project object */ = {
109 | isa = PBXProject;
110 | attributes = {
111 | LastSwiftUpdateCheck = 0900;
112 | LastUpgradeCheck = 1010;
113 | ORGANIZATIONNAME = Mergesort;
114 | TargetAttributes = {
115 | B721D0FD1F61DF880088DC13 = {
116 | CreatedOnToolsVersion = 9.0;
117 | LastSwiftMigration = 1100;
118 | ProvisioningStyle = Automatic;
119 | };
120 | };
121 | };
122 | buildConfigurationList = B721D0F91F61DF880088DC13 /* Build configuration list for PBXProject "FeedbackEffect" */;
123 | compatibilityVersion = "Xcode 8.0";
124 | developmentRegion = en;
125 | hasScannedForEncodings = 0;
126 | knownRegions = (
127 | en,
128 | Base,
129 | );
130 | mainGroup = B721D0F51F61DF880088DC13;
131 | productRefGroup = B721D0FF1F61DF880088DC13 /* Products */;
132 | projectDirPath = "";
133 | projectRoot = "";
134 | targets = (
135 | B721D0FD1F61DF880088DC13 /* Example */,
136 | );
137 | };
138 | /* End PBXProject section */
139 |
140 | /* Begin PBXResourcesBuildPhase section */
141 | B721D0FC1F61DF880088DC13 /* Resources */ = {
142 | isa = PBXResourcesBuildPhase;
143 | buildActionMask = 2147483647;
144 | files = (
145 | B73F346C22DBCD08003AFC57 /* LaunchScreen.storyboard in Resources */,
146 | B73F346E22DBCD08003AFC57 /* Success.m4a in Resources */,
147 | B73F346B22DBCD08003AFC57 /* Assets.xcassets in Resources */,
148 | B73F346D22DBCD08003AFC57 /* Main.storyboard in Resources */,
149 | );
150 | runOnlyForDeploymentPostprocessing = 0;
151 | };
152 | /* End PBXResourcesBuildPhase section */
153 |
154 | /* Begin PBXSourcesBuildPhase section */
155 | B721D0FA1F61DF880088DC13 /* Sources */ = {
156 | isa = PBXSourcesBuildPhase;
157 | buildActionMask = 2147483647;
158 | files = (
159 | B73F346F22DBCD08003AFC57 /* AppDelegate.swift in Sources */,
160 | B73F346A22DBCD08003AFC57 /* ViewController.swift in Sources */,
161 | );
162 | runOnlyForDeploymentPostprocessing = 0;
163 | };
164 | /* End PBXSourcesBuildPhase section */
165 |
166 | /* Begin PBXVariantGroup section */
167 | B73F346222DBCD08003AFC57 /* LaunchScreen.storyboard */ = {
168 | isa = PBXVariantGroup;
169 | children = (
170 | B73F346322DBCD08003AFC57 /* Base */,
171 | );
172 | name = LaunchScreen.storyboard;
173 | sourceTree = "";
174 | };
175 | B73F346422DBCD08003AFC57 /* Main.storyboard */ = {
176 | isa = PBXVariantGroup;
177 | children = (
178 | B73F346522DBCD08003AFC57 /* Base */,
179 | );
180 | name = Main.storyboard;
181 | sourceTree = "";
182 | };
183 | /* End PBXVariantGroup section */
184 |
185 | /* Begin XCBuildConfiguration section */
186 | B721D1191F61DF890088DC13 /* Debug */ = {
187 | isa = XCBuildConfiguration;
188 | buildSettings = {
189 | ALWAYS_SEARCH_USER_PATHS = NO;
190 | CLANG_ANALYZER_NONNULL = YES;
191 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
192 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
193 | CLANG_CXX_LIBRARY = "libc++";
194 | CLANG_ENABLE_MODULES = YES;
195 | CLANG_ENABLE_OBJC_ARC = YES;
196 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
197 | CLANG_WARN_BOOL_CONVERSION = YES;
198 | CLANG_WARN_COMMA = YES;
199 | CLANG_WARN_CONSTANT_CONVERSION = YES;
200 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
201 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
202 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
203 | CLANG_WARN_EMPTY_BODY = YES;
204 | CLANG_WARN_ENUM_CONVERSION = YES;
205 | CLANG_WARN_INFINITE_RECURSION = YES;
206 | CLANG_WARN_INT_CONVERSION = YES;
207 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
208 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
209 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
210 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
211 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
212 | CLANG_WARN_STRICT_PROTOTYPES = YES;
213 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
214 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
215 | CLANG_WARN_UNREACHABLE_CODE = YES;
216 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
217 | CODE_SIGN_IDENTITY = "iPhone Developer";
218 | COPY_PHASE_STRIP = NO;
219 | DEBUG_INFORMATION_FORMAT = dwarf;
220 | ENABLE_STRICT_OBJC_MSGSEND = YES;
221 | ENABLE_TESTABILITY = YES;
222 | GCC_C_LANGUAGE_STANDARD = gnu11;
223 | GCC_DYNAMIC_NO_PIC = NO;
224 | GCC_NO_COMMON_BLOCKS = YES;
225 | GCC_OPTIMIZATION_LEVEL = 0;
226 | GCC_PREPROCESSOR_DEFINITIONS = (
227 | "DEBUG=1",
228 | "$(inherited)",
229 | );
230 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
231 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
232 | GCC_WARN_UNDECLARED_SELECTOR = YES;
233 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
234 | GCC_WARN_UNUSED_FUNCTION = YES;
235 | GCC_WARN_UNUSED_VARIABLE = YES;
236 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
237 | MTL_ENABLE_DEBUG_INFO = YES;
238 | ONLY_ACTIVE_ARCH = YES;
239 | SDKROOT = iphoneos;
240 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
241 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
242 | };
243 | name = Debug;
244 | };
245 | B721D11A1F61DF890088DC13 /* Release */ = {
246 | isa = XCBuildConfiguration;
247 | buildSettings = {
248 | ALWAYS_SEARCH_USER_PATHS = NO;
249 | CLANG_ANALYZER_NONNULL = YES;
250 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
251 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
252 | CLANG_CXX_LIBRARY = "libc++";
253 | CLANG_ENABLE_MODULES = YES;
254 | CLANG_ENABLE_OBJC_ARC = YES;
255 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
256 | CLANG_WARN_BOOL_CONVERSION = YES;
257 | CLANG_WARN_COMMA = YES;
258 | CLANG_WARN_CONSTANT_CONVERSION = YES;
259 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
260 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
261 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
262 | CLANG_WARN_EMPTY_BODY = YES;
263 | CLANG_WARN_ENUM_CONVERSION = YES;
264 | CLANG_WARN_INFINITE_RECURSION = YES;
265 | CLANG_WARN_INT_CONVERSION = YES;
266 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
267 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
268 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
269 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
270 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
271 | CLANG_WARN_STRICT_PROTOTYPES = YES;
272 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
273 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
274 | CLANG_WARN_UNREACHABLE_CODE = YES;
275 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
276 | CODE_SIGN_IDENTITY = "iPhone Developer";
277 | COPY_PHASE_STRIP = NO;
278 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
279 | ENABLE_NS_ASSERTIONS = NO;
280 | ENABLE_STRICT_OBJC_MSGSEND = YES;
281 | GCC_C_LANGUAGE_STANDARD = gnu11;
282 | GCC_NO_COMMON_BLOCKS = YES;
283 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
284 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
285 | GCC_WARN_UNDECLARED_SELECTOR = YES;
286 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
287 | GCC_WARN_UNUSED_FUNCTION = YES;
288 | GCC_WARN_UNUSED_VARIABLE = YES;
289 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
290 | MTL_ENABLE_DEBUG_INFO = NO;
291 | SDKROOT = iphoneos;
292 | SWIFT_COMPILATION_MODE = wholemodule;
293 | SWIFT_OPTIMIZATION_LEVEL = "-O";
294 | VALIDATE_PRODUCT = YES;
295 | };
296 | name = Release;
297 | };
298 | B721D11C1F61DF890088DC13 /* Debug */ = {
299 | isa = XCBuildConfiguration;
300 | buildSettings = {
301 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
302 | CODE_SIGN_STYLE = Automatic;
303 | DEVELOPMENT_TEAM = "";
304 | INFOPLIST_FILE = "$(SRCROOT)/App/Info.plist";
305 | LD_RUNPATH_SEARCH_PATHS = (
306 | "$(inherited)",
307 | "@executable_path/Frameworks",
308 | );
309 | PRODUCT_BUNDLE_IDENTIFIER = com.mergesort.FeedbackEffect;
310 | PRODUCT_NAME = "$(TARGET_NAME)";
311 | SWIFT_VERSION = 5.0;
312 | TARGETED_DEVICE_FAMILY = "1,2";
313 | };
314 | name = Debug;
315 | };
316 | B721D11D1F61DF890088DC13 /* Release */ = {
317 | isa = XCBuildConfiguration;
318 | buildSettings = {
319 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
320 | CODE_SIGN_STYLE = Automatic;
321 | DEVELOPMENT_TEAM = "";
322 | INFOPLIST_FILE = "$(SRCROOT)/App/Info.plist";
323 | LD_RUNPATH_SEARCH_PATHS = (
324 | "$(inherited)",
325 | "@executable_path/Frameworks",
326 | );
327 | PRODUCT_BUNDLE_IDENTIFIER = com.mergesort.FeedbackEffect;
328 | PRODUCT_NAME = "$(TARGET_NAME)";
329 | SWIFT_VERSION = 5.0;
330 | TARGETED_DEVICE_FAMILY = "1,2";
331 | };
332 | name = Release;
333 | };
334 | /* End XCBuildConfiguration section */
335 |
336 | /* Begin XCConfigurationList section */
337 | B721D0F91F61DF880088DC13 /* Build configuration list for PBXProject "FeedbackEffect" */ = {
338 | isa = XCConfigurationList;
339 | buildConfigurations = (
340 | B721D1191F61DF890088DC13 /* Debug */,
341 | B721D11A1F61DF890088DC13 /* Release */,
342 | );
343 | defaultConfigurationIsVisible = 0;
344 | defaultConfigurationName = Release;
345 | };
346 | B721D11B1F61DF890088DC13 /* Build configuration list for PBXNativeTarget "Example" */ = {
347 | isa = XCConfigurationList;
348 | buildConfigurations = (
349 | B721D11C1F61DF890088DC13 /* Debug */,
350 | B721D11D1F61DF890088DC13 /* Release */,
351 | );
352 | defaultConfigurationIsVisible = 0;
353 | defaultConfigurationName = Release;
354 | };
355 | /* End XCConfigurationList section */
356 |
357 | /* Begin XCSwiftPackageProductDependency section */
358 | B73F347922DBCF85003AFC57 /* FeedbackEffect */ = {
359 | isa = XCSwiftPackageProductDependency;
360 | productName = FeedbackEffect;
361 | };
362 | /* End XCSwiftPackageProductDependency section */
363 | };
364 | rootObject = B721D0F61F61DF880088DC13 /* Project object */;
365 | }
366 |
--------------------------------------------------------------------------------