├── {{cookiecutter.app_name}}
├── {{cookiecutter.app_name}}
│ ├── Models
│ │ └── .gitkeep
│ ├── Modules
│ │ ├── .gitkeep
│ │ └── Launch
│ │ │ └── Base.lproj
│ │ │ └── LaunchScreen.storyboard
│ ├── Helpers
│ │ ├── Protocols
│ │ │ └── .gitkeep
│ │ ├── Utilities
│ │ │ ├── .gitkeep
│ │ │ ├── DeeplinkHandler.swift
│ │ │ ├── RootRouter.swift
│ │ │ ├── NotificationsHandler.swift
│ │ │ └── ConfigurationManager.swift
│ │ └── Extensions
│ │ │ └── .gitkeep
│ ├── Resources
│ │ ├── Fonts
│ │ │ └── .gitkeep
│ │ ├── Generated
│ │ │ └── .gitkeep
│ │ ├── Translations
│ │ │ ├── .gitkeep
│ │ │ └── Localizable.strings
│ │ └── Images
│ │ │ └── Assets.xcassets
│ │ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── SupportingFiles
│ │ ├── Configuration.plist
│ │ └── Info.plist
│ ├── main.swift
│ └── AppDelegate.swift
├── Gemfile
├── {{cookiecutter.app_name}}Tests
│ ├── {{cookiecutter.app_name}}Tests-Bridging-Header.h
│ ├── TestsAppDelegate.swift
│ └── Info.plist
├── {{cookiecutter.app_name}}.xcodeproj
│ ├── project.xcworkspace
│ │ └── contents.xcworkspacedata
│ ├── xcuserdata
│ │ ├── mlody.xcuserdatad
│ │ │ └── xcschemes
│ │ │ │ └── xcschememanagement.plist
│ │ └── xlogic.xcuserdatad
│ │ │ └── xcschemes
│ │ │ ├── {{cookiecutter.app_name}}-Debug.xcscheme
│ │ │ ├── {{cookiecutter.app_name}}-Release.xcscheme
│ │ │ └── {{cookiecutter.app_name}}-Staging.xcscheme
│ └── project.pbxproj
├── Podfile
├── .swiftlint.yml
├── Readme.md
└── .gitignore
├── cookiecutter.json
├── hooks
└── post_gen_project.sh
├── LICENSE
└── Readme.md
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/Models/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/Modules/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/Helpers/Protocols/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/Helpers/Utilities/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/Resources/Fonts/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/Helpers/Extensions/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/Resources/Generated/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/Resources/Translations/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/cookiecutter.json:
--------------------------------------------------------------------------------
1 | {
2 | "app_name": "AwesomeApp",
3 | "company_name": "AwesomeCompany"
4 | }
5 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gem "cocoapods", "~> 1.5.3"
4 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}Tests/{{cookiecutter.app_name}}Tests-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // Use this file to import your target's public headers that you would like to expose to Swift.
3 | //
4 |
5 |
--------------------------------------------------------------------------------
/hooks/post_gen_project.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | GREEN='\033[0;32m'
3 | echo -e "${GREEN}Project successfuly generated!"
4 | echo -e "${GREEN}You will need to install bundler and pods for the project. Checkout the generated project Readme to get started."
5 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/Resources/Translations/Localizable.strings:
--------------------------------------------------------------------------------
1 | /*
2 | Localizable.strings
3 | {{cookiecutter.app_name}}
4 |
5 | Copyright © {{cookiecutter.company_name}}. All rights reserved.
6 | */
7 |
8 | // MARK: Common
9 |
10 | "common.ok" = "Ok";
11 | "common.cancel" = "Cancel";
12 | "common.error" = "Error";
13 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}.xcodeproj/xcuserdata/mlody.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | {{cookiecutter.app_name}}.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/SupportingFiles/Configuration.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 |
7 | backendUrl
8 | https://dev.backend.url
9 |
10 | Staging
11 |
12 | backendUrl
13 | https://staging.backend.url
14 |
15 | Release
16 |
17 | backendUrl
18 | https://production.backend.url
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}Tests/TestsAppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TestsAppDelegate.swift
3 | // {{cookiecutter.app_name}}Tests
4 | //
5 | // Copyright © {{cookiecutter.company_name}}. All rights reserved.
6 | //
7 |
8 | import UIKit
9 |
10 | /// The TestsAppDelegate used when the app is run in the test environment
11 | /// This AppDelegate usage is determined in the main.swift file in the main app target
12 | class TestsAppDelegate: NSObject {
13 |
14 | /// This constructor is called at the start of the tests and is a good point for test wide customization
15 | override init() {
16 | super.init()
17 | // Customize any TestsAppDelegate logic here
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}Tests/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 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/Podfile:
--------------------------------------------------------------------------------
1 | source 'https://github.com/CocoaPods/Specs.git'
2 |
3 | platform :ios, '10.0'
4 |
5 | use_frameworks!
6 |
7 | # ignore all warnings from all pods
8 | inhibit_all_warnings!
9 |
10 | target '{{cookiecutter.app_name}}' do
11 |
12 | pod 'R.swift', '5.0.0'
13 | pod 'SwiftLint', '0.31.0'
14 |
15 | target '{{cookiecutter.app_name}}Tests' do
16 | inherit! :search_paths
17 | end
18 | end
19 |
20 | post_install do |installer|
21 | installer.pods_project.targets.each do |target|
22 | target.build_configurations.each do |config|
23 | config.build_settings['EXPANDED_CODE_SIGN_IDENTITY'] = ""
24 | config.build_settings['CODE_SIGNING_REQUIRED'] = "NO"
25 | config.build_settings['CODE_SIGNING_ALLOWED'] = "NO"
26 | config.build_settings['SWIFT_VERSION'] = '5.0'
27 | end
28 | end
29 | end
30 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/.swiftlint.yml:
--------------------------------------------------------------------------------
1 | disabled_rules:
2 | - todo
3 | opt_in_rules:
4 | - attributes
5 | - closure_end_indentation
6 | - closure_spacing
7 | - conditional_returns_on_newline
8 | - empty_count
9 | - explicit_init
10 | - fatal_error_message
11 | - first_where
12 | - force_unwrapping
13 | - multiline_parameters
14 | - operator_usage_whitespace
15 | - overridden_super_call
16 | - pattern_matching_keywords
17 | - private_outlet
18 | - prohibited_super_call
19 | - redundant_nil_coalescing
20 | - single_test_class
21 | - sorted_imports
22 | - switch_case_on_newline
23 | - trailing_closure
24 | - unneeded_parentheses_in_closure_argument
25 | excluded:
26 | - Carthage
27 | - Pods
28 | - {{cookiecutter.app_name}}/Resources/Generated/R.generated.swift
29 | identifier_name:
30 | excluded:
31 | - id
32 | - to
33 | - in
34 | - at
35 | - of
36 | - up
37 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/Readme.md:
--------------------------------------------------------------------------------
1 | # {{cookiecutter.app_name}}
2 |
3 | Supports: iOS 10.x and above
4 |
5 | ## Branches:
6 |
7 | * master - stable app releases
8 | * develop - development branch, merge your feature branches here
9 |
10 | ## Dependencies:
11 |
12 | The project is using cocoapods for managing external libraries and a Gemfile for managing the cocoapods version.
13 |
14 | Get Bundler
15 |
16 | ```
17 | sudo gem install bundler
18 | ```
19 |
20 | To install the specific cocoapods version run
21 |
22 | ```
23 | bundle install
24 | ```
25 |
26 | Then install the pods
27 |
28 | ```
29 | bundle exec pod install
30 | ```
31 |
32 | ### Core Dependencies
33 |
34 | * Swiftlint - A tool to enforce Swift style and conventions.
35 | * R.swift - Get strong typed, autocompleted resources like images, fonts and segues in Swift projects
36 |
37 | ## Project structure:
38 |
39 | * Resources - fonts, strings, images, generated files etc.
40 | * SupportingFiles - configuration plist files
41 | * Models - model objects
42 | * Modules - contains app modules (UI + Code)
43 | * Helpers - protocols, extension and utility classes
44 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017 pgorzelany
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/Helpers/Utilities/DeeplinkHandler.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DeeplinkHandler.swift
3 | // {{cookiecutter.app_name}}
4 | //
5 | // Copyright © {{cookiecutter.company_name}}. All rights reserved.
6 | //
7 |
8 | import Foundation
9 |
10 | class DeeplinkHandler {
11 |
12 | enum Path: String {
13 | case resetPassword = "/api/password/reset" // example deeplink path
14 | }
15 |
16 | // MARK: Methods
17 |
18 | func handleDeeplink(with url: URL) {
19 | guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true),
20 | let path = getPath(from: components) else {
21 | return
22 | }
23 |
24 | switch path {
25 | case .resetPassword:
26 | handleResetPasword(with: components)
27 | }
28 | }
29 |
30 | // MARK: Private methods
31 |
32 | private func getPath(from components: URLComponents) -> Path? {
33 | return Path(rawValue: components.path)
34 | }
35 |
36 | private func handleResetPasword(with components: URLComponents) {
37 | // implementation goes here, probably extract token from query items and send to api
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/main.swift:
--------------------------------------------------------------------------------
1 | //
2 | // main.swift
3 | // {{cookiecutter.app_name}}
4 | //
5 | // Copyright © {{cookiecutter.company_name}}. All rights reserved.
6 | //
7 |
8 | import Foundation
9 | import UIKit
10 |
11 | /// Checks if the app is being opened by the test target
12 | ///
13 | /// - Returns: True if the app is opened by the test target
14 | private func isRunningTests() -> Bool {
15 | return NSClassFromString("XCTestCase") != nil
16 | }
17 |
18 | /// Gets the right AppDelegate class for the current environment.
19 | /// The real AppDelegate should not be used in testing since it may have side effects.
20 | /// Side effects include making api calls, registering for notifications, setting core data, setting UI etc.
21 | ///
22 | /// - Returns: TestsAppDelegate if the app was opened by the test target. Normal AppDelegate otherwise.
23 | private func getDelegateClassName() -> String {
24 | return isRunningTests() ? NSStringFromClass(TestsAppDelegate.self) : NSStringFromClass(AppDelegate.self)
25 | }
26 |
27 | /// Load the actual app with the right app delegate depending on environment
28 | /// Based on https://marcosantadev.com/fake-appdelegate-unit-testing-swift/
29 | _ = UIApplicationMain(CommandLine.argc, CommandLine.unsafeArgv, nil, getDelegateClassName())
30 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/Helpers/Utilities/RootRouter.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RootRouter.swift
3 | // {{cookiecutter.app_name}}
4 | //
5 | // Copyright © {{cookiecutter.company_name}}. All rights reserved.
6 | //
7 |
8 | import UIKit
9 |
10 | class RootRouter {
11 |
12 | /** Replaces root view controller. You can specify the replacment animation type.
13 | If no animation type is specified, there is no animation */
14 | func setRootViewController(controller: UIViewController, animatedWithOptions: UIView.AnimationOptions?) {
15 | guard let window = UIApplication.shared.keyWindow else {
16 | fatalError("No window in app")
17 | }
18 | if let animationOptions = animatedWithOptions, window.rootViewController != nil {
19 | window.rootViewController = controller
20 | UIView.transition(with: window, duration: 0.33, options: animationOptions, animations: {
21 | }, completion: nil)
22 | } else {
23 | window.rootViewController = controller
24 | }
25 | }
26 |
27 | func loadMainAppStructure() {
28 | // Customize your app structure here
29 | let controller = UIViewController()
30 | controller.view.backgroundColor = UIColor.red
31 | setRootViewController(controller: controller, animatedWithOptions: nil)
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/Helpers/Utilities/NotificationsHandler.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NotificationsHandler.swift
3 | // {{cookiecutter.app_name}}
4 | //
5 | // Copyright © {{cookiecutter.company_name}}. All rights reserved.
6 | //
7 |
8 | import Foundation
9 | import UIKit
10 | import UserNotifications
11 |
12 | class NotificationsHandler: NSObject {
13 |
14 | // MARK: Public methods
15 |
16 | func configure() {
17 | UNUserNotificationCenter.current().delegate = self
18 | }
19 |
20 | func registerForRemoteNotifications() {
21 | let application = UIApplication.shared
22 | let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
23 | UNUserNotificationCenter.current().requestAuthorization(options: authOptions) {_, _ in
24 | // do nothing for now
25 | }
26 |
27 | application.registerForRemoteNotifications()
28 | }
29 |
30 | func handleRemoteNotification(with userInfo: [AnyHashable: Any]) {
31 | }
32 | }
33 |
34 | extension NotificationsHandler: UNUserNotificationCenterDelegate {
35 |
36 | func userNotificationCenter(
37 | _ center: UNUserNotificationCenter,
38 | willPresent notification: UNNotification,
39 | withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
40 | completionHandler(.alert)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/SupportingFiles/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 | Configuration
22 | $(CONFIGURATION)
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
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 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/Modules/Launch/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 |
27 |
28 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/Resources/Images/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 | }
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // {{cookiecutter.app_name}}
4 | //
5 | // Copyright © {{cookiecutter.company_name}}. All rights reserved.
6 | //
7 |
8 | import UIKit
9 |
10 | class AppDelegate: UIResponder, UIApplicationDelegate {
11 |
12 | var window: UIWindow?
13 | lazy private var router = RootRouter()
14 | lazy private var deeplinkHandler = DeeplinkHandler()
15 | lazy private var notificationsHandler = NotificationsHandler()
16 |
17 | func application(_ application: UIApplication,
18 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
19 | window = UIWindow(frame: UIScreen.main.bounds)
20 | window?.makeKeyAndVisible()
21 |
22 | // Notifications
23 | notificationsHandler.configure()
24 |
25 | // App structure
26 | router.loadMainAppStructure()
27 |
28 | return true
29 | }
30 |
31 | func application(_ application: UIApplication,
32 | continue userActivity: NSUserActivity,
33 | restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
34 | // To enable full universal link functionality add and configure the associated domain capability
35 | // https://developer.apple.com/library/content/documentation/General/Conceptual/AppSearch/UniversalLinks.html
36 | if userActivity.activityType == NSUserActivityTypeBrowsingWeb, let url = userActivity.webpageURL {
37 | deeplinkHandler.handleDeeplink(with: url)
38 | }
39 | return true
40 | }
41 |
42 | func application(_ application: UIApplication,
43 | didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
44 | // To enable full remote notifications functionality you should first register the device with your api service
45 | //https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/
46 | notificationsHandler.handleRemoteNotification(with: userInfo)
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/.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 | IDEWorkspaceChecks.plist
20 |
21 | ## Other
22 | *.moved-aside
23 | *.xccheckout
24 | *.xcscmblueprint
25 |
26 | ## Obj-C/Swift specific
27 | *.hmap
28 | *.ipa
29 | *.dSYM.zip
30 | *.dSYM
31 |
32 | ## Playgrounds
33 | timeline.xctimeline
34 | playground.xcworkspace
35 |
36 | # Swift Package Manager
37 | #
38 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
39 | # Packages/
40 | # Package.pins
41 | # Package.resolved
42 | .build/
43 |
44 | # CocoaPods
45 | #
46 | # We recommend against adding the Pods directory to your .gitignore. However
47 | # you should judge for yourself, the pros and cons are mentioned at:
48 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
49 | #
50 | # Pods/
51 | #
52 | # Add this line if you want to avoid checking in source code from the Xcode workspace
53 | # *.xcworkspace
54 |
55 | # Carthage
56 | #
57 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
58 | # Carthage/Checkouts
59 |
60 | Carthage/Build
61 |
62 | # fastlane
63 | #
64 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
65 | # screenshots whenever they are needed.
66 | # For more information about the recommended setup visit:
67 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
68 |
69 | fastlane/report.xml
70 | fastlane/Preview.html
71 | fastlane/screenshots/**/*.png
72 | fastlane/test_output
73 |
74 | # Code Injection
75 | #
76 | # After new code Injection tools there's a generated folder /iOSInjectionProject
77 | # https://github.com/johnno1962/injectionforxcode
78 |
79 | iOSInjectionProject/
80 |
81 | # R.swift
82 | **/R.generated.swift
83 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}/Helpers/Utilities/ConfigurationManager.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ConfigurationManager.swift
3 | // {{cookiecutter.app_name}}
4 | //
5 | // Copyright © {{cookiecutter.company_name}}. All rights reserved.
6 | //
7 |
8 | import Foundation
9 |
10 | /**
11 | Use the Configuration.plist file to provide variables dependent on build configuration.
12 | An example would be the backend url, where for different build configurations you have different backend urls.
13 | */
14 | class ConfigurationManager {
15 |
16 | enum Configuration: String {
17 | case debug = "Debug"
18 | case release = "Release"
19 | case production = "Production"
20 | }
21 |
22 | // MARK: Shared instance
23 |
24 | static let shared = ConfigurationManager()
25 |
26 | // MARK: Properties
27 |
28 | private let configurationKey = "Configuration"
29 | private let configurationDictionaryName = "Configuration"
30 | private let backendUrlKey = "backendUrl"
31 |
32 | let activeConfiguration: Configuration
33 | private let activeConfigurationDictionary: NSDictionary
34 |
35 | // MARK: Lifecycle
36 |
37 | init () {
38 | let bundle = Bundle(for: ConfigurationManager.self)
39 | guard let rawConfiguration = bundle.object(forInfoDictionaryKey: configurationKey) as? String,
40 | let activeConfiguration = Configuration(rawValue: rawConfiguration),
41 | let configurationDictionaryPath = bundle.path(forResource: configurationDictionaryName, ofType: "plist"),
42 | let configurationDictionary = NSDictionary(contentsOfFile: configurationDictionaryPath),
43 | let activeEnvironmentDictionary = configurationDictionary[activeConfiguration.rawValue] as? NSDictionary
44 | else {
45 | fatalError("Configuration Error")
46 |
47 | }
48 | self.activeConfiguration = activeConfiguration
49 | self.activeConfigurationDictionary = activeEnvironmentDictionary
50 | }
51 |
52 | // MARK: Methods
53 |
54 | private func getActiveVariableValue(forKey key: String) -> V {
55 | guard let value = activeConfigurationDictionary[key] as? V else {
56 | fatalError("No value satysfying requirements")
57 | }
58 | return value
59 | }
60 |
61 | func isRunning(in configuration: Configuration) -> Bool {
62 | return activeConfiguration == configuration
63 | }
64 |
65 | func getBackendUrl() -> URL {
66 | let backendUrlString: String = getActiveVariableValue(forKey: backendUrlKey)
67 | guard let backendUrl = URL(string: backendUrlString) else {
68 | fatalError("Backend URL missing")
69 | }
70 | return backendUrl
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | ## iOS Project Template
2 |
3 | A template to jumpstart your next iOS project integrating best practices and tools.
4 | Supports Xcode 10, Swift 4.2
5 |
6 | ## Motivation
7 |
8 | When working for early stage startups I frequently had to start new projects from scratch. While doing this I noticed that I am spending a lot of time doing basic project setup and integrating basic tools and best practices in all projects from scratch.
9 |
10 | This template should save project setup time and also provide a common foundation that each team member will be accustomed to so that you don't have to think and explore the project structure and foundations. They will always be the same.
11 |
12 | For a more in-depth writeup of the motivation and project, check out [my blog post](https://medium.com/@piotr.gorzelany/ios-project-best-practices-and-tools-c46135b8116d).
13 |
14 | ## Contains (best practices)
15 |
16 | * [Swiftlint](https://github.com/realm/SwiftLint) integration - A tool to enforce Swift style and conventions
17 | * [R.swift](https://github.com/mac-cain13/R.swift) integration - strong typed, autocompleted resources like images, fonts and segues
18 | * [Separate AppDelegate for app and tests](https://marcosantadev.com/fake-appdelegate-unit-testing-swift/)
19 | * Dev/Staging/Prod configurations
20 | * [Compiler performance profiling flags](https://www.jessesquires.com/blog/measuring-compile-times-xcode9/)
21 | * [Cocoapods integration](https://cocoapods.org)
22 | * [Gemfile for managing Cocoapods version](https://guides.cocoapods.org/using/a-gemfile.html)
23 | * Standard Readme
24 | * Standard project structure
25 | * [Standard gitignore](https://github.com/github/gitignore/blob/master/Swift.gitignore)
26 | * Base classes for handling deeplinks and notifications
27 |
28 | ## Prerequisites:
29 | This project needs [Cookiecutter](https://cookiecutter.readthedocs.io/en/latest/installation.html)
30 |
31 | ```
32 | brew install cookiecutter
33 | ```
34 |
35 | ## Usage
36 |
37 | The project uses Cookiecutter for project templating. To create a new project from this template just run:
38 |
39 | ```
40 | cookiecutter https://github.com/pgorzelany/iOS-project-template.git
41 | ```
42 |
43 | You will get a prompt to give a new app name. Thats it, you should have a new folder with your new app created based on this template!
44 |
45 | The project is using cocoapods for managing external libraries and a Gemfile for managing the cocoapods version.
46 | To install the cocoapod dependencies do the following:
47 |
48 | Get Bundler
49 |
50 | ```
51 | sudo gem install bundler
52 | ```
53 |
54 | To install the specific cocoapods version run
55 |
56 | ```
57 | bundle install
58 | ```
59 |
60 | Then install the pods
61 |
62 | ```
63 | bundle exec pod install
64 | ```
65 |
66 | ## Additional configuration
67 |
68 | You will have to manually configure the bundle id of the main target and test target.
69 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}.xcodeproj/xcuserdata/xlogic.xcuserdatad/xcschemes/{{cookiecutter.app_name}}-Debug.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
34 |
40 |
41 |
42 |
43 |
44 |
50 |
51 |
52 |
53 |
54 |
55 |
66 |
68 |
74 |
75 |
76 |
77 |
78 |
79 |
85 |
87 |
93 |
94 |
95 |
96 |
98 |
99 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}.xcodeproj/xcuserdata/xlogic.xcuserdatad/xcschemes/{{cookiecutter.app_name}}-Release.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
34 |
40 |
41 |
42 |
43 |
44 |
50 |
51 |
52 |
53 |
54 |
55 |
66 |
68 |
74 |
75 |
76 |
77 |
78 |
79 |
85 |
87 |
93 |
94 |
95 |
96 |
98 |
99 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}.xcodeproj/xcuserdata/xlogic.xcuserdatad/xcschemes/{{cookiecutter.app_name}}-Staging.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
34 |
40 |
41 |
42 |
43 |
44 |
50 |
51 |
52 |
53 |
54 |
55 |
66 |
68 |
74 |
75 |
76 |
77 |
78 |
79 |
85 |
87 |
93 |
94 |
95 |
96 |
98 |
99 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/{{cookiecutter.app_name}}/{{cookiecutter.app_name}}.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 48;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 2A1DD4DF1F389C2200712195 /* DeeplinkHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A1DD4DE1F389C2200712195 /* DeeplinkHandler.swift */; };
11 | 2A1DD4E11F389E2100712195 /* NotificationsHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A1DD4E01F389E2100712195 /* NotificationsHandler.swift */; };
12 | 2A1E77371F384BFC006C84D4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A1E77361F384BFC006C84D4 /* AppDelegate.swift */; };
13 | 2A1E773E1F384BFD006C84D4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2A1E773D1F384BFD006C84D4 /* Assets.xcassets */; };
14 | 2A1E77411F384BFD006C84D4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2A1E773F1F384BFD006C84D4 /* LaunchScreen.storyboard */; };
15 | 2A9222821F38797600A648E6 /* ConfigurationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A9222811F38797600A648E6 /* ConfigurationManager.swift */; };
16 | 2ABEE6D41F38856A00531205 /* Configuration.plist in Resources */ = {isa = PBXBuildFile; fileRef = 2ABEE6D31F38828A00531205 /* Configuration.plist */; };
17 | 2ABEE6D61F3886D700531205 /* RootRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2ABEE6D51F3886D700531205 /* RootRouter.swift */; };
18 | 553FC23C214047CB001D9362 /* R.generated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553FC23B214047CB001D9362 /* R.generated.swift */; };
19 | C90395241FC622D2006F1DC0 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = C90395231FC622D2006F1DC0 /* main.swift */; };
20 | C90395261FC62399006F1DC0 /* TestsAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C90395251FC62399006F1DC0 /* TestsAppDelegate.swift */; };
21 | C90395271FC62425006F1DC0 /* TestsAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C90395251FC62399006F1DC0 /* TestsAppDelegate.swift */; };
22 | FCB2C7CB1F57127800481080 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = FCB2C7CA1F57127800481080 /* Localizable.strings */; };
23 | /* End PBXBuildFile section */
24 |
25 | /* Begin PBXContainerItemProxy section */
26 | 2A1E77481F384BFD006C84D4 /* PBXContainerItemProxy */ = {
27 | isa = PBXContainerItemProxy;
28 | containerPortal = 2A1E772B1F384BFC006C84D4 /* Project object */;
29 | proxyType = 1;
30 | remoteGlobalIDString = 2A1E77321F384BFC006C84D4;
31 | remoteInfo = "{{cookiecutter.app_name}}";
32 | };
33 | /* End PBXContainerItemProxy section */
34 |
35 | /* Begin PBXFileReference section */
36 | 2A1DD4DE1F389C2200712195 /* DeeplinkHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeeplinkHandler.swift; sourceTree = ""; };
37 | 2A1DD4E01F389E2100712195 /* NotificationsHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsHandler.swift; sourceTree = ""; };
38 | 2A1E77331F384BFC006C84D4 /* {{cookiecutter.app_name}}.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "{{cookiecutter.app_name}}.app"; sourceTree = BUILT_PRODUCTS_DIR; };
39 | 2A1E77361F384BFC006C84D4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
40 | 2A1E773D1F384BFD006C84D4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
41 | 2A1E77401F384BFD006C84D4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
42 | 2A1E77421F384BFD006C84D4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
43 | 2A1E77471F384BFD006C84D4 /* {{cookiecutter.app_name}}Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "{{cookiecutter.app_name}}Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
44 | 2A1E774D1F384BFD006C84D4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
45 | 2A9222811F38797600A648E6 /* ConfigurationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationManager.swift; sourceTree = ""; };
46 | 2A9222841F387B1D00A648E6 /* {{cookiecutter.app_name}}Tests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "{{cookiecutter.app_name}}Tests-Bridging-Header.h"; sourceTree = ""; };
47 | 2ABEE6D31F38828A00531205 /* Configuration.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Configuration.plist; sourceTree = ""; };
48 | 2ABEE6D51F3886D700531205 /* RootRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootRouter.swift; sourceTree = ""; };
49 | 553FC23B214047CB001D9362 /* R.generated.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = R.generated.swift; sourceTree = ""; };
50 | 55F50BE321404BDD00FAC039 /* Readme.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = Readme.md; sourceTree = ""; };
51 | C90395231FC622D2006F1DC0 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; };
52 | C90395251FC62399006F1DC0 /* TestsAppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestsAppDelegate.swift; sourceTree = ""; };
53 | FCB2C7CA1F57127800481080 /* Localizable.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = Localizable.strings; sourceTree = ""; };
54 | /* End PBXFileReference section */
55 |
56 | /* Begin PBXFrameworksBuildPhase section */
57 | 2A1E77301F384BFC006C84D4 /* Frameworks */ = {
58 | isa = PBXFrameworksBuildPhase;
59 | buildActionMask = 2147483647;
60 | files = (
61 | );
62 | runOnlyForDeploymentPostprocessing = 0;
63 | };
64 | 2A1E77441F384BFD006C84D4 /* Frameworks */ = {
65 | isa = PBXFrameworksBuildPhase;
66 | buildActionMask = 2147483647;
67 | files = (
68 | );
69 | runOnlyForDeploymentPostprocessing = 0;
70 | };
71 | /* End PBXFrameworksBuildPhase section */
72 |
73 | /* Begin PBXGroup section */
74 | 2A1DD4E21F38A09700712195 /* Launch */ = {
75 | isa = PBXGroup;
76 | children = (
77 | 2A1E773F1F384BFD006C84D4 /* LaunchScreen.storyboard */,
78 | );
79 | path = Launch;
80 | sourceTree = "";
81 | };
82 | 2A1E772A1F384BFC006C84D4 = {
83 | isa = PBXGroup;
84 | children = (
85 | 55F50BE321404BDD00FAC039 /* Readme.md */,
86 | 2A1E77351F384BFC006C84D4 /* {{cookiecutter.app_name}} */,
87 | 2A1E774A1F384BFD006C84D4 /* {{cookiecutter.app_name}}Tests */,
88 | 2A1E77341F384BFC006C84D4 /* Products */,
89 | );
90 | sourceTree = "";
91 | };
92 | 2A1E77341F384BFC006C84D4 /* Products */ = {
93 | isa = PBXGroup;
94 | children = (
95 | 2A1E77331F384BFC006C84D4 /* {{cookiecutter.app_name}}.app */,
96 | 2A1E77471F384BFD006C84D4 /* {{cookiecutter.app_name}}Tests.xctest */,
97 | );
98 | name = Products;
99 | sourceTree = "";
100 | };
101 | 2A1E77351F384BFC006C84D4 /* {{cookiecutter.app_name}} */ = {
102 | isa = PBXGroup;
103 | children = (
104 | C90395231FC622D2006F1DC0 /* main.swift */,
105 | 2A1E77361F384BFC006C84D4 /* AppDelegate.swift */,
106 | 2AFB31021F3853C6009C4586 /* Resources */,
107 | 2AFB31071F38542E009C4586 /* SupportingFiles */,
108 | 2AB31D9E1F38740A00B7D1F3 /* Models */,
109 | 2AB31D9F1F38741400B7D1F3 /* Modules */,
110 | 2AFB310A1F385A20009C4586 /* Helpers */,
111 | );
112 | path = "{{cookiecutter.app_name}}";
113 | sourceTree = "";
114 | };
115 | 2A1E774A1F384BFD006C84D4 /* {{cookiecutter.app_name}}Tests */ = {
116 | isa = PBXGroup;
117 | children = (
118 | 2A9222841F387B1D00A648E6 /* {{cookiecutter.app_name}}Tests-Bridging-Header.h */,
119 | 2A1E774D1F384BFD006C84D4 /* Info.plist */,
120 | C90395251FC62399006F1DC0 /* TestsAppDelegate.swift */,
121 | );
122 | path = "{{cookiecutter.app_name}}Tests";
123 | sourceTree = "";
124 | };
125 | 2AB31D9E1F38740A00B7D1F3 /* Models */ = {
126 | isa = PBXGroup;
127 | children = (
128 | );
129 | path = Models;
130 | sourceTree = "";
131 | };
132 | 2AB31D9F1F38741400B7D1F3 /* Modules */ = {
133 | isa = PBXGroup;
134 | children = (
135 | 2A1DD4E21F38A09700712195 /* Launch */,
136 | );
137 | path = Modules;
138 | sourceTree = "";
139 | };
140 | 2AB31DA01F38742400B7D1F3 /* Fonts */ = {
141 | isa = PBXGroup;
142 | children = (
143 | );
144 | path = Fonts;
145 | sourceTree = "";
146 | };
147 | 2AB31DA11F38742A00B7D1F3 /* Translations */ = {
148 | isa = PBXGroup;
149 | children = (
150 | FCB2C7CA1F57127800481080 /* Localizable.strings */,
151 | );
152 | path = Translations;
153 | sourceTree = "";
154 | };
155 | 2AB31DA21F38744600B7D1F3 /* Protocols */ = {
156 | isa = PBXGroup;
157 | children = (
158 | );
159 | path = Protocols;
160 | sourceTree = "";
161 | };
162 | 2AB31DA31F38744C00B7D1F3 /* Utilities */ = {
163 | isa = PBXGroup;
164 | children = (
165 | 2ABEE6D51F3886D700531205 /* RootRouter.swift */,
166 | 2A9222811F38797600A648E6 /* ConfigurationManager.swift */,
167 | 2A1DD4DE1F389C2200712195 /* DeeplinkHandler.swift */,
168 | 2A1DD4E01F389E2100712195 /* NotificationsHandler.swift */,
169 | );
170 | path = Utilities;
171 | sourceTree = "";
172 | };
173 | 2AB31DA41F38745300B7D1F3 /* Extensions */ = {
174 | isa = PBXGroup;
175 | children = (
176 | );
177 | path = Extensions;
178 | sourceTree = "";
179 | };
180 | 2AFB31021F3853C6009C4586 /* Resources */ = {
181 | isa = PBXGroup;
182 | children = (
183 | 553FC239214046D0001D9362 /* Generated */,
184 | 2AB31DA11F38742A00B7D1F3 /* Translations */,
185 | 2AB31DA01F38742400B7D1F3 /* Fonts */,
186 | 2AFB31031F3853D9009C4586 /* Images */,
187 | );
188 | path = Resources;
189 | sourceTree = "";
190 | };
191 | 2AFB31031F3853D9009C4586 /* Images */ = {
192 | isa = PBXGroup;
193 | children = (
194 | 2A1E773D1F384BFD006C84D4 /* Assets.xcassets */,
195 | );
196 | path = Images;
197 | sourceTree = "";
198 | };
199 | 2AFB31071F38542E009C4586 /* SupportingFiles */ = {
200 | isa = PBXGroup;
201 | children = (
202 | 2ABEE6D31F38828A00531205 /* Configuration.plist */,
203 | 2A1E77421F384BFD006C84D4 /* Info.plist */,
204 | );
205 | path = SupportingFiles;
206 | sourceTree = "";
207 | };
208 | 2AFB310A1F385A20009C4586 /* Helpers */ = {
209 | isa = PBXGroup;
210 | children = (
211 | 2AB31DA21F38744600B7D1F3 /* Protocols */,
212 | 2AB31DA41F38745300B7D1F3 /* Extensions */,
213 | 2AB31DA31F38744C00B7D1F3 /* Utilities */,
214 | );
215 | path = Helpers;
216 | sourceTree = "";
217 | };
218 | 553FC239214046D0001D9362 /* Generated */ = {
219 | isa = PBXGroup;
220 | children = (
221 | 553FC23B214047CB001D9362 /* R.generated.swift */,
222 | );
223 | path = Generated;
224 | sourceTree = "";
225 | };
226 | /* End PBXGroup section */
227 |
228 | /* Begin PBXNativeTarget section */
229 | 2A1E77321F384BFC006C84D4 /* {{cookiecutter.app_name}} */ = {
230 | isa = PBXNativeTarget;
231 | buildConfigurationList = 2A1E77501F384BFD006C84D4 /* Build configuration list for PBXNativeTarget "{{cookiecutter.app_name}}" */;
232 | buildPhases = (
233 | 553FC23A2140470C001D9362 /* R.swift */,
234 | 2A1E772F1F384BFC006C84D4 /* Sources */,
235 | FC9CA61F1F83C1B700B8EB94 /* SwiftLint */,
236 | 2A1E77301F384BFC006C84D4 /* Frameworks */,
237 | 2A1E77311F384BFC006C84D4 /* Resources */,
238 | );
239 | buildRules = (
240 | );
241 | dependencies = (
242 | );
243 | name = "{{cookiecutter.app_name}}";
244 | productName = "{{cookiecutter.app_name}}";
245 | productReference = 2A1E77331F384BFC006C84D4 /* {{cookiecutter.app_name}}.app */;
246 | productType = "com.apple.product-type.application";
247 | };
248 | 2A1E77461F384BFD006C84D4 /* {{cookiecutter.app_name}}Tests */ = {
249 | isa = PBXNativeTarget;
250 | buildConfigurationList = 2A1E77531F384BFD006C84D4 /* Build configuration list for PBXNativeTarget "{{cookiecutter.app_name}}Tests" */;
251 | buildPhases = (
252 | 2A1E77431F384BFD006C84D4 /* Sources */,
253 | 2A1E77441F384BFD006C84D4 /* Frameworks */,
254 | 2A1E77451F384BFD006C84D4 /* Resources */,
255 | );
256 | buildRules = (
257 | );
258 | dependencies = (
259 | 2A1E77491F384BFD006C84D4 /* PBXTargetDependency */,
260 | );
261 | name = "{{cookiecutter.app_name}}Tests";
262 | productName = "{{cookiecutter.app_name}}Tests";
263 | productReference = 2A1E77471F384BFD006C84D4 /* {{cookiecutter.app_name}}Tests.xctest */;
264 | productType = "com.apple.product-type.bundle.unit-test";
265 | };
266 | /* End PBXNativeTarget section */
267 |
268 | /* Begin PBXProject section */
269 | 2A1E772B1F384BFC006C84D4 /* Project object */ = {
270 | isa = PBXProject;
271 | attributes = {
272 | LastSwiftUpdateCheck = 0900;
273 | LastUpgradeCheck = 0900;
274 | ORGANIZATIONNAME = "{{cookiecutter.company_name}}";
275 | TargetAttributes = {
276 | 2A1E77321F384BFC006C84D4 = {
277 | CreatedOnToolsVersion = 9.0;
278 | };
279 | 2A1E77461F384BFD006C84D4 = {
280 | CreatedOnToolsVersion = 9.0;
281 | LastSwiftMigration = 0900;
282 | TestTargetID = 2A1E77321F384BFC006C84D4;
283 | };
284 | };
285 | };
286 | buildConfigurationList = 2A1E772E1F384BFC006C84D4 /* Build configuration list for PBXProject "{{cookiecutter.app_name}}" */;
287 | compatibilityVersion = "Xcode 8.0";
288 | developmentRegion = en;
289 | hasScannedForEncodings = 0;
290 | knownRegions = (
291 | en,
292 | Base,
293 | );
294 | mainGroup = 2A1E772A1F384BFC006C84D4;
295 | productRefGroup = 2A1E77341F384BFC006C84D4 /* Products */;
296 | projectDirPath = "";
297 | projectRoot = "";
298 | targets = (
299 | 2A1E77321F384BFC006C84D4 /* {{cookiecutter.app_name}} */,
300 | 2A1E77461F384BFD006C84D4 /* {{cookiecutter.app_name}}Tests */,
301 | );
302 | };
303 | /* End PBXProject section */
304 |
305 | /* Begin PBXResourcesBuildPhase section */
306 | 2A1E77311F384BFC006C84D4 /* Resources */ = {
307 | isa = PBXResourcesBuildPhase;
308 | buildActionMask = 2147483647;
309 | files = (
310 | 2ABEE6D41F38856A00531205 /* Configuration.plist in Resources */,
311 | FCB2C7CB1F57127800481080 /* Localizable.strings in Resources */,
312 | 2A1E77411F384BFD006C84D4 /* LaunchScreen.storyboard in Resources */,
313 | 2A1E773E1F384BFD006C84D4 /* Assets.xcassets in Resources */,
314 | );
315 | runOnlyForDeploymentPostprocessing = 0;
316 | };
317 | 2A1E77451F384BFD006C84D4 /* Resources */ = {
318 | isa = PBXResourcesBuildPhase;
319 | buildActionMask = 2147483647;
320 | files = (
321 | );
322 | runOnlyForDeploymentPostprocessing = 0;
323 | };
324 | /* End PBXResourcesBuildPhase section */
325 |
326 | /* Begin PBXShellScriptBuildPhase section */
327 | 553FC23A2140470C001D9362 /* R.swift */ = {
328 | isa = PBXShellScriptBuildPhase;
329 | buildActionMask = 2147483647;
330 | files = (
331 | );
332 | inputPaths = (
333 | "$TEMP_DIR/rswift-lastrun",
334 | );
335 | name = R.swift;
336 | outputPaths = (
337 | "$SRCROOT/{{cookiecutter.app_name}}/Resources/Generated/R.generated.swift",
338 | );
339 | runOnlyForDeploymentPostprocessing = 0;
340 | shellPath = /bin/sh;
341 | shellScript = "\"$PODS_ROOT/R.swift/rswift\" generate \"$SRCROOT/{{cookiecutter.app_name}}/Resources/Generated/R.generated.swift\"\n";
342 | };
343 | FC9CA61F1F83C1B700B8EB94 /* SwiftLint */ = {
344 | isa = PBXShellScriptBuildPhase;
345 | buildActionMask = 2147483647;
346 | files = (
347 | );
348 | inputPaths = (
349 | );
350 | name = SwiftLint;
351 | outputPaths = (
352 | );
353 | runOnlyForDeploymentPostprocessing = 0;
354 | shellPath = /bin/sh;
355 | shellScript = "${PODS_ROOT}/SwiftLint/swiftlint";
356 | };
357 | /* End PBXShellScriptBuildPhase section */
358 |
359 | /* Begin PBXSourcesBuildPhase section */
360 | 2A1E772F1F384BFC006C84D4 /* Sources */ = {
361 | isa = PBXSourcesBuildPhase;
362 | buildActionMask = 2147483647;
363 | files = (
364 | 2A9222821F38797600A648E6 /* ConfigurationManager.swift in Sources */,
365 | 2ABEE6D61F3886D700531205 /* RootRouter.swift in Sources */,
366 | C90395241FC622D2006F1DC0 /* main.swift in Sources */,
367 | 2A1E77371F384BFC006C84D4 /* AppDelegate.swift in Sources */,
368 | 553FC23C214047CB001D9362 /* R.generated.swift in Sources */,
369 | C90395271FC62425006F1DC0 /* TestsAppDelegate.swift in Sources */,
370 | 2A1DD4E11F389E2100712195 /* NotificationsHandler.swift in Sources */,
371 | 2A1DD4DF1F389C2200712195 /* DeeplinkHandler.swift in Sources */,
372 | );
373 | runOnlyForDeploymentPostprocessing = 0;
374 | };
375 | 2A1E77431F384BFD006C84D4 /* Sources */ = {
376 | isa = PBXSourcesBuildPhase;
377 | buildActionMask = 2147483647;
378 | files = (
379 | C90395261FC62399006F1DC0 /* TestsAppDelegate.swift in Sources */,
380 | );
381 | runOnlyForDeploymentPostprocessing = 0;
382 | };
383 | /* End PBXSourcesBuildPhase section */
384 |
385 | /* Begin PBXTargetDependency section */
386 | 2A1E77491F384BFD006C84D4 /* PBXTargetDependency */ = {
387 | isa = PBXTargetDependency;
388 | target = 2A1E77321F384BFC006C84D4 /* {{cookiecutter.app_name}} */;
389 | targetProxy = 2A1E77481F384BFD006C84D4 /* PBXContainerItemProxy */;
390 | };
391 | /* End PBXTargetDependency section */
392 |
393 | /* Begin PBXVariantGroup section */
394 | 2A1E773F1F384BFD006C84D4 /* LaunchScreen.storyboard */ = {
395 | isa = PBXVariantGroup;
396 | children = (
397 | 2A1E77401F384BFD006C84D4 /* Base */,
398 | );
399 | name = LaunchScreen.storyboard;
400 | sourceTree = "";
401 | };
402 | /* End PBXVariantGroup section */
403 |
404 | /* Begin XCBuildConfiguration section */
405 | 2A1E774E1F384BFD006C84D4 /* Debug */ = {
406 | isa = XCBuildConfiguration;
407 | buildSettings = {
408 | ALWAYS_SEARCH_USER_PATHS = NO;
409 | CLANG_ANALYZER_NONNULL = YES;
410 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
411 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
412 | CLANG_CXX_LIBRARY = "libc++";
413 | CLANG_ENABLE_MODULES = YES;
414 | CLANG_ENABLE_OBJC_ARC = YES;
415 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
416 | CLANG_WARN_BOOL_CONVERSION = YES;
417 | CLANG_WARN_COMMA = YES;
418 | CLANG_WARN_CONSTANT_CONVERSION = YES;
419 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
420 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
421 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
422 | CLANG_WARN_EMPTY_BODY = YES;
423 | CLANG_WARN_ENUM_CONVERSION = YES;
424 | CLANG_WARN_INFINITE_RECURSION = YES;
425 | CLANG_WARN_INT_CONVERSION = YES;
426 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
427 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
428 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
429 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
430 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
431 | CLANG_WARN_STRICT_PROTOTYPES = YES;
432 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
433 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
434 | CLANG_WARN_UNREACHABLE_CODE = YES;
435 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
436 | CODE_SIGN_IDENTITY = "iPhone Developer";
437 | COPY_PHASE_STRIP = NO;
438 | DEBUG_INFORMATION_FORMAT = dwarf;
439 | ENABLE_STRICT_OBJC_MSGSEND = YES;
440 | ENABLE_TESTABILITY = YES;
441 | GCC_C_LANGUAGE_STANDARD = gnu11;
442 | GCC_DYNAMIC_NO_PIC = NO;
443 | GCC_NO_COMMON_BLOCKS = YES;
444 | GCC_OPTIMIZATION_LEVEL = 0;
445 | GCC_PREPROCESSOR_DEFINITIONS = (
446 | "DEBUG=1",
447 | "$(inherited)",
448 | );
449 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
450 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
451 | GCC_WARN_UNDECLARED_SELECTOR = YES;
452 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
453 | GCC_WARN_UNUSED_FUNCTION = YES;
454 | GCC_WARN_UNUSED_VARIABLE = YES;
455 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
456 | MTL_ENABLE_DEBUG_INFO = YES;
457 | ONLY_ACTIVE_ARCH = YES;
458 | SDKROOT = iphoneos;
459 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
460 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
461 | SWIFT_VERSION = 5.0;
462 | };
463 | name = Debug;
464 | };
465 | 2A1E774F1F384BFD006C84D4 /* Release */ = {
466 | isa = XCBuildConfiguration;
467 | buildSettings = {
468 | ALWAYS_SEARCH_USER_PATHS = NO;
469 | CLANG_ANALYZER_NONNULL = YES;
470 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
471 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
472 | CLANG_CXX_LIBRARY = "libc++";
473 | CLANG_ENABLE_MODULES = YES;
474 | CLANG_ENABLE_OBJC_ARC = YES;
475 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
476 | CLANG_WARN_BOOL_CONVERSION = YES;
477 | CLANG_WARN_COMMA = YES;
478 | CLANG_WARN_CONSTANT_CONVERSION = YES;
479 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
480 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
481 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
482 | CLANG_WARN_EMPTY_BODY = YES;
483 | CLANG_WARN_ENUM_CONVERSION = YES;
484 | CLANG_WARN_INFINITE_RECURSION = YES;
485 | CLANG_WARN_INT_CONVERSION = YES;
486 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
487 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
488 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
489 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
490 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
491 | CLANG_WARN_STRICT_PROTOTYPES = YES;
492 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
493 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
494 | CLANG_WARN_UNREACHABLE_CODE = YES;
495 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
496 | CODE_SIGN_IDENTITY = "iPhone Developer";
497 | COPY_PHASE_STRIP = NO;
498 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
499 | ENABLE_NS_ASSERTIONS = NO;
500 | ENABLE_STRICT_OBJC_MSGSEND = YES;
501 | GCC_C_LANGUAGE_STANDARD = gnu11;
502 | GCC_NO_COMMON_BLOCKS = YES;
503 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
504 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
505 | GCC_WARN_UNDECLARED_SELECTOR = YES;
506 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
507 | GCC_WARN_UNUSED_FUNCTION = YES;
508 | GCC_WARN_UNUSED_VARIABLE = YES;
509 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
510 | MTL_ENABLE_DEBUG_INFO = NO;
511 | SDKROOT = iphoneos;
512 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
513 | SWIFT_VERSION = 5.0;
514 | VALIDATE_PRODUCT = YES;
515 | };
516 | name = Release;
517 | };
518 | 2A1E77511F384BFD006C84D4 /* Debug */ = {
519 | isa = XCBuildConfiguration;
520 | buildSettings = {
521 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
522 | INFOPLIST_FILE = "{{cookiecutter.app_name}}/SupportingFiles/Info.plist";
523 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
524 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
525 | OTHER_SWIFT_FLAGS = "$(inherited) -Xfrontend -warn-long-expression-type-checking=500";
526 | PRODUCT_BUNDLE_IDENTIFIER = your.bundle.id;
527 | PRODUCT_NAME = "$(TARGET_NAME)";
528 | SWIFT_VERSION = 5.0;
529 | TARGETED_DEVICE_FAMILY = "1,2";
530 | };
531 | name = Debug;
532 | };
533 | 2A1E77521F384BFD006C84D4 /* Release */ = {
534 | isa = XCBuildConfiguration;
535 | buildSettings = {
536 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
537 | INFOPLIST_FILE = "{{cookiecutter.app_name}}/SupportingFiles/Info.plist";
538 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
539 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
540 | OTHER_SWIFT_FLAGS = "$(inherited)";
541 | PRODUCT_BUNDLE_IDENTIFIER = your.bundle.id;
542 | PRODUCT_NAME = "$(TARGET_NAME)";
543 | SWIFT_VERSION = 5.0;
544 | TARGETED_DEVICE_FAMILY = "1,2";
545 | };
546 | name = Release;
547 | };
548 | 2A1E77541F384BFD006C84D4 /* Debug */ = {
549 | isa = XCBuildConfiguration;
550 | buildSettings = {
551 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
552 | BUNDLE_LOADER = "$(TEST_HOST)";
553 | CLANG_ENABLE_MODULES = YES;
554 | INFOPLIST_FILE = "{{cookiecutter.app_name}}Tests/Info.plist";
555 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
556 | PRODUCT_BUNDLE_IDENTIFIER = "";
557 | PRODUCT_NAME = "$(TARGET_NAME)";
558 | SWIFT_OBJC_BRIDGING_HEADER = "{{cookiecutter.app_name}}Tests/{{cookiecutter.app_name}}Tests-Bridging-Header.h";
559 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
560 | SWIFT_VERSION = 5.0;
561 | TARGETED_DEVICE_FAMILY = "1,2";
562 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/{{cookiecutter.app_name}}.app/{{cookiecutter.app_name}}";
563 | };
564 | name = Debug;
565 | };
566 | 2A1E77551F384BFD006C84D4 /* Release */ = {
567 | isa = XCBuildConfiguration;
568 | buildSettings = {
569 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
570 | BUNDLE_LOADER = "$(TEST_HOST)";
571 | CLANG_ENABLE_MODULES = YES;
572 | INFOPLIST_FILE = "{{cookiecutter.app_name}}Tests/Info.plist";
573 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
574 | PRODUCT_BUNDLE_IDENTIFIER = "";
575 | PRODUCT_NAME = "$(TARGET_NAME)";
576 | SWIFT_OBJC_BRIDGING_HEADER = "{{cookiecutter.app_name}}Tests/{{cookiecutter.app_name}}Tests-Bridging-Header.h";
577 | SWIFT_VERSION = 5.0;
578 | TARGETED_DEVICE_FAMILY = "1,2";
579 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/{{cookiecutter.app_name}}.app/{{cookiecutter.app_name}}";
580 | };
581 | name = Release;
582 | };
583 | 2ABEE6CF1F387C5D00531205 /* Staging */ = {
584 | isa = XCBuildConfiguration;
585 | buildSettings = {
586 | ALWAYS_SEARCH_USER_PATHS = NO;
587 | CLANG_ANALYZER_NONNULL = YES;
588 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
589 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
590 | CLANG_CXX_LIBRARY = "libc++";
591 | CLANG_ENABLE_MODULES = YES;
592 | CLANG_ENABLE_OBJC_ARC = YES;
593 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
594 | CLANG_WARN_BOOL_CONVERSION = YES;
595 | CLANG_WARN_COMMA = YES;
596 | CLANG_WARN_CONSTANT_CONVERSION = YES;
597 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
598 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
599 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
600 | CLANG_WARN_EMPTY_BODY = YES;
601 | CLANG_WARN_ENUM_CONVERSION = YES;
602 | CLANG_WARN_INFINITE_RECURSION = YES;
603 | CLANG_WARN_INT_CONVERSION = YES;
604 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
605 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
606 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
607 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
608 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
609 | CLANG_WARN_STRICT_PROTOTYPES = YES;
610 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
611 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
612 | CLANG_WARN_UNREACHABLE_CODE = YES;
613 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
614 | CODE_SIGN_IDENTITY = "iPhone Developer";
615 | COPY_PHASE_STRIP = NO;
616 | DEBUG_INFORMATION_FORMAT = dwarf;
617 | ENABLE_STRICT_OBJC_MSGSEND = YES;
618 | ENABLE_TESTABILITY = YES;
619 | GCC_C_LANGUAGE_STANDARD = gnu11;
620 | GCC_DYNAMIC_NO_PIC = NO;
621 | GCC_NO_COMMON_BLOCKS = YES;
622 | GCC_OPTIMIZATION_LEVEL = 0;
623 | GCC_PREPROCESSOR_DEFINITIONS = (
624 | "DEBUG=1",
625 | "$(inherited)",
626 | );
627 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
628 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
629 | GCC_WARN_UNDECLARED_SELECTOR = YES;
630 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
631 | GCC_WARN_UNUSED_FUNCTION = YES;
632 | GCC_WARN_UNUSED_VARIABLE = YES;
633 | IPHONEOS_DEPLOYMENT_TARGET = 11.0;
634 | MTL_ENABLE_DEBUG_INFO = YES;
635 | ONLY_ACTIVE_ARCH = YES;
636 | SDKROOT = iphoneos;
637 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
638 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
639 | SWIFT_VERSION = 5.0;
640 | };
641 | name = Staging;
642 | };
643 | 2ABEE6D01F387C5D00531205 /* Staging */ = {
644 | isa = XCBuildConfiguration;
645 | buildSettings = {
646 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
647 | INFOPLIST_FILE = "{{cookiecutter.app_name}}/SupportingFiles/Info.plist";
648 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
649 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
650 | OTHER_SWIFT_FLAGS = "$(inherited)";
651 | PRODUCT_BUNDLE_IDENTIFIER = your.bundle.id;
652 | PRODUCT_NAME = "$(TARGET_NAME)";
653 | SWIFT_VERSION = 5.0;
654 | TARGETED_DEVICE_FAMILY = "1,2";
655 | };
656 | name = Staging;
657 | };
658 | 2ABEE6D11F387C5D00531205 /* Staging */ = {
659 | isa = XCBuildConfiguration;
660 | buildSettings = {
661 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
662 | BUNDLE_LOADER = "$(TEST_HOST)";
663 | CLANG_ENABLE_MODULES = YES;
664 | INFOPLIST_FILE = "{{cookiecutter.app_name}}Tests/Info.plist";
665 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
666 | PRODUCT_BUNDLE_IDENTIFIER = "";
667 | PRODUCT_NAME = "$(TARGET_NAME)";
668 | SWIFT_OBJC_BRIDGING_HEADER = "{{cookiecutter.app_name}}Tests/{{cookiecutter.app_name}}Tests-Bridging-Header.h";
669 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
670 | SWIFT_VERSION = 5.0;
671 | TARGETED_DEVICE_FAMILY = "1,2";
672 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/{{cookiecutter.app_name}}.app/{{cookiecutter.app_name}}";
673 | };
674 | name = Staging;
675 | };
676 | /* End XCBuildConfiguration section */
677 |
678 | /* Begin XCConfigurationList section */
679 | 2A1E772E1F384BFC006C84D4 /* Build configuration list for PBXProject "{{cookiecutter.app_name}}" */ = {
680 | isa = XCConfigurationList;
681 | buildConfigurations = (
682 | 2A1E774E1F384BFD006C84D4 /* Debug */,
683 | 2ABEE6CF1F387C5D00531205 /* Staging */,
684 | 2A1E774F1F384BFD006C84D4 /* Release */,
685 | );
686 | defaultConfigurationIsVisible = 0;
687 | defaultConfigurationName = Release;
688 | };
689 | 2A1E77501F384BFD006C84D4 /* Build configuration list for PBXNativeTarget "{{cookiecutter.app_name}}" */ = {
690 | isa = XCConfigurationList;
691 | buildConfigurations = (
692 | 2A1E77511F384BFD006C84D4 /* Debug */,
693 | 2ABEE6D01F387C5D00531205 /* Staging */,
694 | 2A1E77521F384BFD006C84D4 /* Release */,
695 | );
696 | defaultConfigurationIsVisible = 0;
697 | defaultConfigurationName = Release;
698 | };
699 | 2A1E77531F384BFD006C84D4 /* Build configuration list for PBXNativeTarget "{{cookiecutter.app_name}}Tests" */ = {
700 | isa = XCConfigurationList;
701 | buildConfigurations = (
702 | 2A1E77541F384BFD006C84D4 /* Debug */,
703 | 2ABEE6D11F387C5D00531205 /* Staging */,
704 | 2A1E77551F384BFD006C84D4 /* Release */,
705 | );
706 | defaultConfigurationIsVisible = 0;
707 | defaultConfigurationName = Release;
708 | };
709 | /* End XCConfigurationList section */
710 | };
711 | rootObject = 2A1E772B1F384BFC006C84D4 /* Project object */;
712 | }
713 |
--------------------------------------------------------------------------------