├── DynamicAppIcons ├── DynamicAppIcons.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ ├── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcuserdata │ │ │ └── puneetbhagat02.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ ├── xcshareddata │ │ └── xcschemes │ │ │ └── DynamicAppIcons.xcscheme │ └── xcuserdata │ │ └── puneetbhagat02.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ └── xcschememanagement.plist └── DynamicAppIcons │ ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ └── chaintech-logo-01.png │ ├── Contents.json │ ├── chaintech-logo-01.appiconset │ │ ├── Contents.json │ │ └── chaintech-logo-01.png │ ├── chaintech-logo-02.appiconset │ │ ├── Contents.json │ │ └── chaintech-logo-02.png │ ├── chaintech-logo-03.appiconset │ │ ├── Contents.json │ │ └── chaintech-logo-03.png │ └── chaintech-logo-04.appiconset │ │ ├── Contents.json │ │ └── chaintech-logo-04.png │ ├── DynamicAppIcons-Bridging-Header.h │ ├── DynamicAppIconsApp.swift │ ├── Headers │ ├── LSApplicationProxy.h │ └── LSBundleProxy.h │ ├── Module │ ├── AppIconHome │ │ └── View │ │ │ └── ContentView.swift │ └── AppIconsList │ │ ├── View │ │ └── AppIconsListView.swift │ │ └── ViewModel │ │ ├── IconAnimator.swift │ │ └── IconAnimatorHandler.swift │ └── Preview Content │ └── Preview Assets.xcassets │ └── Contents.json └── README.md /DynamicAppIcons/DynamicAppIcons.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 56; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 756404082C5B8E8500511458 /* IconAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 756404072C5B8E8500511458 /* IconAnimator.swift */; }; 11 | 757BC34A2C5BA0E000B7B347 /* IconAnimatorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 757BC3492C5BA0E000B7B347 /* IconAnimatorHandler.swift */; }; 12 | 75C70C0C2C5B6FB70084506A /* DynamicAppIconsApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75C70C0B2C5B6FB70084506A /* DynamicAppIconsApp.swift */; }; 13 | 75C70C0E2C5B6FB70084506A /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75C70C0D2C5B6FB70084506A /* ContentView.swift */; }; 14 | 75C70C102C5B6FB90084506A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 75C70C0F2C5B6FB90084506A /* Assets.xcassets */; }; 15 | 75C70C132C5B6FB90084506A /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 75C70C122C5B6FB90084506A /* Preview Assets.xcassets */; }; 16 | 75C70C1A2C5B6FD60084506A /* AppIconsListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 75C70C192C5B6FD60084506A /* AppIconsListView.swift */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXFileReference section */ 20 | 756404072C5B8E8500511458 /* IconAnimator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconAnimator.swift; sourceTree = ""; }; 21 | 7564040A2C5B919200511458 /* LSApplicationProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LSApplicationProxy.h; sourceTree = ""; }; 22 | 7564040B2C5B91BC00511458 /* LSBundleProxy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LSBundleProxy.h; sourceTree = ""; }; 23 | 7564040C2C5B937D00511458 /* DynamicAppIcons-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "DynamicAppIcons-Bridging-Header.h"; sourceTree = ""; }; 24 | 757BC3492C5BA0E000B7B347 /* IconAnimatorHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconAnimatorHandler.swift; sourceTree = ""; }; 25 | 75C70C082C5B6FB70084506A /* DynamicAppIcons.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DynamicAppIcons.app; sourceTree = BUILT_PRODUCTS_DIR; }; 26 | 75C70C0B2C5B6FB70084506A /* DynamicAppIconsApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DynamicAppIconsApp.swift; sourceTree = ""; }; 27 | 75C70C0D2C5B6FB70084506A /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 28 | 75C70C0F2C5B6FB90084506A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 29 | 75C70C122C5B6FB90084506A /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 30 | 75C70C192C5B6FD60084506A /* AppIconsListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIconsListView.swift; sourceTree = ""; }; 31 | /* End PBXFileReference section */ 32 | 33 | /* Begin PBXFrameworksBuildPhase section */ 34 | 75C70C052C5B6FB70084506A /* Frameworks */ = { 35 | isa = PBXFrameworksBuildPhase; 36 | buildActionMask = 2147483647; 37 | files = ( 38 | ); 39 | runOnlyForDeploymentPostprocessing = 0; 40 | }; 41 | /* End PBXFrameworksBuildPhase section */ 42 | 43 | /* Begin PBXGroup section */ 44 | 756404002C5B7E4200511458 /* Module */ = { 45 | isa = PBXGroup; 46 | children = ( 47 | 756404012C5B7E4B00511458 /* AppIconHome */, 48 | 756404032C5B7E5C00511458 /* AppIconsList */, 49 | ); 50 | path = Module; 51 | sourceTree = ""; 52 | }; 53 | 756404012C5B7E4B00511458 /* AppIconHome */ = { 54 | isa = PBXGroup; 55 | children = ( 56 | 756404022C5B7E5300511458 /* View */, 57 | ); 58 | path = AppIconHome; 59 | sourceTree = ""; 60 | }; 61 | 756404022C5B7E5300511458 /* View */ = { 62 | isa = PBXGroup; 63 | children = ( 64 | 75C70C0D2C5B6FB70084506A /* ContentView.swift */, 65 | ); 66 | path = View; 67 | sourceTree = ""; 68 | }; 69 | 756404032C5B7E5C00511458 /* AppIconsList */ = { 70 | isa = PBXGroup; 71 | children = ( 72 | 756404062C5B8E4C00511458 /* ViewModel */, 73 | 756404042C5B7E6700511458 /* View */, 74 | ); 75 | path = AppIconsList; 76 | sourceTree = ""; 77 | }; 78 | 756404042C5B7E6700511458 /* View */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | 75C70C192C5B6FD60084506A /* AppIconsListView.swift */, 82 | ); 83 | path = View; 84 | sourceTree = ""; 85 | }; 86 | 756404062C5B8E4C00511458 /* ViewModel */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 756404072C5B8E8500511458 /* IconAnimator.swift */, 90 | 757BC3492C5BA0E000B7B347 /* IconAnimatorHandler.swift */, 91 | ); 92 | path = ViewModel; 93 | sourceTree = ""; 94 | }; 95 | 756404092C5B900200511458 /* Headers */ = { 96 | isa = PBXGroup; 97 | children = ( 98 | 7564040A2C5B919200511458 /* LSApplicationProxy.h */, 99 | 7564040B2C5B91BC00511458 /* LSBundleProxy.h */, 100 | ); 101 | path = Headers; 102 | sourceTree = ""; 103 | }; 104 | 7564040F2C5B97D000511458 /* Frameworks */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | ); 108 | name = Frameworks; 109 | sourceTree = ""; 110 | }; 111 | 75C70BFF2C5B6FB70084506A = { 112 | isa = PBXGroup; 113 | children = ( 114 | 75C70C0A2C5B6FB70084506A /* DynamicAppIcons */, 115 | 75C70C092C5B6FB70084506A /* Products */, 116 | 7564040F2C5B97D000511458 /* Frameworks */, 117 | ); 118 | sourceTree = ""; 119 | }; 120 | 75C70C092C5B6FB70084506A /* Products */ = { 121 | isa = PBXGroup; 122 | children = ( 123 | 75C70C082C5B6FB70084506A /* DynamicAppIcons.app */, 124 | ); 125 | name = Products; 126 | sourceTree = ""; 127 | }; 128 | 75C70C0A2C5B6FB70084506A /* DynamicAppIcons */ = { 129 | isa = PBXGroup; 130 | children = ( 131 | 756404092C5B900200511458 /* Headers */, 132 | 756404002C5B7E4200511458 /* Module */, 133 | 75C70C0B2C5B6FB70084506A /* DynamicAppIconsApp.swift */, 134 | 75C70C0F2C5B6FB90084506A /* Assets.xcassets */, 135 | 75C70C112C5B6FB90084506A /* Preview Content */, 136 | 7564040C2C5B937D00511458 /* DynamicAppIcons-Bridging-Header.h */, 137 | ); 138 | path = DynamicAppIcons; 139 | sourceTree = ""; 140 | }; 141 | 75C70C112C5B6FB90084506A /* Preview Content */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | 75C70C122C5B6FB90084506A /* Preview Assets.xcassets */, 145 | ); 146 | path = "Preview Content"; 147 | sourceTree = ""; 148 | }; 149 | /* End PBXGroup section */ 150 | 151 | /* Begin PBXNativeTarget section */ 152 | 75C70C072C5B6FB70084506A /* DynamicAppIcons */ = { 153 | isa = PBXNativeTarget; 154 | buildConfigurationList = 75C70C162C5B6FB90084506A /* Build configuration list for PBXNativeTarget "DynamicAppIcons" */; 155 | buildPhases = ( 156 | 75C70C042C5B6FB70084506A /* Sources */, 157 | 75C70C052C5B6FB70084506A /* Frameworks */, 158 | 75C70C062C5B6FB70084506A /* Resources */, 159 | ); 160 | buildRules = ( 161 | ); 162 | dependencies = ( 163 | ); 164 | name = DynamicAppIcons; 165 | productName = DynamicAppIcons; 166 | productReference = 75C70C082C5B6FB70084506A /* DynamicAppIcons.app */; 167 | productType = "com.apple.product-type.application"; 168 | }; 169 | /* End PBXNativeTarget section */ 170 | 171 | /* Begin PBXProject section */ 172 | 75C70C002C5B6FB70084506A /* Project object */ = { 173 | isa = PBXProject; 174 | attributes = { 175 | BuildIndependentTargetsInParallel = 1; 176 | LastSwiftUpdateCheck = 1530; 177 | LastUpgradeCheck = 1530; 178 | TargetAttributes = { 179 | 75C70C072C5B6FB70084506A = { 180 | CreatedOnToolsVersion = 15.3; 181 | LastSwiftMigration = 1530; 182 | }; 183 | }; 184 | }; 185 | buildConfigurationList = 75C70C032C5B6FB70084506A /* Build configuration list for PBXProject "DynamicAppIcons" */; 186 | compatibilityVersion = "Xcode 14.0"; 187 | developmentRegion = en; 188 | hasScannedForEncodings = 0; 189 | knownRegions = ( 190 | en, 191 | Base, 192 | ); 193 | mainGroup = 75C70BFF2C5B6FB70084506A; 194 | productRefGroup = 75C70C092C5B6FB70084506A /* Products */; 195 | projectDirPath = ""; 196 | projectRoot = ""; 197 | targets = ( 198 | 75C70C072C5B6FB70084506A /* DynamicAppIcons */, 199 | ); 200 | }; 201 | /* End PBXProject section */ 202 | 203 | /* Begin PBXResourcesBuildPhase section */ 204 | 75C70C062C5B6FB70084506A /* Resources */ = { 205 | isa = PBXResourcesBuildPhase; 206 | buildActionMask = 2147483647; 207 | files = ( 208 | 75C70C132C5B6FB90084506A /* Preview Assets.xcassets in Resources */, 209 | 75C70C102C5B6FB90084506A /* Assets.xcassets in Resources */, 210 | ); 211 | runOnlyForDeploymentPostprocessing = 0; 212 | }; 213 | /* End PBXResourcesBuildPhase section */ 214 | 215 | /* Begin PBXSourcesBuildPhase section */ 216 | 75C70C042C5B6FB70084506A /* Sources */ = { 217 | isa = PBXSourcesBuildPhase; 218 | buildActionMask = 2147483647; 219 | files = ( 220 | 75C70C0E2C5B6FB70084506A /* ContentView.swift in Sources */, 221 | 756404082C5B8E8500511458 /* IconAnimator.swift in Sources */, 222 | 75C70C0C2C5B6FB70084506A /* DynamicAppIconsApp.swift in Sources */, 223 | 75C70C1A2C5B6FD60084506A /* AppIconsListView.swift in Sources */, 224 | 757BC34A2C5BA0E000B7B347 /* IconAnimatorHandler.swift in Sources */, 225 | ); 226 | runOnlyForDeploymentPostprocessing = 0; 227 | }; 228 | /* End PBXSourcesBuildPhase section */ 229 | 230 | /* Begin XCBuildConfiguration section */ 231 | 75C70C142C5B6FB90084506A /* Debug */ = { 232 | isa = XCBuildConfiguration; 233 | buildSettings = { 234 | ALWAYS_SEARCH_USER_PATHS = NO; 235 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 236 | CLANG_ANALYZER_NONNULL = YES; 237 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 238 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 239 | CLANG_ENABLE_MODULES = YES; 240 | CLANG_ENABLE_OBJC_ARC = YES; 241 | CLANG_ENABLE_OBJC_WEAK = YES; 242 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 243 | CLANG_WARN_BOOL_CONVERSION = YES; 244 | CLANG_WARN_COMMA = YES; 245 | CLANG_WARN_CONSTANT_CONVERSION = YES; 246 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 247 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 248 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 249 | CLANG_WARN_EMPTY_BODY = YES; 250 | CLANG_WARN_ENUM_CONVERSION = YES; 251 | CLANG_WARN_INFINITE_RECURSION = YES; 252 | CLANG_WARN_INT_CONVERSION = YES; 253 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 254 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 255 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 256 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 257 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 258 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 259 | CLANG_WARN_STRICT_PROTOTYPES = YES; 260 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 261 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 262 | CLANG_WARN_UNREACHABLE_CODE = YES; 263 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 264 | COPY_PHASE_STRIP = NO; 265 | DEBUG_INFORMATION_FORMAT = dwarf; 266 | ENABLE_STRICT_OBJC_MSGSEND = YES; 267 | ENABLE_TESTABILITY = YES; 268 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 269 | GCC_C_LANGUAGE_STANDARD = gnu17; 270 | GCC_DYNAMIC_NO_PIC = NO; 271 | GCC_NO_COMMON_BLOCKS = YES; 272 | GCC_OPTIMIZATION_LEVEL = 0; 273 | GCC_PREPROCESSOR_DEFINITIONS = ( 274 | "DEBUG=1", 275 | "$(inherited)", 276 | ); 277 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 278 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 279 | GCC_WARN_UNDECLARED_SELECTOR = YES; 280 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 281 | GCC_WARN_UNUSED_FUNCTION = YES; 282 | GCC_WARN_UNUSED_VARIABLE = YES; 283 | IPHONEOS_DEPLOYMENT_TARGET = 17.0; 284 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES; 285 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 286 | MTL_FAST_MATH = YES; 287 | ONLY_ACTIVE_ARCH = YES; 288 | SDKROOT = iphoneos; 289 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; 290 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 291 | }; 292 | name = Debug; 293 | }; 294 | 75C70C152C5B6FB90084506A /* Release */ = { 295 | isa = XCBuildConfiguration; 296 | buildSettings = { 297 | ALWAYS_SEARCH_USER_PATHS = NO; 298 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; 299 | CLANG_ANALYZER_NONNULL = YES; 300 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 301 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 302 | CLANG_ENABLE_MODULES = YES; 303 | CLANG_ENABLE_OBJC_ARC = YES; 304 | CLANG_ENABLE_OBJC_WEAK = YES; 305 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 306 | CLANG_WARN_BOOL_CONVERSION = YES; 307 | CLANG_WARN_COMMA = YES; 308 | CLANG_WARN_CONSTANT_CONVERSION = YES; 309 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 310 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 311 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 312 | CLANG_WARN_EMPTY_BODY = YES; 313 | CLANG_WARN_ENUM_CONVERSION = YES; 314 | CLANG_WARN_INFINITE_RECURSION = YES; 315 | CLANG_WARN_INT_CONVERSION = YES; 316 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 317 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 318 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 319 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 320 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 321 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 322 | CLANG_WARN_STRICT_PROTOTYPES = YES; 323 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 324 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 325 | CLANG_WARN_UNREACHABLE_CODE = YES; 326 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 327 | COPY_PHASE_STRIP = NO; 328 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 329 | ENABLE_NS_ASSERTIONS = NO; 330 | ENABLE_STRICT_OBJC_MSGSEND = YES; 331 | ENABLE_USER_SCRIPT_SANDBOXING = YES; 332 | GCC_C_LANGUAGE_STANDARD = gnu17; 333 | GCC_NO_COMMON_BLOCKS = YES; 334 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 335 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 336 | GCC_WARN_UNDECLARED_SELECTOR = YES; 337 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 338 | GCC_WARN_UNUSED_FUNCTION = YES; 339 | GCC_WARN_UNUSED_VARIABLE = YES; 340 | IPHONEOS_DEPLOYMENT_TARGET = 17.0; 341 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES; 342 | MTL_ENABLE_DEBUG_INFO = NO; 343 | MTL_FAST_MATH = YES; 344 | SDKROOT = iphoneos; 345 | SWIFT_COMPILATION_MODE = wholemodule; 346 | VALIDATE_PRODUCT = YES; 347 | }; 348 | name = Release; 349 | }; 350 | 75C70C172C5B6FB90084506A /* Debug */ = { 351 | isa = XCBuildConfiguration; 352 | buildSettings = { 353 | ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES = "chaintech-logo-01 chaintech-logo-02 chaintech-logo-03 chaintech-logo-04"; 354 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 355 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 356 | ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; 357 | CLANG_ENABLE_MODULES = YES; 358 | CODE_SIGN_STYLE = Automatic; 359 | CURRENT_PROJECT_VERSION = 1; 360 | DEVELOPMENT_ASSET_PATHS = "\"DynamicAppIcons/Preview Content\""; 361 | ENABLE_PREVIEWS = YES; 362 | GENERATE_INFOPLIST_FILE = YES; 363 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 364 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 365 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 366 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 367 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 368 | IPHONEOS_DEPLOYMENT_TARGET = 17.0; 369 | LD_RUNPATH_SEARCH_PATHS = ( 370 | "$(inherited)", 371 | "@executable_path/Frameworks", 372 | ); 373 | MACH_O_TYPE = mh_execute; 374 | MARKETING_VERSION = 1.0; 375 | OTHER_LDFLAGS = ( 376 | "-w", 377 | "-Wl,-U,_OBJC_CLASS_$_LSBundleProxy", 378 | ); 379 | PRODUCT_BUNDLE_IDENTIFIER = com.dynamicAppIcons; 380 | PRODUCT_NAME = "$(TARGET_NAME)"; 381 | SWIFT_EMIT_LOC_STRINGS = YES; 382 | SWIFT_OBJC_BRIDGING_HEADER = "DynamicAppIcons/DynamicAppIcons-Bridging-Header.h"; 383 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 384 | SWIFT_VERSION = 5.0; 385 | TARGETED_DEVICE_FAMILY = "1,2"; 386 | }; 387 | name = Debug; 388 | }; 389 | 75C70C182C5B6FB90084506A /* Release */ = { 390 | isa = XCBuildConfiguration; 391 | buildSettings = { 392 | ASSETCATALOG_COMPILER_ALTERNATE_APPICON_NAMES = "chaintech-logo-01 chaintech-logo-02 chaintech-logo-03 chaintech-logo-04"; 393 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 394 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 395 | ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; 396 | CLANG_ENABLE_MODULES = YES; 397 | CODE_SIGN_STYLE = Automatic; 398 | CURRENT_PROJECT_VERSION = 1; 399 | DEVELOPMENT_ASSET_PATHS = "\"DynamicAppIcons/Preview Content\""; 400 | ENABLE_PREVIEWS = YES; 401 | GENERATE_INFOPLIST_FILE = YES; 402 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 403 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 404 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 405 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 406 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 407 | IPHONEOS_DEPLOYMENT_TARGET = 17.0; 408 | LD_RUNPATH_SEARCH_PATHS = ( 409 | "$(inherited)", 410 | "@executable_path/Frameworks", 411 | ); 412 | MACH_O_TYPE = mh_execute; 413 | MARKETING_VERSION = 1.0; 414 | OTHER_LDFLAGS = ( 415 | "-w", 416 | "-Wl,-U,_OBJC_CLASS_$_LSBundleProxy", 417 | ); 418 | PRODUCT_BUNDLE_IDENTIFIER = com.dynamicAppIcons; 419 | PRODUCT_NAME = "$(TARGET_NAME)"; 420 | SWIFT_EMIT_LOC_STRINGS = YES; 421 | SWIFT_OBJC_BRIDGING_HEADER = "DynamicAppIcons/DynamicAppIcons-Bridging-Header.h"; 422 | SWIFT_VERSION = 5.0; 423 | TARGETED_DEVICE_FAMILY = "1,2"; 424 | }; 425 | name = Release; 426 | }; 427 | /* End XCBuildConfiguration section */ 428 | 429 | /* Begin XCConfigurationList section */ 430 | 75C70C032C5B6FB70084506A /* Build configuration list for PBXProject "DynamicAppIcons" */ = { 431 | isa = XCConfigurationList; 432 | buildConfigurations = ( 433 | 75C70C142C5B6FB90084506A /* Debug */, 434 | 75C70C152C5B6FB90084506A /* Release */, 435 | ); 436 | defaultConfigurationIsVisible = 0; 437 | defaultConfigurationName = Release; 438 | }; 439 | 75C70C162C5B6FB90084506A /* Build configuration list for PBXNativeTarget "DynamicAppIcons" */ = { 440 | isa = XCConfigurationList; 441 | buildConfigurations = ( 442 | 75C70C172C5B6FB90084506A /* Debug */, 443 | 75C70C182C5B6FB90084506A /* Release */, 444 | ); 445 | defaultConfigurationIsVisible = 0; 446 | defaultConfigurationName = Release; 447 | }; 448 | /* End XCConfigurationList section */ 449 | }; 450 | rootObject = 75C70C002C5B6FB70084506A /* Project object */; 451 | } 452 | -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons.xcodeproj/project.xcworkspace/xcuserdata/puneetbhagat02.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chaintech-Network/Dynamic_App_Icon_With_Animation_ios/34a9eebf42ae8d49072678d61f4999e36ee632fa/DynamicAppIcons/DynamicAppIcons.xcodeproj/project.xcworkspace/xcuserdata/puneetbhagat02.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons.xcodeproj/xcshareddata/xcschemes/DynamicAppIcons.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 9 | 10 | 16 | 22 | 23 | 24 | 25 | 26 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons.xcodeproj/xcuserdata/puneetbhagat02.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons.xcodeproj/xcuserdata/puneetbhagat02.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | DynamicAppIcons.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 75C70C072C5B6FB70084506A 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "chaintech-logo-01.png", 5 | "idiom" : "universal", 6 | "platform" : "ios", 7 | "size" : "1024x1024" 8 | } 9 | ], 10 | "info" : { 11 | "author" : "xcode", 12 | "version" : 1 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons/Assets.xcassets/AppIcon.appiconset/chaintech-logo-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chaintech-Network/Dynamic_App_Icon_With_Animation_ios/34a9eebf42ae8d49072678d61f4999e36ee632fa/DynamicAppIcons/DynamicAppIcons/Assets.xcassets/AppIcon.appiconset/chaintech-logo-01.png -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons/Assets.xcassets/chaintech-logo-01.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "chaintech-logo-01.png", 5 | "idiom" : "universal", 6 | "platform" : "ios", 7 | "size" : "1024x1024" 8 | } 9 | ], 10 | "info" : { 11 | "author" : "xcode", 12 | "version" : 1 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons/Assets.xcassets/chaintech-logo-01.appiconset/chaintech-logo-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chaintech-Network/Dynamic_App_Icon_With_Animation_ios/34a9eebf42ae8d49072678d61f4999e36ee632fa/DynamicAppIcons/DynamicAppIcons/Assets.xcassets/chaintech-logo-01.appiconset/chaintech-logo-01.png -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons/Assets.xcassets/chaintech-logo-02.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "chaintech-logo-02.png", 5 | "idiom" : "universal", 6 | "platform" : "ios", 7 | "size" : "1024x1024" 8 | } 9 | ], 10 | "info" : { 11 | "author" : "xcode", 12 | "version" : 1 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons/Assets.xcassets/chaintech-logo-02.appiconset/chaintech-logo-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chaintech-Network/Dynamic_App_Icon_With_Animation_ios/34a9eebf42ae8d49072678d61f4999e36ee632fa/DynamicAppIcons/DynamicAppIcons/Assets.xcassets/chaintech-logo-02.appiconset/chaintech-logo-02.png -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons/Assets.xcassets/chaintech-logo-03.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "chaintech-logo-03.png", 5 | "idiom" : "universal", 6 | "platform" : "ios", 7 | "size" : "1024x1024" 8 | } 9 | ], 10 | "info" : { 11 | "author" : "xcode", 12 | "version" : 1 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons/Assets.xcassets/chaintech-logo-03.appiconset/chaintech-logo-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chaintech-Network/Dynamic_App_Icon_With_Animation_ios/34a9eebf42ae8d49072678d61f4999e36ee632fa/DynamicAppIcons/DynamicAppIcons/Assets.xcassets/chaintech-logo-03.appiconset/chaintech-logo-03.png -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons/Assets.xcassets/chaintech-logo-04.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "chaintech-logo-04.png", 5 | "idiom" : "universal", 6 | "platform" : "ios", 7 | "size" : "1024x1024" 8 | } 9 | ], 10 | "info" : { 11 | "author" : "xcode", 12 | "version" : 1 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons/Assets.xcassets/chaintech-logo-04.appiconset/chaintech-logo-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chaintech-Network/Dynamic_App_Icon_With_Animation_ios/34a9eebf42ae8d49072678d61f4999e36ee632fa/DynamicAppIcons/DynamicAppIcons/Assets.xcassets/chaintech-logo-04.appiconset/chaintech-logo-04.png -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons/DynamicAppIcons-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | #import "LSApplicationProxy.h" 6 | #import "LSBundleProxy.h" 7 | -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons/DynamicAppIconsApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DynamicAppIconsApp.swift 3 | // DynamicAppIcons 4 | // 5 | // Created by Puneet Bhagat02 on 01/08/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | @main 11 | struct DynamicAppIconsApp: App { 12 | var body: some Scene { 13 | WindowGroup { 14 | ContentView() 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons/Headers/LSApplicationProxy.h: -------------------------------------------------------------------------------- 1 | // 2 | // LSApplicationProxy.h 3 | // DynamicAppIcons 4 | // 5 | // Created by Puneet Bhagat02 on 01/08/24. 6 | // 7 | 8 | #import 9 | 10 | /** 11 | * A proxy for interacting with the application. 12 | */ 13 | @interface LSApplicationProxy : NSObject 14 | 15 | /** 16 | * Sets the alternate icon name for the application. 17 | * 18 | * @param name The name of the alternate icon. 19 | * @param result A block that will be executed with the result of the operation. 20 | */ 21 | - (void)setAlternateIconName:(nullable NSString *)name 22 | withResult:(void (^_Nonnull)(BOOL success, NSError *_Nullable))result; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons/Headers/LSBundleProxy.h: -------------------------------------------------------------------------------- 1 | // 2 | // LSBundleProxy.h 3 | // DynamicAppIcons 4 | // 5 | // Created by Puneet Bhagat02 on 01/08/24. 6 | // 7 | 8 | #import 9 | 10 | /** 11 | * A proxy for interacting with the bundle. 12 | */ 13 | @interface LSBundleProxy : NSObject 14 | 15 | /** 16 | * Returns the bundle proxy for the current process. 17 | * 18 | * @return The bundle proxy. 19 | */ 20 | + (nonnull LSApplicationProxy *)bundleProxyForCurrentProcess; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons/Module/AppIconHome/View/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // ChangeAppIcons 4 | // 5 | // Created by Puneet Bhagat02 on 01/08/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ContentView: View { 11 | 12 | @AppStorage("icon") var selectedIcon: String = "chaintech-logo-01" 13 | 14 | @State private var isPresentAppIconsList: Bool = false 15 | 16 | var body: some View { 17 | Button { 18 | isPresentAppIconsList = true 19 | } label: { 20 | VStack { 21 | if selectedIcon == "Animate\nicon" { 22 | VStack { 23 | Text("Note:- ") 24 | .font(.system(size: 18).bold()) 25 | .foregroundStyle(.black) 26 | + 27 | Text("Closing the app. Animation will begin in 3 seconds.") 28 | .font(.system(size: 18)) 29 | .foregroundStyle(.black) 30 | Text("Animation\nicon") 31 | .font(.system(size: 18).bold()) 32 | .foregroundStyle(.white) 33 | .frame(width: 100, height: 100) 34 | .background(LinearGradient(gradient: Gradient(colors: [.blue, .green]), startPoint: .leading, endPoint: .bottom)) 35 | .cornerRadius(6) 36 | 37 | } 38 | } else { 39 | Image(uiImage: UIImage(named: selectedIcon) ?? UIImage()) 40 | .resizable() 41 | .frame(width: 100, height: 100) 42 | .cornerRadius(8) 43 | } 44 | Text("Change App icon") 45 | .font(.system(size: 18).bold()) 46 | } 47 | } 48 | .sheet(isPresented: $isPresentAppIconsList, content: { 49 | AppIconsListView() 50 | .presentationDetents([.medium]) 51 | .presentationCornerRadius(21) 52 | }) 53 | 54 | } 55 | 56 | } 57 | 58 | #Preview { 59 | ContentView() 60 | } 61 | -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons/Module/AppIconsList/View/AppIconsListView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppIconsListView.swift 3 | // ChangeAppIcons 4 | // 5 | // Created by Puneet Bhagat02 on 01/08/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct AppIconsListView: View { 11 | 12 | @AppStorage("icon") var selectedIcon: String = "chaintech-logo-01" 13 | 14 | @Environment(\.dismiss) var dismiss 15 | let animator: IconAnimatorHandler = IconAnimatorHandler() 16 | let columns = [ 17 | GridItem(.adaptive(minimum: 80)) 18 | ] 19 | 20 | 21 | var body: some View { 22 | GeometryReader(content: { geometry in 23 | VStack { 24 | 25 | Text("App icons") 26 | .font(.system(size: 22).bold()) 27 | 28 | ScrollView(showsIndicators: false) { 29 | 30 | LazyVGrid(columns: columns, spacing: 20) { 31 | ForEach(0.. Void)? = nil 41 | 42 | /// Whether or not this animation has been cancelled 43 | private var isCancelled = false 44 | 45 | init(numberOfFrames: Int, 46 | numberOfLoops: Int = 1, 47 | iconsList:[String], 48 | targetFramesPerSecond: CGFloat = 30, 49 | shouldRunOnMainThread: Bool = false) { 50 | self.numberOfFrames = numberOfFrames 51 | self.targetFramesPerSecond = targetFramesPerSecond 52 | self.shouldRunOnMainThread = shouldRunOnMainThread 53 | self.numberOfLoops = numberOfLoops 54 | self.iconsList = iconsList 55 | } 56 | 57 | /// Starts a new app icon animation. Can be called multiple times. 58 | func startAnimation(completion: (() -> Void)? = nil) { 59 | // Set/reset properties 60 | animationStartTime = CACurrentMediaTime() 61 | currentLoopCount = 0 62 | isCancelled = false 63 | self.completion = completion 64 | 65 | // Start the animation, either using the main thread loop 66 | // or timer, depending on configuration 67 | if shouldRunOnMainThread { 68 | startAnimationOnMainThread() 69 | } else { 70 | startAnimationUsingTimer() 71 | } 72 | } 73 | 74 | /// Cancel the current animation, if any 75 | func cancel() { 76 | isCancelled = true 77 | completion?() 78 | } 79 | 80 | /// Runs the icon animation using a `CFRunLoopTimer` 81 | private func startAnimationUsingTimer() { 82 | // Calcualte the duration of each frame, in seconds 83 | let frameDuration = 1.0 / targetFramesPerSecond 84 | 85 | // Calculate the time when we should start our timer. 86 | // This is set to be halfway through the next frame interval, 87 | // so that when we try to determine what frame we're on, 88 | // we're well in the middle of a frame range 89 | let startTime = animationStartTime + (frameDuration / 2) 90 | 91 | // Create a timer to run every frame 92 | let timer = CFRunLoopTimerCreateWithHandler( 93 | /* allocator: */ kCFAllocatorDefault, 94 | /* fireDate: */ startTime, 95 | /* interval: */ frameDuration, 96 | /* flags: */ 0, 97 | /* order */ 0 98 | ) { [weak self] timer in 99 | guard let self else { 100 | return 101 | } 102 | 103 | // If our animation was cancelled, 104 | // invalidate our timer and do nothing 105 | if isCancelled { 106 | CFRunLoopTimerInvalidate(timer) 107 | } 108 | 109 | // On every frame, update our icon 110 | let shouldContinue = self.updateFrame() 111 | 112 | // If we've reached our last frame, 113 | // invalidate the timer and call our completion block 114 | if (!shouldContinue) { 115 | CFRunLoopTimerInvalidate(timer) 116 | self.completion?() 117 | } 118 | } 119 | 120 | // Start the timer 121 | CFRunLoopAddTimer(CFRunLoopGetMain(), timer, CFRunLoopMode.commonModes) 122 | } 123 | 124 | /// Runs the icon animation using a loop on the main thread 125 | /// (sometimes better performance than `startAnimationUsingTimer`, 126 | /// at the expense of not being able to do other work while animating) 127 | private func startAnimationOnMainThread() { 128 | // Calculate the duration of each frame, in seconds 129 | let frameDuration = 1.0 / targetFramesPerSecond 130 | 131 | // Store the time at which we last updated the frame 132 | // (starting with 0, meaning we're ready to show the 133 | // first frame immediately) 134 | var lastFrameTime: CFTimeInterval = 0 135 | 136 | DispatchQueue.main.async { 137 | while (true) { 138 | // If our animation has been cancelled, 139 | // break out of our loop immediately 140 | if self.isCancelled { 141 | break 142 | } 143 | 144 | // Check if it's been at least one frame 145 | // since the last time we updated our icon 146 | // (otherwise, just sleep) 147 | let currentTime = CACurrentMediaTime() 148 | if currentTime - lastFrameTime < frameDuration { 149 | Thread.sleep(forTimeInterval: 0.001) 150 | continue 151 | } 152 | 153 | // Mark the current time so that we can 154 | // figure out when we need to show the next frame 155 | lastFrameTime = currentTime 156 | 157 | // If we've reached our last frame, 158 | // call our completion block and break 159 | // out of our loop 160 | let shouldContinue = self.updateFrame() 161 | if (!shouldContinue) { 162 | self.completion?() 163 | break 164 | } 165 | } 166 | } 167 | } 168 | 169 | /** 170 | Updates the app icon based to the current frame of the animation 171 | based on the current time. 172 | 173 | - returns A boolean value indicating whether this animation still has more frames to display 174 | */ 175 | private func updateFrame() -> Bool { 176 | // Determine the frame we _should_ be showing 177 | // based on the current time. This allows the animation 178 | // to continue smoothly even if some frames are dropped 179 | let timeSinceStart = CACurrentMediaTime() - animationStartTime 180 | let currentFrame = Int(timeSinceStart * targetFramesPerSecond) % numberOfFrames 181 | 182 | // Determine the name of the icon to show 183 | let iconName = iconsList[currentFrame] 184 | // Use `LSApplicationProxy.setAlternateIconName` to update 185 | // our icon (which allows us to skip the user-facing alert 186 | // and update even when we're in the backtround) 187 | appProxy.setAlternateIconName(iconName) { success, error in 188 | if !success || error != nil { 189 | print("Error: \(error as Any)") 190 | return 191 | } 192 | } 193 | 194 | // If we've reached the end of a loop... 195 | if currentFrame == 0 { 196 | // Check if we've looped as many times as we'd like. 197 | // If so, return `false` to indicate that we're done animating 198 | if currentLoopCount == numberOfLoops { 199 | return false 200 | } 201 | currentLoopCount += 1 202 | } 203 | 204 | return true 205 | } 206 | 207 | } 208 | 209 | -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons/Module/AppIconsList/ViewModel/IconAnimatorHandler.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IconAnimatorHandler.swift 3 | // DynamicAppIcons 4 | // 5 | // Created by Puneet Bhagat02 on 01/08/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | class IconAnimatorHandler { 11 | 12 | let iconNames: [String] = 13 | [ 14 | "chaintech-logo-01", 15 | "chaintech-logo-02", 16 | "chaintech-logo-03", 17 | "chaintech-logo-04" 18 | ] 19 | 20 | // An `IconAnimator` that runs at 4fps on the main thread 21 | private let iconAnimator = IconAnimator( 22 | numberOfFrames: 4, 23 | numberOfLoops: 4, 24 | iconsList: [ 25 | "chaintech-logo-01", 26 | "chaintech-logo-02", 27 | "chaintech-logo-03", 28 | "chaintech-logo-04" 29 | ], 30 | targetFramesPerSecond: 4, 31 | shouldRunOnMainThread: true 32 | ) 33 | 34 | // A background task to keep our app alive while we're animating 35 | private var backgroundTask: UIBackgroundTaskIdentifier? = nil 36 | 37 | func performIconAnimation() { 38 | backgroundTask = UIApplication.shared.beginBackgroundTask() 39 | 40 | DispatchQueue.main.asyncAfter(deadline: .now () + .seconds(3)) { 41 | self.startAnimation() 42 | } 43 | } 44 | 45 | private func startAnimation() { 46 | // Start the animation 47 | iconAnimator.startAnimation() { [weak self] in 48 | // Once the animation is complete, 49 | // end our background task so that iOS knows 50 | // that our app has finished its work 51 | if let backgroundTask = self?.backgroundTask { 52 | UIApplication.shared.endBackgroundTask(backgroundTask) 53 | } 54 | self?.backgroundTask = nil 55 | } 56 | 57 | } 58 | 59 | 60 | func changeAppIcon(to iconName: String, callback: @escaping() -> Void) { 61 | UIApplication.shared.setAlternateIconName(iconName) { error in 62 | if let error = error { 63 | print("Error setting alternate icon \(error.localizedDescription)") 64 | } 65 | callback() 66 | } 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /DynamicAppIcons/DynamicAppIcons/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dynamic App Icon With Animation 2 | 3 | ![Hero-image - DynamicAppIconWithAnimation-git-banner](https://github.com/user-attachments/assets/f327e40c-4dc7-4322-bd71-8c48c8e2f800) 4 | 5 | # Overview 6 | 7 | In today's competitive mobile app landscape, the visual appeal of your app icon can make all the difference. With the ability to add dynamic app icons in iOS, you can take it a step further by incorporating animations and interactivity. This project demonstrates how to implement dynamic app icons with animations, allowing your app to stand out and convey its personality. 8 | 9 | # Features 10 | 11 | * Dynamic app icons 12 | * Customizable animations for icons 13 | 14 | ## Getting Started 15 | 16 | To Get started with this project, follow these steps: 17 | 18 | 1. **Clone the repository**: 19 | 20 | ```bash 21 | git clone https://github.com/Chaintech-Network/Dynamic_App_Icon_With_Animation_ios 22 | ``` 23 | 24 | 2. **Open the project** in Xcode. 25 | 26 | 3. **Build and run** the project on the simulator or a real device. 27 | 28 | ## Video Demonstration 29 | 30 | For the visual walkthrough of the project and its features, chack out the attached video demonstration: 31 | 32 | [**Video**](https://github.com/user-attachments/assets/9ac136ca-39aa-44a7-8af7-593b44c42cc2) 33 | 34 | ## Requirements 35 | 36 | - iOS 17.0+ 37 | - Xcode 15.0+ 38 | - Swift 5.0+ 39 | 40 | 41 | ## 📖 Detailed Explanation 42 | For an in-depth guide and detailed explanation, check out our comprehensive Medium Blog Post. 43 | 44 | [![Medium](https://img.shields.io/badge/Medium-12100E?style=for-the-badge&logo=medium&logoColor=white)](https://medium.com/mobile-innovation-network/dynamic-app-icon-with-animation-afacb2403a45) 45 | [![LinkedIn](https://img.shields.io/badge/LinkedIn-0077B5?style=for-the-badge&logo=linkedin&logoColor=white)](https://www.linkedin.com/showcase/mobile-innovation-network) 46 | 47 | 48 | 49 | --------------------------------------------------------------------------------