├── .gitignore ├── LICENSE ├── README.md ├── Sample └── sample │ └── Assets.xcassets │ ├── AppIconPdf.imageset │ ├── Contents.json │ └── Icon.pdf │ └── Contents.json ├── convertappicon.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── kreait.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── kreait.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── convertappicon.xcscheme │ └── xcschememanagement.plist ├── convertappicon ├── Config.swift ├── Helper.swift ├── Processor.swift ├── Project.swift └── main.swift └── sample ├── Icon.graffle ├── data.plist └── image3.pdf ├── Icon.sketch ├── convertappicon ├── sample.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── kreait.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── kreait.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── sample ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── Icon-1024.png │ │ ├── Icon-120.png │ │ ├── Icon-152.png │ │ ├── Icon-167.png │ │ ├── Icon-180.png │ │ ├── Icon-20.png │ │ ├── Icon-29.png │ │ ├── Icon-40.png │ │ ├── Icon-58.png │ │ ├── Icon-60.png │ │ ├── Icon-76.png │ │ ├── Icon-80.png │ │ └── Icon-87.png ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist └── ViewController.swift ├── samplewatch Extension ├── Assets.xcassets │ ├── Complication.complicationset │ │ ├── Circular.imageset │ │ │ └── Contents.json │ │ ├── Contents.json │ │ ├── Extra Large.imageset │ │ │ └── Contents.json │ │ ├── Modular.imageset │ │ │ └── Contents.json │ │ └── Utilitarian.imageset │ │ │ └── Contents.json │ └── Contents.json ├── ExtensionDelegate.swift ├── Info.plist └── InterfaceController.swift └── samplewatch ├── Assets.xcassets ├── AppIcon.appiconset │ ├── Contents.json │ ├── Icon-172.png │ ├── Icon-196.png │ ├── Icon-48.png │ ├── Icon-55.png │ ├── Icon-58.png │ ├── Icon-80.png │ ├── Icon-87.png │ └── Icon-88.png ├── AppIconPdf.imageset │ ├── Contents.json │ └── Icon.pdf └── Contents.json ├── Base.lproj └── Interface.storyboard └── Info.plist /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 kreait 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # convertappicon 2 | 3 | **convertappicon** converts a pdf into multiple app icons. It is a macOS tool written in Swift and currently supports generating iOS icons (iPhone, iPad and watch). The easiest way is to execute it from a project target script phase inside of Xcode. 4 | 5 | **IMPORTANT**: Put the master pdf file into the project right alongside the destination AppIcon with an additional tailing 'Pdf' asset name (see sample). You do *not* need to bundle/copy the pdf to the target itself. 6 | 7 | ## Background 8 | 9 | Xcode supports (named) images from pdf assets for a long time, but sadly the app icon itself is an exception: up to 18 png files have to be arranged manually inside of Xcode to provide a proper app icon. 10 | 11 | Due to an app offering multiple, pre-defined app icons to the user as an alternative as well, this can be a cumbersome task. 12 | 13 | For that reason, I've created this script during a hackathon as a proof of concept and then later moved from a bash/ImageMagick/scripting setup to a native Swift tool. 14 | 15 | Feel free to ask questions, fork or create pull requests - [oliver.michalak@kreait.com](oliver.michalak@kreait.com) 16 | 17 | ## Synopsis 18 | 19 | `convertappicon [-c] [-h] [-t] [-s iphone ipad watch marketing] APPICONSETPATH` 20 | 21 | APPICONSETPATH : The last parameter is the (partial) path to the destination .appiconset folder. It will traverse down and tries to find the first matching subfolder. 22 | 23 | -c : Will clean the target folder first. 24 | 25 | -h : Will show this help. 26 | 27 | -t : Test only, will print app icon path, master pdf path and all possible icons only. 28 | 29 | -s : Select icon categories: 'iphone', 'ipad', 'watch' or 'marketing' - if omitted all of them will be created. 30 | 31 | ## Sample 32 | 33 | There is a sample project showing you how the tool is going to be integrated. It was setup in the following steps: 34 | 35 | - create a new iOS project 36 | - open the `Assets.xcassets` entry (a default `AppIcon` asset should already be set up but empty) 37 | - add an new image asset and name it `AppIconPdf` 38 | - from either Sketch or OmniGraffle export the sample Icon file into a pdf 39 | - drag the pdf into the newly created AppIconPdf panel (optional: set scale to `Single Scale`) 40 | - create a new (aggregation) target in the projects target list (see cross platform templates) 41 | - within that target, create a new run script build phase 42 | - enter the path to the `convertappicon` script and add the `"${SRCROOT}"` folder 43 | - select the build target and build it, to run the conversion 44 | - now the previously empty `AppIcon` asset contains all icons 45 | 46 | Providing `"${SRCROOT}"` in a target build script is usually enough but if you have multiple icons, you must provide the full folder path. 47 | -------------------------------------------------------------------------------- /Sample/sample/Assets.xcassets/AppIconPdf.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Icon.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /Sample/sample/Assets.xcassets/AppIconPdf.imageset/Icon.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kreait/convertappicon/7a0c4d560580bd411cefedc956c4ae19cdcf7533/Sample/sample/Assets.xcassets/AppIconPdf.imageset/Icon.pdf -------------------------------------------------------------------------------- /Sample/sample/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /convertappicon.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 9E198D2F20712A710067061F /* Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E198D2E20712A710067061F /* Helper.swift */; }; 11 | 9E98A974206ED60800D31100 /* Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E98A973206ED60800D31100 /* Config.swift */; }; 12 | 9EC37EE2206BE702002C02EC /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EC37EE1206BE702002C02EC /* main.swift */; }; 13 | 9EEFC472206D6A450022FBE0 /* Project.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EEFC471206D6A450022FBE0 /* Project.swift */; }; 14 | 9EEFC474206D7A8D0022FBE0 /* Processor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EEFC473206D7A8D0022FBE0 /* Processor.swift */; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXCopyFilesBuildPhase section */ 18 | 9EC37EDC206BE702002C02EC /* CopyFiles */ = { 19 | isa = PBXCopyFilesBuildPhase; 20 | buildActionMask = 2147483647; 21 | dstPath = /usr/share/man/man1/; 22 | dstSubfolderSpec = 0; 23 | files = ( 24 | ); 25 | runOnlyForDeploymentPostprocessing = 1; 26 | }; 27 | /* End PBXCopyFilesBuildPhase section */ 28 | 29 | /* Begin PBXFileReference section */ 30 | 9E198D2E20712A710067061F /* Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Helper.swift; sourceTree = ""; }; 31 | 9E98A973206ED60800D31100 /* Config.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Config.swift; sourceTree = ""; }; 32 | 9EC37EDE206BE702002C02EC /* convertappicon */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = convertappicon; sourceTree = BUILT_PRODUCTS_DIR; }; 33 | 9EC37EE1206BE702002C02EC /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 34 | 9EEFC471206D6A450022FBE0 /* Project.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Project.swift; sourceTree = ""; }; 35 | 9EEFC473206D7A8D0022FBE0 /* Processor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Processor.swift; sourceTree = ""; }; 36 | /* End PBXFileReference section */ 37 | 38 | /* Begin PBXFrameworksBuildPhase section */ 39 | 9EC37EDB206BE702002C02EC /* Frameworks */ = { 40 | isa = PBXFrameworksBuildPhase; 41 | buildActionMask = 2147483647; 42 | files = ( 43 | ); 44 | runOnlyForDeploymentPostprocessing = 0; 45 | }; 46 | /* End PBXFrameworksBuildPhase section */ 47 | 48 | /* Begin PBXGroup section */ 49 | 9EC37ED5206BE702002C02EC = { 50 | isa = PBXGroup; 51 | children = ( 52 | 9EC37EE0206BE702002C02EC /* convertappicon */, 53 | 9EC37EDF206BE702002C02EC /* Products */, 54 | ); 55 | sourceTree = ""; 56 | }; 57 | 9EC37EDF206BE702002C02EC /* Products */ = { 58 | isa = PBXGroup; 59 | children = ( 60 | 9EC37EDE206BE702002C02EC /* convertappicon */, 61 | ); 62 | name = Products; 63 | sourceTree = ""; 64 | }; 65 | 9EC37EE0206BE702002C02EC /* convertappicon */ = { 66 | isa = PBXGroup; 67 | children = ( 68 | 9EC37EE1206BE702002C02EC /* main.swift */, 69 | 9E198D2E20712A710067061F /* Helper.swift */, 70 | 9EEFC471206D6A450022FBE0 /* Project.swift */, 71 | 9EEFC473206D7A8D0022FBE0 /* Processor.swift */, 72 | 9E98A973206ED60800D31100 /* Config.swift */, 73 | ); 74 | path = convertappicon; 75 | sourceTree = ""; 76 | }; 77 | /* End PBXGroup section */ 78 | 79 | /* Begin PBXNativeTarget section */ 80 | 9EC37EDD206BE702002C02EC /* convertappicon */ = { 81 | isa = PBXNativeTarget; 82 | buildConfigurationList = 9EC37EE5206BE702002C02EC /* Build configuration list for PBXNativeTarget "convertappicon" */; 83 | buildPhases = ( 84 | 9EC37EDA206BE702002C02EC /* Sources */, 85 | 9EC37EDB206BE702002C02EC /* Frameworks */, 86 | 9EC37EDC206BE702002C02EC /* CopyFiles */, 87 | ); 88 | buildRules = ( 89 | ); 90 | dependencies = ( 91 | ); 92 | name = convertappicon; 93 | productName = convert; 94 | productReference = 9EC37EDE206BE702002C02EC /* convertappicon */; 95 | productType = "com.apple.product-type.tool"; 96 | }; 97 | /* End PBXNativeTarget section */ 98 | 99 | /* Begin PBXProject section */ 100 | 9EC37ED6206BE702002C02EC /* Project object */ = { 101 | isa = PBXProject; 102 | attributes = { 103 | LastSwiftUpdateCheck = 0920; 104 | LastUpgradeCheck = 0930; 105 | ORGANIZATIONNAME = kreait; 106 | TargetAttributes = { 107 | 9EC37EDD206BE702002C02EC = { 108 | CreatedOnToolsVersion = 9.2; 109 | ProvisioningStyle = Automatic; 110 | }; 111 | }; 112 | }; 113 | buildConfigurationList = 9EC37ED9206BE702002C02EC /* Build configuration list for PBXProject "convertappicon" */; 114 | compatibilityVersion = "Xcode 8.0"; 115 | developmentRegion = en; 116 | hasScannedForEncodings = 0; 117 | knownRegions = ( 118 | en, 119 | ); 120 | mainGroup = 9EC37ED5206BE702002C02EC; 121 | productRefGroup = 9EC37EDF206BE702002C02EC /* Products */; 122 | projectDirPath = ""; 123 | projectRoot = ""; 124 | targets = ( 125 | 9EC37EDD206BE702002C02EC /* convertappicon */, 126 | ); 127 | }; 128 | /* End PBXProject section */ 129 | 130 | /* Begin PBXSourcesBuildPhase section */ 131 | 9EC37EDA206BE702002C02EC /* Sources */ = { 132 | isa = PBXSourcesBuildPhase; 133 | buildActionMask = 2147483647; 134 | files = ( 135 | 9E198D2F20712A710067061F /* Helper.swift in Sources */, 136 | 9EC37EE2206BE702002C02EC /* main.swift in Sources */, 137 | 9E98A974206ED60800D31100 /* Config.swift in Sources */, 138 | 9EEFC474206D7A8D0022FBE0 /* Processor.swift in Sources */, 139 | 9EEFC472206D6A450022FBE0 /* Project.swift in Sources */, 140 | ); 141 | runOnlyForDeploymentPostprocessing = 0; 142 | }; 143 | /* End PBXSourcesBuildPhase section */ 144 | 145 | /* Begin XCBuildConfiguration section */ 146 | 9EC37EE3206BE702002C02EC /* Debug */ = { 147 | isa = XCBuildConfiguration; 148 | buildSettings = { 149 | ALWAYS_SEARCH_USER_PATHS = NO; 150 | CLANG_ANALYZER_NONNULL = YES; 151 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 152 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 153 | CLANG_CXX_LIBRARY = "libc++"; 154 | CLANG_ENABLE_MODULES = YES; 155 | CLANG_ENABLE_OBJC_ARC = YES; 156 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 157 | CLANG_WARN_BOOL_CONVERSION = YES; 158 | CLANG_WARN_COMMA = YES; 159 | CLANG_WARN_CONSTANT_CONVERSION = YES; 160 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 161 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 162 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 163 | CLANG_WARN_EMPTY_BODY = YES; 164 | CLANG_WARN_ENUM_CONVERSION = YES; 165 | CLANG_WARN_INFINITE_RECURSION = YES; 166 | CLANG_WARN_INT_CONVERSION = YES; 167 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 168 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 169 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 170 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 171 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 172 | CLANG_WARN_STRICT_PROTOTYPES = YES; 173 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 174 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 175 | CLANG_WARN_UNREACHABLE_CODE = YES; 176 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 177 | CODE_SIGN_IDENTITY = "Mac Developer"; 178 | COPY_PHASE_STRIP = NO; 179 | DEBUG_INFORMATION_FORMAT = dwarf; 180 | ENABLE_STRICT_OBJC_MSGSEND = YES; 181 | ENABLE_TESTABILITY = YES; 182 | GCC_C_LANGUAGE_STANDARD = gnu11; 183 | GCC_DYNAMIC_NO_PIC = NO; 184 | GCC_NO_COMMON_BLOCKS = YES; 185 | GCC_OPTIMIZATION_LEVEL = 0; 186 | GCC_PREPROCESSOR_DEFINITIONS = ( 187 | "DEBUG=1", 188 | "$(inherited)", 189 | ); 190 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 191 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 192 | GCC_WARN_UNDECLARED_SELECTOR = YES; 193 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 194 | GCC_WARN_UNUSED_FUNCTION = YES; 195 | GCC_WARN_UNUSED_VARIABLE = YES; 196 | MACOSX_DEPLOYMENT_TARGET = 10.13; 197 | MTL_ENABLE_DEBUG_INFO = YES; 198 | ONLY_ACTIVE_ARCH = YES; 199 | SDKROOT = macosx; 200 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 201 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 202 | }; 203 | name = Debug; 204 | }; 205 | 9EC37EE4206BE702002C02EC /* Release */ = { 206 | isa = XCBuildConfiguration; 207 | buildSettings = { 208 | ALWAYS_SEARCH_USER_PATHS = NO; 209 | CLANG_ANALYZER_NONNULL = YES; 210 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 211 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 212 | CLANG_CXX_LIBRARY = "libc++"; 213 | CLANG_ENABLE_MODULES = YES; 214 | CLANG_ENABLE_OBJC_ARC = YES; 215 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 216 | CLANG_WARN_BOOL_CONVERSION = YES; 217 | CLANG_WARN_COMMA = YES; 218 | CLANG_WARN_CONSTANT_CONVERSION = YES; 219 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 220 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 221 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 222 | CLANG_WARN_EMPTY_BODY = YES; 223 | CLANG_WARN_ENUM_CONVERSION = YES; 224 | CLANG_WARN_INFINITE_RECURSION = YES; 225 | CLANG_WARN_INT_CONVERSION = YES; 226 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 227 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 228 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 229 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 230 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 231 | CLANG_WARN_STRICT_PROTOTYPES = YES; 232 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 233 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 234 | CLANG_WARN_UNREACHABLE_CODE = YES; 235 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 236 | CODE_SIGN_IDENTITY = "Mac Developer"; 237 | COPY_PHASE_STRIP = NO; 238 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 239 | ENABLE_NS_ASSERTIONS = NO; 240 | ENABLE_STRICT_OBJC_MSGSEND = YES; 241 | GCC_C_LANGUAGE_STANDARD = gnu11; 242 | GCC_NO_COMMON_BLOCKS = YES; 243 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 244 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 245 | GCC_WARN_UNDECLARED_SELECTOR = YES; 246 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 247 | GCC_WARN_UNUSED_FUNCTION = YES; 248 | GCC_WARN_UNUSED_VARIABLE = YES; 249 | MACOSX_DEPLOYMENT_TARGET = 10.13; 250 | MTL_ENABLE_DEBUG_INFO = NO; 251 | SDKROOT = macosx; 252 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 253 | }; 254 | name = Release; 255 | }; 256 | 9EC37EE6206BE702002C02EC /* Debug */ = { 257 | isa = XCBuildConfiguration; 258 | buildSettings = { 259 | CODE_SIGN_STYLE = Automatic; 260 | DEVELOPMENT_TEAM = L4Y43KC7TD; 261 | PRODUCT_NAME = "$(TARGET_NAME)"; 262 | SWIFT_VERSION = 4.0; 263 | }; 264 | name = Debug; 265 | }; 266 | 9EC37EE7206BE702002C02EC /* Release */ = { 267 | isa = XCBuildConfiguration; 268 | buildSettings = { 269 | CODE_SIGN_STYLE = Automatic; 270 | DEVELOPMENT_TEAM = L4Y43KC7TD; 271 | PRODUCT_NAME = "$(TARGET_NAME)"; 272 | SWIFT_VERSION = 4.0; 273 | }; 274 | name = Release; 275 | }; 276 | /* End XCBuildConfiguration section */ 277 | 278 | /* Begin XCConfigurationList section */ 279 | 9EC37ED9206BE702002C02EC /* Build configuration list for PBXProject "convertappicon" */ = { 280 | isa = XCConfigurationList; 281 | buildConfigurations = ( 282 | 9EC37EE3206BE702002C02EC /* Debug */, 283 | 9EC37EE4206BE702002C02EC /* Release */, 284 | ); 285 | defaultConfigurationIsVisible = 0; 286 | defaultConfigurationName = Release; 287 | }; 288 | 9EC37EE5206BE702002C02EC /* Build configuration list for PBXNativeTarget "convertappicon" */ = { 289 | isa = XCConfigurationList; 290 | buildConfigurations = ( 291 | 9EC37EE6206BE702002C02EC /* Debug */, 292 | 9EC37EE7206BE702002C02EC /* Release */, 293 | ); 294 | defaultConfigurationIsVisible = 0; 295 | defaultConfigurationName = Release; 296 | }; 297 | /* End XCConfigurationList section */ 298 | }; 299 | rootObject = 9EC37ED6206BE702002C02EC /* Project object */; 300 | } 301 | -------------------------------------------------------------------------------- /convertappicon.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /convertappicon.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /convertappicon.xcodeproj/project.xcworkspace/xcuserdata/kreait.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kreait/convertappicon/7a0c4d560580bd411cefedc956c4ae19cdcf7533/convertappicon.xcodeproj/project.xcworkspace/xcuserdata/kreait.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /convertappicon.xcodeproj/xcuserdata/kreait.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 20 | 21 | 22 | 24 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /convertappicon.xcodeproj/xcuserdata/kreait.xcuserdatad/xcschemes/convertappicon.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /convertappicon.xcodeproj/xcuserdata/kreait.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | convertappicon.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 9EC37EDD206BE702002C02EC 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /convertappicon/Config.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Image.swift 3 | // convert 4 | // 5 | // Created by kreait on 30.03.18. 6 | // Copyright © 2018 kreait. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | enum Idiom: String, Encodable { 13 | 14 | case phone = "iphone" 15 | case pad = "ipad" 16 | case marketing = "ios-marketing" 17 | case watch = "watch" 18 | } 19 | 20 | enum Role: String, Encodable { 21 | 22 | case notificationCenter 23 | case companionSettings 24 | case appLauncher 25 | case longLook 26 | case quickLook 27 | } 28 | 29 | struct Config: Encodable { 30 | 31 | let size: Float 32 | let idiom: Idiom 33 | let scale: Int 34 | let role: Role? 35 | let subtype: String? 36 | 37 | init(size: Float, idiom: Idiom, scale: Int, role: Role? = nil, subtype: String? = nil) { 38 | self.size = size 39 | self.idiom = idiom 40 | self.scale = scale 41 | self.role = role 42 | self.subtype = subtype 43 | } 44 | 45 | var iconName: String { 46 | return "Icon-\(Int(size * Float(scale))).png" 47 | } 48 | 49 | enum CodingKeys: String, CodingKey { 50 | case size 51 | case idiom 52 | case scale 53 | case role 54 | case subtype 55 | case filename 56 | } 57 | 58 | func encode(to encoder: Encoder) throws { 59 | var container = encoder.container(keyedBy: CodingKeys.self) 60 | if Int(size) == Int(size.rounded()) { // uh 61 | try container.encode("\(Int(size))x\(Int(size))", forKey: .size) 62 | } 63 | else { 64 | try container.encode("\(size)x\(size)", forKey: .size) 65 | } 66 | try container.encode(idiom, forKey: .idiom) 67 | try container.encode("\(scale)x", forKey: .scale) 68 | try container.encode(iconName, forKey: .filename) 69 | if let role = role { 70 | try container.encode(role, forKey: .role) 71 | } 72 | if let subtype = subtype { 73 | try container.encode(subtype, forKey: .subtype) 74 | } 75 | } 76 | } 77 | 78 | struct Configuration { 79 | 80 | static let list = [Config(size: 20, idiom: .phone, scale: 2), 81 | Config(size: 20, idiom: .phone, scale: 3), 82 | Config(size: 29, idiom: .phone, scale: 2), 83 | Config(size: 29, idiom: .phone, scale: 3), 84 | Config(size: 40, idiom: .phone, scale: 2), 85 | Config(size: 40, idiom: .phone, scale: 3), 86 | Config(size: 60, idiom: .phone, scale: 2), 87 | Config(size: 60, idiom: .phone, scale: 3), 88 | 89 | Config(size: 20, idiom: .pad, scale: 1), 90 | Config(size: 20, idiom: .pad, scale: 2), 91 | Config(size: 29, idiom: .pad, scale: 1), 92 | Config(size: 29, idiom: .pad, scale: 2), 93 | Config(size: 40, idiom: .pad, scale: 1), 94 | Config(size: 40, idiom: .pad, scale: 2), 95 | Config(size: 76, idiom: .pad, scale: 1), 96 | Config(size: 76, idiom: .pad, scale: 2), 97 | Config(size: 83.5, idiom: .pad, scale: 2), 98 | 99 | Config(size: 24, idiom: .watch, scale: 2, role: .notificationCenter, subtype: "38mm"), 100 | Config(size: 27.5, idiom: .watch, scale: 2, role: .notificationCenter, subtype: "42mm"), 101 | Config(size: 29, idiom: .watch, scale: 2, role: .companionSettings), 102 | Config(size: 29, idiom: .watch, scale: 3, role: .companionSettings), 103 | Config(size: 40, idiom: .watch, scale: 2, role: .appLauncher, subtype: "38mm"), 104 | Config(size: 44, idiom: .watch, scale: 2, role: .longLook, subtype: "42mm"), 105 | Config(size: 86, idiom: .watch, scale: 2, role: .quickLook, subtype: "38mm"), 106 | Config(size: 98, idiom: .watch, scale: 2, role: .quickLook, subtype: "42mm"), 107 | 108 | Config(size: 1024, idiom: .marketing, scale: 1)] 109 | } 110 | -------------------------------------------------------------------------------- /convertappicon/Helper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Help.swift 3 | // convertappicon 4 | // 5 | // Created by kreait on 01.04.18. 6 | // Copyright © 2018 kreait. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | struct Helper { 13 | 14 | static func output(verbose: Bool) { 15 | 16 | print ("convertappicon [-c] [-h] [-t] [-s iphone ipad marketing] APPICONSETPATH") 17 | if verbose { 18 | print("'convertappicon' converts a pdf into multiple app icon sizes for iOS") 19 | print("-c : Will clean the target folder first.") 20 | print("-h : Will show this help.") 21 | print("-t : Test only, will print app icon path, master pdf path and all possible icons only.") 22 | print("-s : Select icon categories: 'iphone', 'ipad', 'watch' or 'marketing' - if omitted all of them will be created.") 23 | print("APPICONSETPATH : The last parameter is the (partial) path to the destination .appiconset folder. It will traverse down and tries to find the first matching subfolder.") 24 | print("Providing ${SRCROOT} in a target build script is usually enough but if you have multiple icons, you must provide the full folder path.") 25 | print("\nIMPORTANT: The master PDF file must be placed into the project as well right alongside the destination AppIcon with an additional tailing 'Pdf' name.") 26 | print("Example: if you target app icon is called 'AppIcon' then create an image asset with 'AppIconPdf' with only the pdf inside (although you do *not* need to bundle/copy the pdf to the target itself).") 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /convertappicon/Processor.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Image.swift 3 | // convert 4 | // 5 | // Created by kreait on 29.03.18. 6 | // Copyright © 2018 kreait. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import AppKit 11 | 12 | 13 | struct Processor { 14 | 15 | private var iconPath: String 16 | private var pdfPath: String 17 | 18 | private var sourceImage: NSImage 19 | 20 | init?(iconPath: String, pdfPath: String) { 21 | 22 | self.iconPath = iconPath 23 | self.pdfPath = pdfPath 24 | guard let sourceImage = NSImage(contentsOfFile: pdfPath) else { 25 | return nil 26 | } 27 | self.sourceImage = sourceImage 28 | } 29 | 30 | func convert(to config: Config) -> Bool { 31 | 32 | let size = CGFloat(config.size * Float(config.scale)) 33 | let rect = NSRect(x: 0, y: 0, width: size, height: size) 34 | 35 | // create non-retina image rep, uh 36 | guard let rep = NSBitmapImageRep(bitmapDataPlanes: nil, pixelsWide: Int(size), pixelsHigh: Int(size), bitsPerSample: 8, samplesPerPixel: 4, hasAlpha: true, isPlanar: false, colorSpaceName: NSColorSpaceName.calibratedRGB, bytesPerRow: 0, bitsPerPixel: 0) else { return false } 37 | rep.size = NSSize(width: size, height: size) 38 | NSGraphicsContext.saveGraphicsState() 39 | NSGraphicsContext.current = NSGraphicsContext(bitmapImageRep: rep) 40 | sourceImage.draw(in: rect, from: NSRect(x: 0, y: 0, width: sourceImage.size.width, height: sourceImage.size.height), operation: .copy, fraction: 1) 41 | NSGraphicsContext.restoreGraphicsState() 42 | 43 | guard let pngData = rep.representation(using: .png, properties: [:]) else { return false } 44 | 45 | let name = "\(self.iconPath)/\(config.iconName)" 46 | do { 47 | try pngData.write(to: URL(fileURLWithPath: name)) 48 | } 49 | catch { 50 | print(error) 51 | return false 52 | } 53 | return true 54 | } 55 | 56 | func writeConfiguration(configurations: [Config]) -> Bool { 57 | 58 | struct Contents: Encodable { 59 | 60 | struct Info: Encodable { 61 | let version: Int 62 | let author: String 63 | } 64 | 65 | var info: Info 66 | var images: [Config] 67 | } 68 | 69 | let contents = Contents(info: Contents.Info(version: 1, author: "xcode"), images: configurations) 70 | 71 | let name = "\(self.iconPath)/Contents.json" 72 | 73 | do { 74 | let data = try JSONEncoder().encode(contents) 75 | try data.write(to: URL(fileURLWithPath: name)) 76 | } 77 | catch { 78 | print(error) 79 | return false 80 | } 81 | return true 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /convertappicon/Project.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Project.swift 3 | // convert 4 | // 5 | // Created by kreait on 29.03.18. 6 | // Copyright © 2018 kreait. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | class Project { 13 | 14 | private let path: String 15 | 16 | init(path: String) { 17 | self.path = path 18 | } 19 | 20 | private func find(name: String, basepath: String) -> String? { 21 | guard !basepath.contains(name) else { return basepath } 22 | do { 23 | let list = try FileManager.default.contentsOfDirectory(atPath: basepath) 24 | let results = list.filter({ $0.prefix(1) != "." }) 25 | .compactMap { find(name: name, basepath: "\(basepath)/\($0)") } 26 | guard let result = results.first else { return nil } 27 | guard FileManager.default.fileExists(atPath: result) else { return nil } 28 | return result 29 | } 30 | catch { 31 | // print(error) 32 | return nil 33 | } 34 | } 35 | 36 | func findAppIconPath() -> String? { 37 | return find(name: ".appiconset", basepath: path) 38 | } 39 | 40 | func findPdfPath(from appIconPath:String) -> String? { 41 | let comps = appIconPath.components(separatedBy: "/") 42 | guard let fullname = comps.last else { return nil } 43 | guard let name = fullname.components(separatedBy: ".").first else { return nil } 44 | let head = comps.dropLast() 45 | let resultPath = "\(head.joined(separator: "/"))/\(name)Pdf.imageset" 46 | return find(name: ".pdf", basepath: resultPath) 47 | } 48 | 49 | func cleanTarget(appIconPath: String) { 50 | do { 51 | let list = try FileManager.default.contentsOfDirectory(atPath: appIconPath) 52 | try list.filter({ $0.prefix(1) != "." }) 53 | .forEach { try FileManager.default.removeItem(atPath: "\(appIconPath)/\($0)") } 54 | } 55 | catch { 56 | // print(error) 57 | } 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /convertappicon/main.swift: -------------------------------------------------------------------------------- 1 | // 2 | // main.swift 3 | // convert 4 | // 5 | // Created by kreait on 28.03.18. 6 | // Copyright © 2018 kreait. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | if 2 > CommandLine.argc { 13 | Helper.output(verbose: false) 14 | exit(-1) 15 | } 16 | 17 | let options = CommandLine.arguments[1.. 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /sample/sample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /sample/sample.xcodeproj/project.xcworkspace/xcuserdata/kreait.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kreait/convertappicon/7a0c4d560580bd411cefedc956c4ae19cdcf7533/sample/sample.xcodeproj/project.xcworkspace/xcuserdata/kreait.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /sample/sample.xcodeproj/xcuserdata/kreait.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | app icon.xcscheme 8 | 9 | orderHint 10 | 2 11 | 12 | sample.xcscheme 13 | 14 | orderHint 15 | 0 16 | 17 | samplewatch.xcscheme 18 | 19 | orderHint 20 | 1 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /sample/sample/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // sample 4 | // 5 | // Created by kreait on 03.04.18. 6 | // Copyright © 2018 kreait. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // 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. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // 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. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // 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. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // 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. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /sample/sample/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | {"images":[{"size":"20x20","idiom":"iphone","filename":"Icon-40.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"Icon-60.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"Icon-58.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"Icon-87.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"Icon-80.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"Icon-120.png","scale":"3x"},{"size":"60x60","idiom":"iphone","filename":"Icon-120.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-180.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"Icon-20.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"Icon-40.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"Icon-29.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"Icon-58.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"Icon-40.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"Icon-80.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"Icon-76.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"Icon-152.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"Icon-167.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"Icon-1024.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}} -------------------------------------------------------------------------------- /sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kreait/convertappicon/7a0c4d560580bd411cefedc956c4ae19cdcf7533/sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-1024.png -------------------------------------------------------------------------------- /sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kreait/convertappicon/7a0c4d560580bd411cefedc956c4ae19cdcf7533/sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-120.png -------------------------------------------------------------------------------- /sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kreait/convertappicon/7a0c4d560580bd411cefedc956c4ae19cdcf7533/sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-152.png -------------------------------------------------------------------------------- /sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kreait/convertappicon/7a0c4d560580bd411cefedc956c4ae19cdcf7533/sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-167.png -------------------------------------------------------------------------------- /sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kreait/convertappicon/7a0c4d560580bd411cefedc956c4ae19cdcf7533/sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-180.png -------------------------------------------------------------------------------- /sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kreait/convertappicon/7a0c4d560580bd411cefedc956c4ae19cdcf7533/sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-20.png -------------------------------------------------------------------------------- /sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kreait/convertappicon/7a0c4d560580bd411cefedc956c4ae19cdcf7533/sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-29.png -------------------------------------------------------------------------------- /sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kreait/convertappicon/7a0c4d560580bd411cefedc956c4ae19cdcf7533/sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-40.png -------------------------------------------------------------------------------- /sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kreait/convertappicon/7a0c4d560580bd411cefedc956c4ae19cdcf7533/sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-58.png -------------------------------------------------------------------------------- /sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kreait/convertappicon/7a0c4d560580bd411cefedc956c4ae19cdcf7533/sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-60.png -------------------------------------------------------------------------------- /sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kreait/convertappicon/7a0c4d560580bd411cefedc956c4ae19cdcf7533/sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-76.png -------------------------------------------------------------------------------- /sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kreait/convertappicon/7a0c4d560580bd411cefedc956c4ae19cdcf7533/sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-80.png -------------------------------------------------------------------------------- /sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kreait/convertappicon/7a0c4d560580bd411cefedc956c4ae19cdcf7533/sample/sample/Assets.xcassets/AppIcon.appiconset/Icon-87.png -------------------------------------------------------------------------------- /sample/sample/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 | -------------------------------------------------------------------------------- /sample/sample/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 | -------------------------------------------------------------------------------- /sample/sample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /sample/sample/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // sample 4 | // 5 | // Created by kreait on 03.04.18. 6 | // Copyright © 2018 kreait. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | // Do any additional setup after loading the view, typically from a nib. 16 | } 17 | 18 | override func didReceiveMemoryWarning() { 19 | super.didReceiveMemoryWarning() 20 | // Dispose of any resources that can be recreated. 21 | } 22 | 23 | 24 | } 25 | 26 | -------------------------------------------------------------------------------- /sample/samplewatch Extension/Assets.xcassets/Complication.complicationset/Circular.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "watch", 5 | "scale" : "2x", 6 | "screen-width" : "<=145" 7 | }, 8 | { 9 | "idiom" : "watch", 10 | "scale" : "2x", 11 | "screen-width" : ">145" 12 | } 13 | ], 14 | "info" : { 15 | "version" : 1, 16 | "author" : "xcode" 17 | } 18 | } -------------------------------------------------------------------------------- /sample/samplewatch Extension/Assets.xcassets/Complication.complicationset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "assets" : [ 3 | { 4 | "idiom" : "watch", 5 | "filename" : "Circular.imageset", 6 | "role" : "circular" 7 | }, 8 | { 9 | "idiom" : "watch", 10 | "filename" : "Extra Large.imageset", 11 | "role" : "extra-large" 12 | }, 13 | { 14 | "idiom" : "watch", 15 | "filename" : "Modular.imageset", 16 | "role" : "modular" 17 | }, 18 | { 19 | "idiom" : "watch", 20 | "filename" : "Utilitarian.imageset", 21 | "role" : "utilitarian" 22 | } 23 | ], 24 | "info" : { 25 | "version" : 1, 26 | "author" : "xcode" 27 | } 28 | } -------------------------------------------------------------------------------- /sample/samplewatch Extension/Assets.xcassets/Complication.complicationset/Extra Large.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "watch", 5 | "scale" : "2x", 6 | "screen-width" : "<=145" 7 | }, 8 | { 9 | "idiom" : "watch", 10 | "scale" : "2x", 11 | "screen-width" : ">145" 12 | } 13 | ], 14 | "info" : { 15 | "version" : 1, 16 | "author" : "xcode" 17 | } 18 | } -------------------------------------------------------------------------------- /sample/samplewatch Extension/Assets.xcassets/Complication.complicationset/Modular.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "watch", 5 | "scale" : "2x", 6 | "screen-width" : "<=145" 7 | }, 8 | { 9 | "idiom" : "watch", 10 | "scale" : "2x", 11 | "screen-width" : ">145" 12 | } 13 | ], 14 | "info" : { 15 | "version" : 1, 16 | "author" : "xcode" 17 | } 18 | } -------------------------------------------------------------------------------- /sample/samplewatch Extension/Assets.xcassets/Complication.complicationset/Utilitarian.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "watch", 5 | "scale" : "2x", 6 | "screen-width" : "<=145" 7 | }, 8 | { 9 | "idiom" : "watch", 10 | "scale" : "2x", 11 | "screen-width" : ">145" 12 | } 13 | ], 14 | "info" : { 15 | "version" : 1, 16 | "author" : "xcode" 17 | } 18 | } -------------------------------------------------------------------------------- /sample/samplewatch Extension/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /sample/samplewatch Extension/ExtensionDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExtensionDelegate.swift 3 | // samplewatch Extension 4 | // 5 | // Created by kreait on 05.04.18. 6 | // Copyright © 2018 kreait. All rights reserved. 7 | // 8 | 9 | import WatchKit 10 | 11 | class ExtensionDelegate: NSObject, WKExtensionDelegate { 12 | 13 | func applicationDidFinishLaunching() { 14 | // Perform any final initialization of your application. 15 | } 16 | 17 | func applicationDidBecomeActive() { 18 | // 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. 19 | } 20 | 21 | func applicationWillResignActive() { 22 | // 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. 23 | // Use this method to pause ongoing tasks, disable timers, etc. 24 | } 25 | 26 | func handle(_ backgroundTasks: Set) { 27 | // Sent when the system needs to launch the application in the background to process tasks. Tasks arrive in a set, so loop through and process each one. 28 | for task in backgroundTasks { 29 | // Use a switch statement to check the task type 30 | switch task { 31 | case let backgroundTask as WKApplicationRefreshBackgroundTask: 32 | // Be sure to complete the background task once you’re done. 33 | backgroundTask.setTaskCompletedWithSnapshot(false) 34 | case let snapshotTask as WKSnapshotRefreshBackgroundTask: 35 | // Snapshot tasks have a unique completion call, make sure to set your expiration date 36 | snapshotTask.setTaskCompleted(restoredDefaultState: true, estimatedSnapshotExpiration: Date.distantFuture, userInfo: nil) 37 | case let connectivityTask as WKWatchConnectivityRefreshBackgroundTask: 38 | // Be sure to complete the connectivity task once you’re done. 39 | connectivityTask.setTaskCompletedWithSnapshot(false) 40 | case let urlSessionTask as WKURLSessionRefreshBackgroundTask: 41 | // Be sure to complete the URL session task once you’re done. 42 | urlSessionTask.setTaskCompletedWithSnapshot(false) 43 | default: 44 | // make sure to complete unhandled task types 45 | task.setTaskCompletedWithSnapshot(false) 46 | } 47 | } 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /sample/samplewatch Extension/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | samplewatch Extension 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | XPC! 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | NSExtension 24 | 25 | NSExtensionAttributes 26 | 27 | WKAppBundleIdentifier 28 | com.kreait.sample.watchkitapp 29 | 30 | NSExtensionPointIdentifier 31 | com.apple.watchkit 32 | 33 | WKExtensionDelegateClassName 34 | $(PRODUCT_MODULE_NAME).ExtensionDelegate 35 | 36 | 37 | -------------------------------------------------------------------------------- /sample/samplewatch Extension/InterfaceController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // InterfaceController.swift 3 | // samplewatch Extension 4 | // 5 | // Created by kreait on 05.04.18. 6 | // Copyright © 2018 kreait. All rights reserved. 7 | // 8 | 9 | import WatchKit 10 | import Foundation 11 | 12 | 13 | class InterfaceController: WKInterfaceController { 14 | 15 | override func awake(withContext context: Any?) { 16 | super.awake(withContext: context) 17 | 18 | // Configure interface objects here. 19 | } 20 | 21 | override func willActivate() { 22 | // This method is called when watch view controller is about to be visible to user 23 | super.willActivate() 24 | } 25 | 26 | override func didDeactivate() { 27 | // This method is called when watch view controller is no longer visible 28 | super.didDeactivate() 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /sample/samplewatch/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | {"images":[{"size":"24x24","idiom":"watch","filename":"Icon-48.png","subtype":"38mm","role":"notificationCenter","scale":"2x"},{"size":"27.5x27.5","idiom":"watch","filename":"Icon-55.png","subtype":"42mm","role":"notificationCenter","scale":"2x"},{"size":"29x29","idiom":"watch","filename":"Icon-58.png","role":"companionSettings","scale":"2x"},{"size":"29x29","idiom":"watch","filename":"Icon-87.png","role":"companionSettings","scale":"3x"},{"size":"40x40","idiom":"watch","filename":"Icon-80.png","subtype":"38mm","role":"appLauncher","scale":"2x"},{"size":"44x44","idiom":"watch","filename":"Icon-88.png","subtype":"42mm","role":"longLook","scale":"2x"},{"size":"86x86","idiom":"watch","filename":"Icon-172.png","subtype":"38mm","role":"quickLook","scale":"2x"},{"size":"98x98","idiom":"watch","filename":"Icon-196.png","subtype":"42mm","role":"quickLook","scale":"2x"}],"info":{"version":1,"author":"xcode"}} -------------------------------------------------------------------------------- /sample/samplewatch/Assets.xcassets/AppIcon.appiconset/Icon-172.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kreait/convertappicon/7a0c4d560580bd411cefedc956c4ae19cdcf7533/sample/samplewatch/Assets.xcassets/AppIcon.appiconset/Icon-172.png -------------------------------------------------------------------------------- /sample/samplewatch/Assets.xcassets/AppIcon.appiconset/Icon-196.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kreait/convertappicon/7a0c4d560580bd411cefedc956c4ae19cdcf7533/sample/samplewatch/Assets.xcassets/AppIcon.appiconset/Icon-196.png -------------------------------------------------------------------------------- /sample/samplewatch/Assets.xcassets/AppIcon.appiconset/Icon-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kreait/convertappicon/7a0c4d560580bd411cefedc956c4ae19cdcf7533/sample/samplewatch/Assets.xcassets/AppIcon.appiconset/Icon-48.png -------------------------------------------------------------------------------- /sample/samplewatch/Assets.xcassets/AppIcon.appiconset/Icon-55.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kreait/convertappicon/7a0c4d560580bd411cefedc956c4ae19cdcf7533/sample/samplewatch/Assets.xcassets/AppIcon.appiconset/Icon-55.png -------------------------------------------------------------------------------- /sample/samplewatch/Assets.xcassets/AppIcon.appiconset/Icon-58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kreait/convertappicon/7a0c4d560580bd411cefedc956c4ae19cdcf7533/sample/samplewatch/Assets.xcassets/AppIcon.appiconset/Icon-58.png -------------------------------------------------------------------------------- /sample/samplewatch/Assets.xcassets/AppIcon.appiconset/Icon-80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kreait/convertappicon/7a0c4d560580bd411cefedc956c4ae19cdcf7533/sample/samplewatch/Assets.xcassets/AppIcon.appiconset/Icon-80.png -------------------------------------------------------------------------------- /sample/samplewatch/Assets.xcassets/AppIcon.appiconset/Icon-87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kreait/convertappicon/7a0c4d560580bd411cefedc956c4ae19cdcf7533/sample/samplewatch/Assets.xcassets/AppIcon.appiconset/Icon-87.png -------------------------------------------------------------------------------- /sample/samplewatch/Assets.xcassets/AppIcon.appiconset/Icon-88.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kreait/convertappicon/7a0c4d560580bd411cefedc956c4ae19cdcf7533/sample/samplewatch/Assets.xcassets/AppIcon.appiconset/Icon-88.png -------------------------------------------------------------------------------- /sample/samplewatch/Assets.xcassets/AppIconPdf.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "Icon.pdf" 6 | } 7 | ], 8 | "info" : { 9 | "version" : 1, 10 | "author" : "xcode" 11 | } 12 | } -------------------------------------------------------------------------------- /sample/samplewatch/Assets.xcassets/AppIconPdf.imageset/Icon.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kreait/convertappicon/7a0c4d560580bd411cefedc956c4ae19cdcf7533/sample/samplewatch/Assets.xcassets/AppIconPdf.imageset/Icon.pdf -------------------------------------------------------------------------------- /sample/samplewatch/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /sample/samplewatch/Base.lproj/Interface.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /sample/samplewatch/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | sample 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | UISupportedInterfaceOrientations 24 | 25 | UIInterfaceOrientationPortrait 26 | UIInterfaceOrientationPortraitUpsideDown 27 | 28 | WKCompanionAppBundleIdentifier 29 | com.kreait.sample 30 | WKWatchKitApp 31 | 32 | 33 | 34 | --------------------------------------------------------------------------------