├── {{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 | --------------------------------------------------------------------------------