├── .gitignore ├── README.md ├── ambient-xcode.gemspec ├── bin └── ambient ├── example ├── Ambientfile ├── Ambientfile-objc ├── Ambientfile-verbose └── images │ └── Constant.png ├── lib ├── ambient.rb └── ambient │ ├── application.rb │ ├── capabilities_helper.rb │ ├── dsl.rb │ ├── dsl │ ├── main_scope.rb │ ├── plist_scope.rb │ ├── scheme_scope.rb │ └── target_scope.rb │ ├── init.rb │ ├── plist_helper.rb │ ├── project_creation.rb │ └── project_helper.rb └── templates └── ios ├── PRODUCTNAME.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata └── PRODUCTNAME ├── AppDelegate.swift ├── Assets.xcassets └── AppIcon.appiconset │ └── Contents.json ├── Base.lproj ├── LaunchScreen.storyboard └── Main.storyboard ├── Info.plist └── ViewController.swift /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | tags 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > [!WARNING] 2 | > You shouldn't use this, it's not maintained and probably doesn't work with latest versions of things. Looks like maybe https://github.com/yonaskolb/XcodeGen might be similar 3 | 4 | Ambient environment for Xcode projects 5 | ====================================== 6 | 7 | Ambient lets you define all of your Xcode project environment settings all in one easy to read Ruby file, and re-apply it to your Xcode project to ensure settings are correct. 8 | 9 | An `xcconfig` file can be used in order to help abstract your settings away from the main project file. The disadvantage of `xcconfig` files though is that they can still be overridden by settings defined in the project. Ambient doesn't have this issue as it simply overwrites the values in the project file. 10 | 11 | 12 | Installation 13 | ============ 14 | 15 | Simply run: 16 | ```bash 17 | gem install ambient-xcode 18 | ``` 19 | 20 | Or if you use Bundler, add the following to your `Gemfile`: 21 | ```ruby 22 | gem "ambient-xcode" 23 | ``` 24 | 25 | Usage 26 | ===== 27 | 28 | Create an `Ambientfile` defining your project in the same directory as your `*.xcodeproj` file. 29 | 30 | Here's a sample of the `Ambientfile` structure: 31 | ```ruby 32 | base_ios_settings! "MyProject" 33 | 34 | target "MyProject" do 35 | capability :healthkit 36 | capability :apple_pay 37 | 38 | scheme "Debug" do 39 | option "PRODUCT_NAME", "Debug" 40 | option "BUNDLE_DISPLAY_NAME_SUFFIX", "uk.danielgreen.MyProject" 41 | end 42 | end 43 | 44 | plist("MyProject/Info.plist") do 45 | entry "LSApplicationQueriesSchemes", [ "dbapi-2", "dbapi-8-emm"] 46 | end 47 | ``` 48 | 49 | Run `ambient` from the command line to write your settings into your project: 50 | ``` 51 | usage: 52 | $ ambient COMMAND 53 | 54 | Commands: 55 | + [no arguments] Applies the settings from the Ambientfile 56 | + init Creates an Ambientfile in the current directory 57 | + new NAME Creates a new iOS Xcode project with given name 58 | + [anything else] Applies the settings from the file name supplied 59 | ``` 60 | 61 | You can also have more than one `Ambientfile` for the same project. Just name it something else and run `ambient [filename]` (e.g. `ambient Ambientfile-enterprise`). Use `use_settings_from` to inherit settings: 62 | 63 | ```ruby 64 | use_settings_from 'Ambientfile' 65 | 66 | target "Monies" do 67 | development_team "341MONEY25" 68 | capability :apple_pay 69 | end 70 | ``` 71 | 72 | 73 | Notes 74 | ===== 75 | 76 | - The [example Ambientfile](https://github.com/Dan2552/ambient-xcode/blob/master/example/Ambientfile) or [example Ambientfile-objc](https://github.com/Dan2552/ambient-xcode/blob/master/example/Ambientfile-objc) matches the exact settings of a new iOS project. 77 | - Use the `use_defaults_for_everything_not_specified_in_this_file!` setting to ensure your project file is clean. Warning though: this setting will clear all your targets' settings, so be sure to define absolutely every setting in the `Ambientfile` if you want to use this. 78 | - When defining settings directly within a target, the setting is set to each scheme. 79 | - The name of the constants used for `option` is located in the **Quick Help** section in Xcode 80 | ![Constants](example/images/Constant.png) 81 | 82 | Possible future features 83 | ======================== 84 | 85 | - Automatic editing of `.entitlements` 86 | - Helper method to change build phases to default 87 | - Version number + build number 88 | - Provisioning profiles from searching by name rather than storing a uuid (so it actually works across teams) 89 | - Ability to not have to commit `*.xcodeproj` into version control (maybe too far?) 90 | -------------------------------------------------------------------------------- /ambient-xcode.gemspec: -------------------------------------------------------------------------------- 1 | lib = File.expand_path('../lib', __FILE__) 2 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 3 | 4 | Gem::Specification.new do |gem| 5 | gem.name = 'ambient-xcode' 6 | gem.version = '0.8.1' 7 | gem.authors = ['Daniel Inkpen'] 8 | gem.email = ['dan2552@gmail.com'] 9 | gem.description = %q{CLI for configuring Xcode projects from a Ruby file.} 10 | gem.summary = %q{Define your environment settings all in one easy to read Ruby file.} 11 | gem.homepage = 'https://github.com/Dan2552/ambient' 12 | gem.license = 'MIT' 13 | 14 | gem.add_dependency 'xcodeproj', '~> 1.5', '>= 1.5.0' 15 | gem.add_dependency 'plist', '~> 3.2', '>= 3.2.0' 16 | 17 | gem.files = `git ls-files`.split($/) 18 | gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) } 19 | gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) 20 | gem.require_paths = ['lib'] 21 | end 22 | -------------------------------------------------------------------------------- /bin/ambient: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'fileutils' 3 | 4 | $:.push File.expand_path("../../lib", __FILE__) 5 | 6 | require 'ambient' 7 | 8 | def print_help 9 | print_version 10 | puts "" 11 | puts "usage: " 12 | puts "$ ambient COMMAND" 13 | puts "" 14 | puts "Commands:" 15 | puts "+ [no arguments]\tApplies the settings from the Ambientfile" 16 | puts "+ init\t\t\tCreates an Ambientfile in the current directory" 17 | puts "+ new NAME\t\tCreates a new iOS Xcode project with given name" 18 | puts "+ [anything else]\tApplies the settings from the file name supplied" 19 | end 20 | 21 | def print_version 22 | path = File.expand_path("../../", __FILE__) 23 | gem_contents = File.read("#{path}/ambient-xcode.gemspec") 24 | match = gem_contents.match /^\s*gem.version\s*= ('|")(.*)('|")/ 25 | puts "ambient-xcode #{match[2]}" 26 | end 27 | 28 | if ARGV[0] == "init" 29 | Ambient::Init.new.create_ambientfile 30 | elsif ARGV[0] == "new" 31 | Ambient::ProjectCreation.new(Dir.pwd, ARGV[1]).create_ios_project 32 | elsif ARGV[0] == "help" || ARGV[0] == "--help" 33 | print_help 34 | elsif ARGV[0] == "version" || ARGV[0] == "--version" || ARGV[0] == "-v" 35 | print_version 36 | else 37 | Ambient::Application.new.run_ambientfile(ARGV[0]) 38 | end 39 | -------------------------------------------------------------------------------- /example/Ambientfile: -------------------------------------------------------------------------------- 1 | PROJECT = "MyProject" 2 | PREFIX = "com.organization." 3 | 4 | base_ios_settings! PROJECT, 5 | prefix: PREFIX, 6 | tests: true, 7 | ui_tests: true 8 | -------------------------------------------------------------------------------- /example/Ambientfile-objc: -------------------------------------------------------------------------------- 1 | PROJECT = "MyProject" 2 | PREFIX = "com.organization." 3 | 4 | base_ios_settings! PROJECT, 5 | prefix: PREFIX, 6 | tests: true, 7 | ui_tests: true, 8 | swift: false 9 | -------------------------------------------------------------------------------- /example/Ambientfile-verbose: -------------------------------------------------------------------------------- 1 | use_defaults_for_everything_not_specified_in_this_file! 2 | enable_default_warnings! 3 | 4 | option "ALWAYS_SEARCH_USER_PATHS", false 5 | option "CLANG_CXX_LANGUAGE_STANDARD", "gnu++0x" 6 | option "CLANG_CXX_LIBRARY", "libc++" 7 | option "CLANG_ENABLE_MODULES", true 8 | option "CLANG_ENABLE_OBJC_ARC", true 9 | 10 | option "CODE_SIGN_IDENTITY[sdk=iphoneos*]", "iPhone Developer" 11 | option "COPY_PHASE_STRIP", false 12 | 13 | option "ENABLE_STRICT_OBJC_MSGSEND", true 14 | option "GCC_C_LANGUAGE_STANDARD", "gnu99" 15 | option "GCC_NO_COMMON_BLOCKS", true 16 | option "SDKROOT", "iphoneos" 17 | option "IPHONEOS_DEPLOYMENT_TARGET", "9.0" 18 | 19 | scheme "Debug" do 20 | option "DEBUG_INFORMATION_FORMAT", "dwarf" 21 | option "ENABLE_TESTABILITY", true 22 | option "MTL_ENABLE_DEBUG_INFO", true 23 | option "ONLY_ACTIVE_ARCH", true 24 | option "GCC_DYNAMIC_NO_PIC", false 25 | option "GCC_OPTIMIZATION_LEVEL", "0" 26 | option "GCC_PREPROCESSOR_DEFINITIONS", ["DEBUG=1", "$(inherited)"] 27 | option "SWIFT_OPTIMIZATION_LEVEL", "-Onone" 28 | end 29 | 30 | scheme "Release" do 31 | option "DEBUG_INFORMATION_FORMAT", "dwarf-with-dsym" 32 | option "ENABLE_NS_ASSERTIONS", false 33 | option "MTL_ENABLE_DEBUG_INFO", false 34 | option "VALIDATE_PRODUCT", true 35 | end 36 | 37 | target "#{PROJECT}" do 38 | option "INFOPLIST_FILE", "#{PROJECT}/Info.plist" 39 | option "PRODUCT_BUNDLE_IDENTIFIER", "#{PREFIX}#{PROJECT}" 40 | option "ASSETCATALOG_COMPILER_APPICON_NAME", "AppIcon" 41 | option "LD_RUNPATH_SEARCH_PATHS", "$(inherited) @executable_path/Frameworks" 42 | option "PRODUCT_NAME", "$(TARGET_NAME)" 43 | end 44 | 45 | target "#{PROJECT}Tests" do 46 | option "INFOPLIST_FILE", "#{PROJECT}Tests/Info.plist" 47 | option "BUNDLE_LOADER", "$(TEST_HOST)" 48 | option "TEST_HOST", "$(BUILT_PRODUCTS_DIR)/#{PROJECT}.app/#{PROJECT}" 49 | option "PRODUCT_BUNDLE_IDENTIFIER", "#{PREFIX}#{PROJECT}Tests" 50 | option "LD_RUNPATH_SEARCH_PATHS", "$(inherited) @executable_path/Frameworks @loader_path/Frameworks" 51 | option "PRODUCT_NAME", "$(TARGET_NAME)" 52 | end 53 | 54 | target "#{PROJECT}UITests" do 55 | option "INFOPLIST_FILE", "#{PROJECT}UITests/Info.plist" 56 | option "TEST_TARGET_NAME", "#{PROJECT}" 57 | option "PRODUCT_BUNDLE_IDENTIFIER", "#{PREFIX}#{PROJECT}UITests" 58 | option "LD_RUNPATH_SEARCH_PATHS", "$(inherited) @executable_path/Frameworks @loader_path/Frameworks" 59 | option "USES_XCTRUNNER", "YES" 60 | option "PRODUCT_NAME", "$(TARGET_NAME)" 61 | end 62 | -------------------------------------------------------------------------------- /example/images/Constant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Dan2552/ambient-xcode/d1ff1f56a4a53f41b8787d9a36ce4fcaa3089cf4/example/images/Constant.png -------------------------------------------------------------------------------- /lib/ambient.rb: -------------------------------------------------------------------------------- 1 | require 'xcodeproj' 2 | require 'plist' 3 | 4 | require_relative 'ambient/project_helper' 5 | require_relative 'ambient/capabilities_helper' 6 | require_relative 'ambient/plist_helper' 7 | require_relative 'ambient/dsl' 8 | require_relative 'ambient/project_creation' 9 | require_relative 'ambient/init' 10 | require_relative 'ambient/application' 11 | -------------------------------------------------------------------------------- /lib/ambient/application.rb: -------------------------------------------------------------------------------- 1 | module Ambient 2 | class Application 3 | attr_reader :path 4 | 5 | def initialize(path = nil) 6 | @path = path || Dir.pwd 7 | 8 | @use_defaults = false 9 | @project_options = {} 10 | @shared_target_options = {} 11 | @target_options = {} 12 | @scheme_options = {} 13 | @parents = {} 14 | @capabilities = {} 15 | @development_teams = {} 16 | end 17 | 18 | def run_ambientfile(file = nil) 19 | setup_project(file || "Ambientfile") 20 | end 21 | 22 | def configure(&block) 23 | instance_eval(&block) 24 | end 25 | 26 | private 27 | 28 | def project_helper 29 | @project_helper ||= ProjectHelper.new(path) 30 | end 31 | 32 | def set_parent_scheme(target: nil, child: nil, parent: nil) 33 | target = target || :all 34 | @parents[target] ||= {} 35 | @parents[target][child] = parent 36 | end 37 | 38 | def set_option(option, value, target: nil, scheme: nil, parent: nil) 39 | value = "YES" if value == true 40 | value = "NO" if value == false 41 | value = nil if value == :default 42 | 43 | if target 44 | if scheme 45 | @target_options[target] ||= {} 46 | @target_options[target][scheme] ||= {} 47 | @target_options[target][scheme][option] = value 48 | else 49 | @shared_target_options[target] ||= {} 50 | @shared_target_options[target][option] = value 51 | end 52 | else 53 | if scheme 54 | @scheme_options[scheme] ||= {} 55 | @scheme_options[scheme][option] = value 56 | else 57 | @project_options[option] = value 58 | end 59 | end 60 | end 61 | 62 | def set_capability(target_name, capability_name) 63 | capabilities = @capabilities[target_name] ||= [] 64 | capabilities << capability_name 65 | end 66 | 67 | def set_development_team(target_name, team_name) 68 | @development_teams[target_name] = team_name 69 | end 70 | 71 | def setup_project(ambientfile) 72 | read(ambientfile) 73 | project_helper.print_info 74 | reset_project_to_defaults if @use_defaults 75 | reset_targets_to_defaults if @use_defaults 76 | reset_capabilites_to_defaults if @use_defaults 77 | load_in_parent_scheme_values 78 | process_project_options 79 | process_scheme_options 80 | process_shared_target_options 81 | process_target_options 82 | process_capabilities 83 | process_development_teams 84 | project_helper.save_changes 85 | end 86 | 87 | def reset_project_to_defaults 88 | puts "resetting project settings to xcode default settings" 89 | project_helper.reset_project_to_defaults 90 | end 91 | 92 | def reset_targets_to_defaults 93 | puts "resetting target settings to xcode default settings" 94 | project_helper.reset_targets_to_defaults 95 | end 96 | 97 | def reset_capabilites_to_defaults 98 | puts "resetting capabilities to xcode default settings" 99 | project_helper.reset_capabilities_to_defaults 100 | end 101 | 102 | def process_project_options 103 | puts "applying ambient project settings" 104 | project_helper.process_project_options(@project_options) 105 | end 106 | 107 | def process_scheme_options 108 | puts "applying ambient scheme settings" 109 | project_helper.process_scheme_options(@scheme_options) 110 | end 111 | 112 | def process_shared_target_options 113 | puts "applying ambient shared target settings" 114 | project_helper.process_shared_target_options(@shared_target_options) 115 | end 116 | 117 | def process_target_options 118 | puts "applying ambient target settings" 119 | project_helper.process_target_options(@target_options) 120 | end 121 | 122 | def process_capabilities 123 | puts "applying ambient capabilities" 124 | project_helper.process_capabilities(@capabilities) 125 | end 126 | 127 | def process_development_teams 128 | puts "applying ambient development teams" 129 | project_helper.process_development_teams(@development_teams) 130 | end 131 | 132 | def load_in_parent_scheme_values 133 | @parents.each do |target, parents| 134 | parents.each do |child, parent| 135 | if parent 136 | if target == :all 137 | puts "Identified #{child} as a child of #{parent}" 138 | child_options = @scheme_options[child] 139 | parent_options = @scheme_options[parent] 140 | else 141 | target_options = @target_options[target] 142 | child_options = target_options[child] 143 | parent_options = target_options[parent] 144 | end 145 | child_options.merge!(parent_options) { |_, child, _| child } 146 | end 147 | end 148 | end 149 | end 150 | 151 | def read(filename) 152 | puts "# Reading settings from #{filename}" 153 | ambient = File.join(path, filename) 154 | 155 | unless File.exists?(ambient) 156 | puts "😱 #{filename} not found in current directory." 157 | exit 1 158 | end 159 | 160 | DSL::MainScope.new(self).instance_eval do 161 | eval(File.read(ambient)) 162 | end 163 | end 164 | end 165 | end 166 | -------------------------------------------------------------------------------- /lib/ambient/capabilities_helper.rb: -------------------------------------------------------------------------------- 1 | module Ambient 2 | class CapabilitiesHelper 3 | CAPABILITIES = { 4 | application_group_ios: "ApplicationGroups.iOS", 5 | background_modes: "BackgroundModes", 6 | data_protection: "DataProtection", 7 | game_center: "GameCenter", 8 | healthkit: "HealthKit", 9 | health_kit: "HealthKit", 10 | homekit: "HomeKit", 11 | home_kit: "HomeKit", 12 | in_app_purchase: "InAppPurchase", 13 | inter_app_audio: "InterAppAudio", 14 | keychain: "Keychain", 15 | maps: "Maps.iOS", 16 | apple_pay: "OMC", 17 | passbook: "Passbook", 18 | wallet: "Passbook", 19 | safari_keychain: "SafariKeychain", 20 | personal_vpn: "VPNLite", 21 | wireless_accessory_configuration: "WAC", 22 | icloud: "iCloud" 23 | } 24 | 25 | def initialize(project, target) 26 | @project = project 27 | @target = target 28 | end 29 | 30 | def clear_capabilities 31 | capabilities.delete_if { |_, _| true } if capabilities 32 | end 33 | 34 | def enable_capability(capability) 35 | capabilities[capability_key(capability)] = {"enabled"=>"1"} 36 | end 37 | 38 | def disable_capability(capability) 39 | capabilities.delete(capability_key(capability)) 40 | end 41 | 42 | def set_development_team(team) 43 | target_attributes["DevelopmentTeam"] = team 44 | end 45 | 46 | private 47 | 48 | def capabilities 49 | target_attributes["SystemCapabilities"] 50 | end 51 | 52 | def target_attributes 53 | unless @project.root_object.attributes["TargetAttributes"] 54 | @project.root_object.attributes["TargetAttributes"] = {} 55 | end 56 | 57 | unless @project.root_object.attributes["TargetAttributes"][@target.uuid] 58 | @project.root_object.attributes["TargetAttributes"][@target.uuid] = {} 59 | end 60 | 61 | @project.root_object.attributes["TargetAttributes"][@target.uuid] 62 | end 63 | 64 | def capability_key(capability) 65 | capability = CAPABILITIES[capability] || capability.to_s 66 | prefix = "com.apple." 67 | capability = "#{prefix}#{capability}" unless capability.start_with? prefix 68 | capability 69 | end 70 | end 71 | end 72 | -------------------------------------------------------------------------------- /lib/ambient/dsl.rb: -------------------------------------------------------------------------------- 1 | require_relative 'dsl/main_scope' 2 | require_relative 'dsl/plist_scope' 3 | require_relative 'dsl/scheme_scope' 4 | require_relative 'dsl/target_scope' 5 | -------------------------------------------------------------------------------- /lib/ambient/dsl/main_scope.rb: -------------------------------------------------------------------------------- 1 | module Ambient 2 | module DSL 3 | class MainScope 4 | attr_reader :application 5 | 6 | def initialize(application) 7 | @application = application 8 | end 9 | 10 | def use_settings_from(filename) 11 | application.configure { run_ambientfile(filename) } 12 | end 13 | 14 | def option(name, value) 15 | application.configure { set_option(name, value) } 16 | end 17 | 18 | def base_ios_settings!(project_name, prefix: "", tests: false, ui_tests: false, swift: true, target: nil, test_target: nil, ui_test_target: nil) 19 | use_defaults_for_everything_not_specified_in_this_file! 20 | enable_default_warnings! 21 | 22 | target ||= "project_name" 23 | test_target ||= "#{project_name}Tests" 24 | ui_test_target ||= "#{project_name}UITests" 25 | tests = true if test_target 26 | ui_tests = true if ui_test_target 27 | 28 | option "ALWAYS_SEARCH_USER_PATHS", false 29 | option "CLANG_CXX_LANGUAGE_STANDARD", "gnu++14" 30 | option "CLANG_CXX_LIBRARY", "libc++" 31 | option "CLANG_ENABLE_MODULES", true 32 | option "CLANG_ENABLE_OBJC_ARC", true 33 | 34 | option "CODE_SIGN_IDENTITY", "iPhone Developer" 35 | option "COPY_PHASE_STRIP", false 36 | 37 | option "ENABLE_STRICT_OBJC_MSGSEND", true 38 | option "GCC_C_LANGUAGE_STANDARD", "gnu11" 39 | option "GCC_NO_COMMON_BLOCKS", true 40 | option "SDKROOT", "iphoneos" 41 | option "IPHONEOS_DEPLOYMENT_TARGET", "10.0" 42 | option "SWIFT_VERSION", "3.0" 43 | 44 | scheme "Debug" do 45 | option "DEBUG_INFORMATION_FORMAT", "dwarf" 46 | option "ENABLE_TESTABILITY", true 47 | option "MTL_ENABLE_DEBUG_INFO", true 48 | option "ONLY_ACTIVE_ARCH", true 49 | option "GCC_DYNAMIC_NO_PIC", false 50 | option "GCC_OPTIMIZATION_LEVEL", "0" 51 | option "GCC_PREPROCESSOR_DEFINITIONS", ["DEBUG=1", "$(inherited)"] 52 | option "SWIFT_OPTIMIZATION_LEVEL", "-Onone" if swift 53 | option "SWIFT_ACTIVE_COMPILATION_CONDITIONS", "DEBUG" 54 | end 55 | 56 | scheme "Release" do 57 | option "DEBUG_INFORMATION_FORMAT", "dwarf-with-dsym" 58 | option "ENABLE_NS_ASSERTIONS", false 59 | option "MTL_ENABLE_DEBUG_INFO", false 60 | option "VALIDATE_PRODUCT", true 61 | option "SWIFT_OPTIMIZATION_LEVEL", "-Owholemodule" 62 | end 63 | 64 | target project_name do 65 | option "INFOPLIST_FILE", "#{project_name}/Info.plist" 66 | option "PRODUCT_BUNDLE_IDENTIFIER", "#{prefix}#{project_name}" 67 | option "ASSETCATALOG_COMPILER_APPICON_NAME", "AppIcon" 68 | option "LD_RUNPATH_SEARCH_PATHS", "$(inherited) @executable_path/Frameworks" 69 | option "PRODUCT_NAME", "$(TARGET_NAME)" 70 | end 71 | 72 | if tests 73 | target test_target do 74 | option "INFOPLIST_FILE", "#{project_name}Tests/Info.plist" 75 | option "BUNDLE_LOADER", "$(TEST_HOST)" 76 | option "TEST_HOST", "$(BUILT_PRODUCTS_DIR)/#{project_name}.app/#{project_name}" 77 | option "PRODUCT_BUNDLE_IDENTIFIER", "#{prefix}#{project_name}Tests" 78 | option "LD_RUNPATH_SEARCH_PATHS", "$(inherited) @executable_path/Frameworks @loader_path/Frameworks" 79 | option "PRODUCT_NAME", "$(TARGET_NAME)" 80 | end 81 | end 82 | 83 | if ui_tests 84 | target ui_test_target do 85 | option "INFOPLIST_FILE", "#{project_name}UITests/Info.plist" 86 | option "TEST_TARGET_NAME", "#{project_name}" 87 | option "PRODUCT_BUNDLE_IDENTIFIER", "#{prefix}#{project_name}UITests" 88 | option "LD_RUNPATH_SEARCH_PATHS", "$(inherited) @executable_path/Frameworks @loader_path/Frameworks" 89 | option "USES_XCTRUNNER", "YES" 90 | option "PRODUCT_NAME", "$(TARGET_NAME)" 91 | end 92 | end 93 | end 94 | 95 | def enable_extra_warnings_and_static_analyser! 96 | warnings = %w(GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED 97 | GCC_WARN_MISSING_PARENTHESES 98 | GCC_WARN_ABOUT_RETURN_TYPE 99 | GCC_WARN_SIGN_COMPARE 100 | GCC_WARN_CHECK_SWITCH_STATEMENTS 101 | GCC_WARN_UNUSED_FUNCTION 102 | GCC_WARN_UNUSED_LABEL 103 | GCC_WARN_UNUSED_VALUE 104 | GCC_WARN_UNUSED_VARIABLE 105 | GCC_WARN_SHADOW 106 | GCC_WARN_64_TO_32_BIT_CONVERSION 107 | GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS 108 | GCC_WARN_UNDECLARED_SELECTOR 109 | GCC_WARN_TYPECHECK_CALLS_TO_PRINTF 110 | GCC_WARN_UNINITIALIZED_AUTOS 111 | CLANG_WARN_INT_CONVERSION 112 | CLANG_WARN_ENUM_CONVERSION 113 | CLANG_WARN_CONSTANT_CONVERSION 114 | CLANG_WARN_BOOL_CONVERSION 115 | CLANG_WARN_EMPTY_BODY 116 | CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION 117 | CLANG_WARN__DUPLICATE_METHOD_MATCH 118 | GCC_WARN_64_TO_32_BIT_CONVERSION 119 | RUN_CLANG_STATIC_ANALYZER 120 | GCC_TREAT_WARNINGS_AS_ERRORS 121 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING 122 | CLANG_WARN_COMMA 123 | CLANG_WARN_DOCUMENTATION_COMMENTS 124 | CLANG_WARN_INFINITE_RECURSION 125 | CLANG_WARN_RANGE_LOOP_ANALYSIS 126 | CLANG_WARN_STRICT_PROTOTYPES 127 | CLANG_WARN_SUSPICIOUS_MOVE) 128 | warnings.each { |w| option(w, true) } 129 | 130 | option "CLANG_WARN_UNGUARDED_AVAILABILITY", "YES_AGGRESSIVE" 131 | end 132 | 133 | def enable_default_warnings! 134 | truthy = %w(CLANG_WARN_BOOL_CONVERSION 135 | CLANG_WARN_CONSTANT_CONVERSION 136 | CLANG_WARN_EMPTY_BODY 137 | CLANG_WARN_ENUM_CONVERSION 138 | CLANG_WARN_INT_CONVERSION 139 | CLANG_WARN_UNREACHABLE_CODE 140 | CLANG_WARN__DUPLICATE_METHOD_MATCH 141 | GCC_WARN_64_TO_32_BIT_CONVERSION 142 | GCC_WARN_UNDECLARED_SELECTOR 143 | GCC_WARN_UNUSED_FUNCTION 144 | GCC_WARN_UNUSED_VARIABLE) 145 | error = %w(CLANG_WARN_DIRECT_OBJC_ISA_USAGE 146 | CLANG_WARN_OBJC_ROOT_CLASS 147 | GCC_WARN_ABOUT_RETURN_TYPE) 148 | aggressive = %w(GCC_WARN_UNINITIALIZED_AUTOS) 149 | 150 | truthy.each { |w| option(w, true) } 151 | error.each { |w| option(w, "YES_ERROR") } 152 | aggressive.each { |w| option(w, "YES_AGGRESSIVE") } 153 | end 154 | 155 | def target(name, &block) 156 | TargetScope.new(application, name).configure(&block) 157 | end 158 | 159 | def use_defaults_for_everything_not_specified_in_this_file! 160 | application.configure { @use_defaults = true } 161 | end 162 | 163 | def scheme(name, parent: nil, &block) 164 | SchemeScope.new(application, nil, name, parent).configure(&block) 165 | end 166 | 167 | def plist(path, &block) 168 | PlistScope.new(application, path).configure(&block) 169 | end 170 | end 171 | end 172 | end 173 | -------------------------------------------------------------------------------- /lib/ambient/dsl/plist_scope.rb: -------------------------------------------------------------------------------- 1 | module Ambient 2 | module DSL 3 | class PlistScope 4 | attr_reader :application, 5 | :helper 6 | 7 | def initialize(application, path) 8 | @application = application 9 | @helper = PlistHelper.new(path) 10 | end 11 | 12 | def configure(&block) 13 | instance_eval(&block) 14 | end 15 | 16 | def entry(key, value) 17 | helper.add_entry(key, value) 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/ambient/dsl/scheme_scope.rb: -------------------------------------------------------------------------------- 1 | module Ambient 2 | module DSL 3 | class SchemeScope 4 | attr_reader :application 5 | 6 | def initialize(application, target, name, parent) 7 | @application = application 8 | @target = target 9 | @name = name 10 | @parent = parent 11 | 12 | application.configure do 13 | set_parent_scheme( 14 | target: target && target.name, 15 | child: name, 16 | parent: parent 17 | ) 18 | end 19 | end 20 | 21 | def configure(&block) 22 | if block 23 | instance_eval(&block) 24 | end 25 | end 26 | 27 | def option(option_name, value) 28 | target = @target 29 | name = @name 30 | parent = @parent 31 | 32 | if target 33 | application.configure { set_option(option_name, value, target: target.name, scheme: name, parent: parent) } 34 | else 35 | application.configure { set_option(option_name, value, scheme: name, parent: parent) } 36 | end 37 | end 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /lib/ambient/dsl/target_scope.rb: -------------------------------------------------------------------------------- 1 | module Ambient 2 | module DSL 3 | class TargetScope 4 | attr_reader :application, 5 | :name 6 | 7 | def initialize(application, name) 8 | @application = application 9 | @name = name 10 | end 11 | 12 | def configure(&block) 13 | instance_eval(&block) 14 | end 15 | 16 | def option(option_name, value) 17 | target_name = @name 18 | application.configure { set_option(option_name, value, target: target_name) } 19 | end 20 | 21 | def scheme(name, parent: nil, &block) 22 | SchemeScope.new(application, self, name, parent).configure(&block) 23 | end 24 | 25 | def capability(capability_name) 26 | target_name = @name 27 | application.configure { set_capability(target_name, capability_name) } 28 | end 29 | 30 | def development_team(team_name) 31 | target_name = @name 32 | application.configure { set_development_team(target_name, team_name) } 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /lib/ambient/init.rb: -------------------------------------------------------------------------------- 1 | module Ambient 2 | class Init 3 | attr_reader :path, 4 | :project_name, 5 | :project_prefix 6 | 7 | def initialize(path = nil, project_name = nil, project_prefix = nil) 8 | @path = path || Dir.pwd 9 | @project_name = project_name || "MyProject" 10 | @project_prefix = project_prefix || "com.#{@project_name.downcase}." 11 | end 12 | 13 | def create_ambientfile 14 | puts "# Creating Ambientfile..." 15 | write_file 16 | puts "File created at #{filepath}" 17 | end 18 | 19 | private 20 | 21 | def write_file 22 | File.open(filepath, 'w') { |file| file.write(contents) } 23 | end 24 | 25 | def filepath 26 | "#{path}/Ambientfile" 27 | end 28 | 29 | def contents 30 | "base_ios_settings! \"#{project_name}\", prefix: \"#{project_prefix}\"\n" 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/ambient/plist_helper.rb: -------------------------------------------------------------------------------- 1 | module Ambient 2 | class PlistHelper 3 | attr_reader :path 4 | 5 | def initialize(path) 6 | @path = path 7 | end 8 | 9 | def add_entry(key, value) 10 | plist_as_dictionary[key] = value 11 | puts "applying to plist: #{path} #{key}" 12 | save 13 | end 14 | 15 | private 16 | 17 | def plist_as_dictionary 18 | @plist_as_dictionary ||= Plist::parse_xml(path) 19 | end 20 | 21 | def to_plist 22 | plist_as_dictionary.to_plist 23 | end 24 | 25 | def save 26 | File.open(path, 'w') { |file| file.write(to_plist) } 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/ambient/project_creation.rb: -------------------------------------------------------------------------------- 1 | module Ambient 2 | class ProjectCreation 3 | attr_reader :path, 4 | :name 5 | 6 | def initialize(path, name) 7 | @path = path 8 | @name = name.gsub(/\W/, "") 9 | check_name! 10 | end 11 | 12 | def create_ios_project 13 | check_already_exists! 14 | puts "# Setting up project..." 15 | copy_from_template 16 | rename_project_to_name 17 | find_and_replace_instances_of_template_to_name 18 | create_ambientfile 19 | run_ambientfile 20 | end 21 | 22 | private 23 | 24 | def check_already_exists! 25 | return unless File.exists?(project_path) 26 | 27 | puts "😱 #{name} already exists in the current directory" 28 | exit 1 29 | end 30 | 31 | def check_name! 32 | return if name 33 | 34 | puts "😱 You must specify a project name when creating a new project" 35 | puts "e.g. `ambient new MyProject`" 36 | exit(1) 37 | end 38 | 39 | def run_ambientfile 40 | Application.new(project_path).run_ambientfile 41 | end 42 | 43 | def create_ambientfile 44 | Init.new(project_path, name).create_ambientfile 45 | end 46 | 47 | def copy_from_template 48 | FileUtils.copy_entry ios_template_path, project_path 49 | end 50 | 51 | def rename_project_to_name 52 | FileUtils.mv "#{project_path}/PRODUCTNAME", 53 | "#{project_path}/#{name}" 54 | FileUtils.mv "#{project_path}/PRODUCTNAME.xcodeproj", 55 | "#{project_path}/#{name}.xcodeproj" 56 | end 57 | 58 | def find_and_replace_instances_of_template_to_name 59 | files_in_project.each do |file| 60 | find_and_replace(file, "PRODUCTNAME", name) 61 | end 62 | end 63 | 64 | def project_path 65 | path + "/#{name}" 66 | end 67 | 68 | def ios_template_path 69 | File.expand_path("../../../templates/ios", __FILE__) 70 | end 71 | 72 | def files_in_project 73 | Dir.glob(project_path + '/**/*').select { |path| File.file?(path) } 74 | end 75 | 76 | def find_and_replace(path, old, new) 77 | text = File.read(path) 78 | replace = text.gsub(old, new) 79 | return if text == replace 80 | File.open(path, "w") { |file| file.puts replace } 81 | end 82 | end 83 | end 84 | -------------------------------------------------------------------------------- /lib/ambient/project_helper.rb: -------------------------------------------------------------------------------- 1 | module Ambient 2 | class ProjectHelper 3 | attr_reader :path 4 | 5 | def initialize(path) 6 | @path = path 7 | projects = Dir.glob(path + '/*.xcodeproj') 8 | @project = Xcodeproj::Project.open(projects.first) 9 | end 10 | 11 | def reset_project_to_defaults 12 | @project.build_configurations.each do |configuration| 13 | build_settings = configuration.build_settings 14 | build_settings.each { |k, _| build_settings.delete(k) } 15 | end 16 | end 17 | 18 | def reset_targets_to_defaults 19 | @project.targets.each do |target| 20 | @project.build_configurations.each do |configuration| 21 | build_settings = target.build_configuration_list.build_settings(configuration.to_s) 22 | build_settings.each { |k, _| build_settings.delete(k) } 23 | end 24 | end 25 | end 26 | 27 | def reset_capabilities_to_defaults 28 | @project.targets.each do |target| 29 | CapabilitiesHelper.new(@project, target).clear_capabilities 30 | end 31 | end 32 | 33 | def process_project_options(options) 34 | @project.build_configurations.each do |configuration| 35 | options.each do |key, value| 36 | configuration.build_settings[key] = value 37 | configuration.build_settings.delete(key) if value == nil 38 | end 39 | end 40 | end 41 | 42 | def process_shared_target_options(shared_target_options) 43 | @project.targets.each do |target| 44 | options = shared_target_options[target.to_s] 45 | if options 46 | @project.build_configurations.each do |configuration| 47 | target.build_configuration_list.build_settings(configuration.to_s).merge!(options) 48 | end 49 | end 50 | end 51 | end 52 | 53 | def process_target_options(target_options) 54 | @project.targets.each do |target| 55 | options = target_options[target.to_s] 56 | if options 57 | @project.build_configurations.each do |configuration| 58 | scheme_options = options[configuration.to_s] 59 | if scheme_options 60 | target.build_configuration_list.build_settings(configuration.to_s).merge!(scheme_options) 61 | end 62 | end 63 | end 64 | end 65 | end 66 | 67 | def process_capabilities(capabilities_hash) 68 | capabilities_hash.each do |target_name, capabilities| 69 | @project.targets.each do |target| 70 | if target_name == target.to_s 71 | helper = CapabilitiesHelper.new(@project, target) 72 | capabilities.each { |c| helper.enable_capability(c) } 73 | end 74 | end 75 | end 76 | end 77 | 78 | def process_scheme_options(options) 79 | @project.build_configurations.each do |configuration| 80 | scheme_options = options[configuration.to_s] || {} 81 | scheme_options.each do |key, value| 82 | configuration.build_settings[key] = value 83 | configuration.build_settings.delete(key) if value == nil 84 | end 85 | end 86 | end 87 | 88 | def process_development_teams(development_teams) 89 | development_teams.each do |target_name, development_team| 90 | @project.targets.each do |target| 91 | if target_name == target.to_s 92 | helper = CapabilitiesHelper.new(@project, target) 93 | helper.set_development_team(development_team) 94 | end 95 | end 96 | end 97 | end 98 | 99 | def print_info 100 | puts "" 101 | puts "Targets:" 102 | @project.targets.each { |t| puts "- #{t.to_s}" } 103 | puts "" 104 | puts "Build configurations:" 105 | @project.build_configurations.each { |c| puts "- #{c.to_s}" } 106 | puts "" 107 | end 108 | 109 | def save_changes 110 | @project.save 111 | end 112 | end 113 | end 114 | -------------------------------------------------------------------------------- /templates/ios/PRODUCTNAME.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | AB04CB941EEC68E000947BB1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB04CB931EEC68E000947BB1 /* AppDelegate.swift */; }; 11 | AB04CB961EEC68E000947BB1 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AB04CB951EEC68E000947BB1 /* ViewController.swift */; }; 12 | AB04CB991EEC68E000947BB1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AB04CB971EEC68E000947BB1 /* Main.storyboard */; }; 13 | AB04CB9B1EEC68E000947BB1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AB04CB9A1EEC68E000947BB1 /* Assets.xcassets */; }; 14 | AB04CB9E1EEC68E000947BB1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AB04CB9C1EEC68E000947BB1 /* LaunchScreen.storyboard */; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXFileReference section */ 18 | AB04CB901EEC68E000947BB1 /* PRODUCTNAME.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PRODUCTNAME.app; sourceTree = BUILT_PRODUCTS_DIR; }; 19 | AB04CB931EEC68E000947BB1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 20 | AB04CB951EEC68E000947BB1 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 21 | AB04CB981EEC68E000947BB1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 22 | AB04CB9A1EEC68E000947BB1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 23 | AB04CB9D1EEC68E000947BB1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 24 | AB04CB9F1EEC68E000947BB1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 25 | /* End PBXFileReference section */ 26 | 27 | /* Begin PBXFrameworksBuildPhase section */ 28 | AB04CB8D1EEC68E000947BB1 /* Frameworks */ = { 29 | isa = PBXFrameworksBuildPhase; 30 | buildActionMask = 2147483647; 31 | files = ( 32 | ); 33 | runOnlyForDeploymentPostprocessing = 0; 34 | }; 35 | /* End PBXFrameworksBuildPhase section */ 36 | 37 | /* Begin PBXGroup section */ 38 | AB04CB871EEC68E000947BB1 = { 39 | isa = PBXGroup; 40 | children = ( 41 | AB04CB921EEC68E000947BB1 /* PRODUCTNAME */, 42 | AB04CB911EEC68E000947BB1 /* Products */, 43 | ); 44 | sourceTree = ""; 45 | }; 46 | AB04CB911EEC68E000947BB1 /* Products */ = { 47 | isa = PBXGroup; 48 | children = ( 49 | AB04CB901EEC68E000947BB1 /* PRODUCTNAME.app */, 50 | ); 51 | name = Products; 52 | sourceTree = ""; 53 | }; 54 | AB04CB921EEC68E000947BB1 /* PRODUCTNAME */ = { 55 | isa = PBXGroup; 56 | children = ( 57 | AB04CB931EEC68E000947BB1 /* AppDelegate.swift */, 58 | AB04CB951EEC68E000947BB1 /* ViewController.swift */, 59 | AB04CB971EEC68E000947BB1 /* Main.storyboard */, 60 | AB04CB9A1EEC68E000947BB1 /* Assets.xcassets */, 61 | AB04CB9C1EEC68E000947BB1 /* LaunchScreen.storyboard */, 62 | AB04CB9F1EEC68E000947BB1 /* Info.plist */, 63 | ); 64 | path = PRODUCTNAME; 65 | sourceTree = ""; 66 | }; 67 | /* End PBXGroup section */ 68 | 69 | /* Begin PBXNativeTarget section */ 70 | AB04CB8F1EEC68E000947BB1 /* PRODUCTNAME */ = { 71 | isa = PBXNativeTarget; 72 | buildConfigurationList = AB04CBA21EEC68E000947BB1 /* Build configuration list for PBXNativeTarget "PRODUCTNAME" */; 73 | buildPhases = ( 74 | AB04CB8C1EEC68E000947BB1 /* Sources */, 75 | AB04CB8D1EEC68E000947BB1 /* Frameworks */, 76 | AB04CB8E1EEC68E000947BB1 /* Resources */, 77 | ); 78 | buildRules = ( 79 | ); 80 | dependencies = ( 81 | ); 82 | name = PRODUCTNAME; 83 | productName = PRODUCTNAME; 84 | productReference = AB04CB901EEC68E000947BB1 /* PRODUCTNAME.app */; 85 | productType = "com.apple.product-type.application"; 86 | }; 87 | /* End PBXNativeTarget section */ 88 | 89 | /* Begin PBXProject section */ 90 | AB04CB881EEC68E000947BB1 /* Project object */ = { 91 | isa = PBXProject; 92 | attributes = { 93 | LastSwiftUpdateCheck = 0900; 94 | LastUpgradeCheck = 0900; 95 | ORGANIZATIONNAME = ORGANIZATION; 96 | TargetAttributes = { 97 | AB04CB8F1EEC68E000947BB1 = { 98 | CreatedOnToolsVersion = 9.0; 99 | }; 100 | }; 101 | }; 102 | buildConfigurationList = AB04CB8B1EEC68E000947BB1 /* Build configuration list for PBXProject "PRODUCTNAME" */; 103 | compatibilityVersion = "Xcode 8.0"; 104 | developmentRegion = en; 105 | hasScannedForEncodings = 0; 106 | knownRegions = ( 107 | en, 108 | Base, 109 | ); 110 | mainGroup = AB04CB871EEC68E000947BB1; 111 | productRefGroup = AB04CB911EEC68E000947BB1 /* Products */; 112 | projectDirPath = ""; 113 | projectRoot = ""; 114 | targets = ( 115 | AB04CB8F1EEC68E000947BB1 /* PRODUCTNAME */, 116 | ); 117 | }; 118 | /* End PBXProject section */ 119 | 120 | /* Begin PBXResourcesBuildPhase section */ 121 | AB04CB8E1EEC68E000947BB1 /* Resources */ = { 122 | isa = PBXResourcesBuildPhase; 123 | buildActionMask = 2147483647; 124 | files = ( 125 | AB04CB9E1EEC68E000947BB1 /* LaunchScreen.storyboard in Resources */, 126 | AB04CB9B1EEC68E000947BB1 /* Assets.xcassets in Resources */, 127 | AB04CB991EEC68E000947BB1 /* Main.storyboard in Resources */, 128 | ); 129 | runOnlyForDeploymentPostprocessing = 0; 130 | }; 131 | /* End PBXResourcesBuildPhase section */ 132 | 133 | /* Begin PBXSourcesBuildPhase section */ 134 | AB04CB8C1EEC68E000947BB1 /* Sources */ = { 135 | isa = PBXSourcesBuildPhase; 136 | buildActionMask = 2147483647; 137 | files = ( 138 | AB04CB961EEC68E000947BB1 /* ViewController.swift in Sources */, 139 | AB04CB941EEC68E000947BB1 /* AppDelegate.swift in Sources */, 140 | ); 141 | runOnlyForDeploymentPostprocessing = 0; 142 | }; 143 | /* End PBXSourcesBuildPhase section */ 144 | 145 | /* Begin PBXVariantGroup section */ 146 | AB04CB971EEC68E000947BB1 /* Main.storyboard */ = { 147 | isa = PBXVariantGroup; 148 | children = ( 149 | AB04CB981EEC68E000947BB1 /* Base */, 150 | ); 151 | name = Main.storyboard; 152 | sourceTree = ""; 153 | }; 154 | AB04CB9C1EEC68E000947BB1 /* LaunchScreen.storyboard */ = { 155 | isa = PBXVariantGroup; 156 | children = ( 157 | AB04CB9D1EEC68E000947BB1 /* Base */, 158 | ); 159 | name = LaunchScreen.storyboard; 160 | sourceTree = ""; 161 | }; 162 | /* End PBXVariantGroup section */ 163 | 164 | /* Begin XCBuildConfiguration section */ 165 | AB04CBA01EEC68E000947BB1 /* Debug */ = { 166 | isa = XCBuildConfiguration; 167 | buildSettings = { 168 | ALWAYS_SEARCH_USER_PATHS = NO; 169 | CLANG_ANALYZER_NONNULL = YES; 170 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 171 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 172 | CLANG_CXX_LIBRARY = "libc++"; 173 | CLANG_ENABLE_MODULES = YES; 174 | CLANG_ENABLE_OBJC_ARC = YES; 175 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 176 | CLANG_WARN_BOOL_CONVERSION = YES; 177 | CLANG_WARN_COMMA = YES; 178 | CLANG_WARN_CONSTANT_CONVERSION = YES; 179 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 180 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 181 | CLANG_WARN_EMPTY_BODY = YES; 182 | CLANG_WARN_ENUM_CONVERSION = YES; 183 | CLANG_WARN_INFINITE_RECURSION = YES; 184 | CLANG_WARN_INT_CONVERSION = YES; 185 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 186 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 187 | CLANG_WARN_STRICT_PROTOTYPES = YES; 188 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 189 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 190 | CLANG_WARN_UNREACHABLE_CODE = YES; 191 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 192 | CODE_SIGN_IDENTITY = "iPhone Developer"; 193 | COPY_PHASE_STRIP = NO; 194 | DEBUG_INFORMATION_FORMAT = dwarf; 195 | ENABLE_STRICT_OBJC_MSGSEND = YES; 196 | ENABLE_TESTABILITY = YES; 197 | GCC_C_LANGUAGE_STANDARD = gnu11; 198 | GCC_DYNAMIC_NO_PIC = NO; 199 | GCC_NO_COMMON_BLOCKS = YES; 200 | GCC_OPTIMIZATION_LEVEL = 0; 201 | GCC_PREPROCESSOR_DEFINITIONS = ( 202 | "DEBUG=1", 203 | "$(inherited)", 204 | ); 205 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 206 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 207 | GCC_WARN_UNDECLARED_SELECTOR = YES; 208 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 209 | GCC_WARN_UNUSED_FUNCTION = YES; 210 | GCC_WARN_UNUSED_VARIABLE = YES; 211 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 212 | MTL_ENABLE_DEBUG_INFO = YES; 213 | ONLY_ACTIVE_ARCH = YES; 214 | SDKROOT = iphoneos; 215 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 216 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 217 | }; 218 | name = Debug; 219 | }; 220 | AB04CBA11EEC68E000947BB1 /* Release */ = { 221 | isa = XCBuildConfiguration; 222 | buildSettings = { 223 | ALWAYS_SEARCH_USER_PATHS = NO; 224 | CLANG_ANALYZER_NONNULL = YES; 225 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 226 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 227 | CLANG_CXX_LIBRARY = "libc++"; 228 | CLANG_ENABLE_MODULES = YES; 229 | CLANG_ENABLE_OBJC_ARC = YES; 230 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 231 | CLANG_WARN_BOOL_CONVERSION = YES; 232 | CLANG_WARN_COMMA = YES; 233 | CLANG_WARN_CONSTANT_CONVERSION = YES; 234 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 235 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 236 | CLANG_WARN_EMPTY_BODY = YES; 237 | CLANG_WARN_ENUM_CONVERSION = YES; 238 | CLANG_WARN_INFINITE_RECURSION = YES; 239 | CLANG_WARN_INT_CONVERSION = YES; 240 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 241 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 242 | CLANG_WARN_STRICT_PROTOTYPES = YES; 243 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 244 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 245 | CLANG_WARN_UNREACHABLE_CODE = YES; 246 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 247 | CODE_SIGN_IDENTITY = "iPhone Developer"; 248 | COPY_PHASE_STRIP = NO; 249 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 250 | ENABLE_NS_ASSERTIONS = NO; 251 | ENABLE_STRICT_OBJC_MSGSEND = YES; 252 | GCC_C_LANGUAGE_STANDARD = gnu11; 253 | GCC_NO_COMMON_BLOCKS = YES; 254 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 255 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 256 | GCC_WARN_UNDECLARED_SELECTOR = YES; 257 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 258 | GCC_WARN_UNUSED_FUNCTION = YES; 259 | GCC_WARN_UNUSED_VARIABLE = YES; 260 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 261 | MTL_ENABLE_DEBUG_INFO = NO; 262 | SDKROOT = iphoneos; 263 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 264 | VALIDATE_PRODUCT = YES; 265 | }; 266 | name = Release; 267 | }; 268 | AB04CBA31EEC68E000947BB1 /* Debug */ = { 269 | isa = XCBuildConfiguration; 270 | buildSettings = { 271 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 272 | INFOPLIST_FILE = PRODUCTNAME/Info.plist; 273 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 274 | PRODUCT_BUNDLE_IDENTIFIER = com.organization.PRODUCTNAME; 275 | PRODUCT_NAME = "$(TARGET_NAME)"; 276 | SWIFT_VERSION = 4.0; 277 | TARGETED_DEVICE_FAMILY = "1,2"; 278 | }; 279 | name = Debug; 280 | }; 281 | AB04CBA41EEC68E000947BB1 /* Release */ = { 282 | isa = XCBuildConfiguration; 283 | buildSettings = { 284 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 285 | INFOPLIST_FILE = PRODUCTNAME/Info.plist; 286 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 287 | PRODUCT_BUNDLE_IDENTIFIER = com.organization.PRODUCTNAME; 288 | PRODUCT_NAME = "$(TARGET_NAME)"; 289 | SWIFT_VERSION = 4.0; 290 | TARGETED_DEVICE_FAMILY = "1,2"; 291 | }; 292 | name = Release; 293 | }; 294 | /* End XCBuildConfiguration section */ 295 | 296 | /* Begin XCConfigurationList section */ 297 | AB04CB8B1EEC68E000947BB1 /* Build configuration list for PBXProject "PRODUCTNAME" */ = { 298 | isa = XCConfigurationList; 299 | buildConfigurations = ( 300 | AB04CBA01EEC68E000947BB1 /* Debug */, 301 | AB04CBA11EEC68E000947BB1 /* Release */, 302 | ); 303 | defaultConfigurationIsVisible = 0; 304 | defaultConfigurationName = Release; 305 | }; 306 | AB04CBA21EEC68E000947BB1 /* Build configuration list for PBXNativeTarget "PRODUCTNAME" */ = { 307 | isa = XCConfigurationList; 308 | buildConfigurations = ( 309 | AB04CBA31EEC68E000947BB1 /* Debug */, 310 | AB04CBA41EEC68E000947BB1 /* Release */, 311 | ); 312 | defaultConfigurationIsVisible = 0; 313 | }; 314 | /* End XCConfigurationList section */ 315 | }; 316 | rootObject = AB04CB881EEC68E000947BB1 /* Project object */; 317 | } 318 | -------------------------------------------------------------------------------- /templates/ios/PRODUCTNAME.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /templates/ios/PRODUCTNAME/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | @UIApplicationMain 4 | class AppDelegate: UIResponder, UIApplicationDelegate { 5 | var window: UIWindow? 6 | 7 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 8 | // Override point for customization after application launch. 9 | return true 10 | } 11 | 12 | func applicationWillResignActive(_ application: UIApplication) { 13 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 14 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 15 | } 16 | 17 | func applicationDidEnterBackground(_ application: UIApplication) { 18 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 19 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 20 | } 21 | 22 | func applicationWillEnterForeground(_ application: UIApplication) { 23 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 24 | } 25 | 26 | func applicationDidBecomeActive(_ application: UIApplication) { 27 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 28 | } 29 | 30 | func applicationWillTerminate(_ application: UIApplication) { 31 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /templates/ios/PRODUCTNAME/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /templates/ios/PRODUCTNAME/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 | -------------------------------------------------------------------------------- /templates/ios/PRODUCTNAME/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /templates/ios/PRODUCTNAME/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /templates/ios/PRODUCTNAME/ViewController.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | class ViewController: UIViewController { 4 | override func viewDidLoad() { 5 | super.viewDidLoad() 6 | // Do any additional setup after loading the view, typically from a nib. 7 | } 8 | 9 | override func didReceiveMemoryWarning() { 10 | super.didReceiveMemoryWarning() 11 | // Dispose of any resources that can be recreated. 12 | } 13 | } 14 | --------------------------------------------------------------------------------