├── HSLocationManager.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── hitesh.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── hitesh.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── HSLocationManager ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── Location │ ├── HSLocationManager.swift │ ├── HSLocationTracking.swift │ ├── HSLogger.swift │ └── UIApplication+Extension.swift └── ViewController.swift └── README.md /HSLocationManager.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 67B2E75A22A4DBD000F5FFAD /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B2E75922A4DBD000F5FFAD /* AppDelegate.swift */; }; 11 | 67B2E75C22A4DBD000F5FFAD /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B2E75B22A4DBD000F5FFAD /* ViewController.swift */; }; 12 | 67B2E75F22A4DBD000F5FFAD /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 67B2E75D22A4DBD000F5FFAD /* Main.storyboard */; }; 13 | 67B2E76122A4DBD100F5FFAD /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 67B2E76022A4DBD100F5FFAD /* Assets.xcassets */; }; 14 | 67B2E76422A4DBD100F5FFAD /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 67B2E76222A4DBD100F5FFAD /* LaunchScreen.storyboard */; }; 15 | 67B2E76D22A4DBEF00F5FFAD /* HSLocationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B2E76C22A4DBEF00F5FFAD /* HSLocationManager.swift */; }; 16 | 67B2E76F22A4DDAD00F5FFAD /* HSLocationTracking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B2E76E22A4DDAD00F5FFAD /* HSLocationTracking.swift */; }; 17 | 67B2E77122A4DECF00F5FFAD /* HSLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B2E77022A4DECF00F5FFAD /* HSLogger.swift */; }; 18 | 67B2E77322A4DF6600F5FFAD /* UIApplication+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B2E77222A4DF6600F5FFAD /* UIApplication+Extension.swift */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXFileReference section */ 22 | 67B2E75622A4DBD000F5FFAD /* HSLocationManager.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HSLocationManager.app; sourceTree = BUILT_PRODUCTS_DIR; }; 23 | 67B2E75922A4DBD000F5FFAD /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 24 | 67B2E75B22A4DBD000F5FFAD /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 25 | 67B2E75E22A4DBD000F5FFAD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 26 | 67B2E76022A4DBD100F5FFAD /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 27 | 67B2E76322A4DBD100F5FFAD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 28 | 67B2E76522A4DBD100F5FFAD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 29 | 67B2E76C22A4DBEF00F5FFAD /* HSLocationManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HSLocationManager.swift; sourceTree = ""; }; 30 | 67B2E76E22A4DDAD00F5FFAD /* HSLocationTracking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HSLocationTracking.swift; sourceTree = ""; }; 31 | 67B2E77022A4DECF00F5FFAD /* HSLogger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HSLogger.swift; sourceTree = ""; }; 32 | 67B2E77222A4DF6600F5FFAD /* UIApplication+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+Extension.swift"; sourceTree = ""; }; 33 | /* End PBXFileReference section */ 34 | 35 | /* Begin PBXFrameworksBuildPhase section */ 36 | 67B2E75322A4DBD000F5FFAD /* Frameworks */ = { 37 | isa = PBXFrameworksBuildPhase; 38 | buildActionMask = 2147483647; 39 | files = ( 40 | ); 41 | runOnlyForDeploymentPostprocessing = 0; 42 | }; 43 | /* End PBXFrameworksBuildPhase section */ 44 | 45 | /* Begin PBXGroup section */ 46 | 67B2E74D22A4DBD000F5FFAD = { 47 | isa = PBXGroup; 48 | children = ( 49 | 67B2E75822A4DBD000F5FFAD /* HSLocationManager */, 50 | 67B2E75722A4DBD000F5FFAD /* Products */, 51 | ); 52 | sourceTree = ""; 53 | }; 54 | 67B2E75722A4DBD000F5FFAD /* Products */ = { 55 | isa = PBXGroup; 56 | children = ( 57 | 67B2E75622A4DBD000F5FFAD /* HSLocationManager.app */, 58 | ); 59 | name = Products; 60 | sourceTree = ""; 61 | }; 62 | 67B2E75822A4DBD000F5FFAD /* HSLocationManager */ = { 63 | isa = PBXGroup; 64 | children = ( 65 | 67B2E75922A4DBD000F5FFAD /* AppDelegate.swift */, 66 | 67B2E75B22A4DBD000F5FFAD /* ViewController.swift */, 67 | 67B2E75D22A4DBD000F5FFAD /* Main.storyboard */, 68 | 67B2E76B22A4DBE400F5FFAD /* Location */, 69 | 67B2E76022A4DBD100F5FFAD /* Assets.xcassets */, 70 | 67B2E76222A4DBD100F5FFAD /* LaunchScreen.storyboard */, 71 | 67B2E76522A4DBD100F5FFAD /* Info.plist */, 72 | ); 73 | path = HSLocationManager; 74 | sourceTree = ""; 75 | }; 76 | 67B2E76B22A4DBE400F5FFAD /* Location */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | 67B2E76C22A4DBEF00F5FFAD /* HSLocationManager.swift */, 80 | 67B2E76E22A4DDAD00F5FFAD /* HSLocationTracking.swift */, 81 | 67B2E77022A4DECF00F5FFAD /* HSLogger.swift */, 82 | 67B2E77222A4DF6600F5FFAD /* UIApplication+Extension.swift */, 83 | ); 84 | path = Location; 85 | sourceTree = ""; 86 | }; 87 | /* End PBXGroup section */ 88 | 89 | /* Begin PBXNativeTarget section */ 90 | 67B2E75522A4DBD000F5FFAD /* HSLocationManager */ = { 91 | isa = PBXNativeTarget; 92 | buildConfigurationList = 67B2E76822A4DBD100F5FFAD /* Build configuration list for PBXNativeTarget "HSLocationManager" */; 93 | buildPhases = ( 94 | 67B2E75222A4DBD000F5FFAD /* Sources */, 95 | 67B2E75322A4DBD000F5FFAD /* Frameworks */, 96 | 67B2E75422A4DBD000F5FFAD /* Resources */, 97 | ); 98 | buildRules = ( 99 | ); 100 | dependencies = ( 101 | ); 102 | name = HSLocationManager; 103 | productName = HSLocationManager; 104 | productReference = 67B2E75622A4DBD000F5FFAD /* HSLocationManager.app */; 105 | productType = "com.apple.product-type.application"; 106 | }; 107 | /* End PBXNativeTarget section */ 108 | 109 | /* Begin PBXProject section */ 110 | 67B2E74E22A4DBD000F5FFAD /* Project object */ = { 111 | isa = PBXProject; 112 | attributes = { 113 | LastSwiftUpdateCheck = 1020; 114 | LastUpgradeCheck = 1020; 115 | ORGANIZATIONNAME = Hitesh; 116 | TargetAttributes = { 117 | 67B2E75522A4DBD000F5FFAD = { 118 | CreatedOnToolsVersion = 10.2; 119 | }; 120 | }; 121 | }; 122 | buildConfigurationList = 67B2E75122A4DBD000F5FFAD /* Build configuration list for PBXProject "HSLocationManager" */; 123 | compatibilityVersion = "Xcode 9.3"; 124 | developmentRegion = en; 125 | hasScannedForEncodings = 0; 126 | knownRegions = ( 127 | en, 128 | Base, 129 | ); 130 | mainGroup = 67B2E74D22A4DBD000F5FFAD; 131 | productRefGroup = 67B2E75722A4DBD000F5FFAD /* Products */; 132 | projectDirPath = ""; 133 | projectRoot = ""; 134 | targets = ( 135 | 67B2E75522A4DBD000F5FFAD /* HSLocationManager */, 136 | ); 137 | }; 138 | /* End PBXProject section */ 139 | 140 | /* Begin PBXResourcesBuildPhase section */ 141 | 67B2E75422A4DBD000F5FFAD /* Resources */ = { 142 | isa = PBXResourcesBuildPhase; 143 | buildActionMask = 2147483647; 144 | files = ( 145 | 67B2E76422A4DBD100F5FFAD /* LaunchScreen.storyboard in Resources */, 146 | 67B2E76122A4DBD100F5FFAD /* Assets.xcassets in Resources */, 147 | 67B2E75F22A4DBD000F5FFAD /* Main.storyboard in Resources */, 148 | ); 149 | runOnlyForDeploymentPostprocessing = 0; 150 | }; 151 | /* End PBXResourcesBuildPhase section */ 152 | 153 | /* Begin PBXSourcesBuildPhase section */ 154 | 67B2E75222A4DBD000F5FFAD /* Sources */ = { 155 | isa = PBXSourcesBuildPhase; 156 | buildActionMask = 2147483647; 157 | files = ( 158 | 67B2E77122A4DECF00F5FFAD /* HSLogger.swift in Sources */, 159 | 67B2E75C22A4DBD000F5FFAD /* ViewController.swift in Sources */, 160 | 67B2E75A22A4DBD000F5FFAD /* AppDelegate.swift in Sources */, 161 | 67B2E76F22A4DDAD00F5FFAD /* HSLocationTracking.swift in Sources */, 162 | 67B2E77322A4DF6600F5FFAD /* UIApplication+Extension.swift in Sources */, 163 | 67B2E76D22A4DBEF00F5FFAD /* HSLocationManager.swift in Sources */, 164 | ); 165 | runOnlyForDeploymentPostprocessing = 0; 166 | }; 167 | /* End PBXSourcesBuildPhase section */ 168 | 169 | /* Begin PBXVariantGroup section */ 170 | 67B2E75D22A4DBD000F5FFAD /* Main.storyboard */ = { 171 | isa = PBXVariantGroup; 172 | children = ( 173 | 67B2E75E22A4DBD000F5FFAD /* Base */, 174 | ); 175 | name = Main.storyboard; 176 | sourceTree = ""; 177 | }; 178 | 67B2E76222A4DBD100F5FFAD /* LaunchScreen.storyboard */ = { 179 | isa = PBXVariantGroup; 180 | children = ( 181 | 67B2E76322A4DBD100F5FFAD /* Base */, 182 | ); 183 | name = LaunchScreen.storyboard; 184 | sourceTree = ""; 185 | }; 186 | /* End PBXVariantGroup section */ 187 | 188 | /* Begin XCBuildConfiguration section */ 189 | 67B2E76622A4DBD100F5FFAD /* Debug */ = { 190 | isa = XCBuildConfiguration; 191 | buildSettings = { 192 | ALWAYS_SEARCH_USER_PATHS = NO; 193 | CLANG_ANALYZER_NONNULL = YES; 194 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 195 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 196 | CLANG_CXX_LIBRARY = "libc++"; 197 | CLANG_ENABLE_MODULES = YES; 198 | CLANG_ENABLE_OBJC_ARC = YES; 199 | CLANG_ENABLE_OBJC_WEAK = YES; 200 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 201 | CLANG_WARN_BOOL_CONVERSION = YES; 202 | CLANG_WARN_COMMA = YES; 203 | CLANG_WARN_CONSTANT_CONVERSION = YES; 204 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 205 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 206 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 207 | CLANG_WARN_EMPTY_BODY = YES; 208 | CLANG_WARN_ENUM_CONVERSION = YES; 209 | CLANG_WARN_INFINITE_RECURSION = YES; 210 | CLANG_WARN_INT_CONVERSION = YES; 211 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 212 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 213 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 214 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 215 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 216 | CLANG_WARN_STRICT_PROTOTYPES = YES; 217 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 218 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 219 | CLANG_WARN_UNREACHABLE_CODE = YES; 220 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 221 | CODE_SIGN_IDENTITY = "iPhone Developer"; 222 | COPY_PHASE_STRIP = NO; 223 | DEBUG_INFORMATION_FORMAT = dwarf; 224 | ENABLE_STRICT_OBJC_MSGSEND = YES; 225 | ENABLE_TESTABILITY = YES; 226 | GCC_C_LANGUAGE_STANDARD = gnu11; 227 | GCC_DYNAMIC_NO_PIC = NO; 228 | GCC_NO_COMMON_BLOCKS = YES; 229 | GCC_OPTIMIZATION_LEVEL = 0; 230 | GCC_PREPROCESSOR_DEFINITIONS = ( 231 | "DEBUG=1", 232 | "$(inherited)", 233 | ); 234 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 235 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 236 | GCC_WARN_UNDECLARED_SELECTOR = YES; 237 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 238 | GCC_WARN_UNUSED_FUNCTION = YES; 239 | GCC_WARN_UNUSED_VARIABLE = YES; 240 | IPHONEOS_DEPLOYMENT_TARGET = 12.2; 241 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 242 | MTL_FAST_MATH = YES; 243 | ONLY_ACTIVE_ARCH = YES; 244 | SDKROOT = iphoneos; 245 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 246 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 247 | }; 248 | name = Debug; 249 | }; 250 | 67B2E76722A4DBD100F5FFAD /* Release */ = { 251 | isa = XCBuildConfiguration; 252 | buildSettings = { 253 | ALWAYS_SEARCH_USER_PATHS = NO; 254 | CLANG_ANALYZER_NONNULL = YES; 255 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 256 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 257 | CLANG_CXX_LIBRARY = "libc++"; 258 | CLANG_ENABLE_MODULES = YES; 259 | CLANG_ENABLE_OBJC_ARC = YES; 260 | CLANG_ENABLE_OBJC_WEAK = YES; 261 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 262 | CLANG_WARN_BOOL_CONVERSION = YES; 263 | CLANG_WARN_COMMA = YES; 264 | CLANG_WARN_CONSTANT_CONVERSION = YES; 265 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 266 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 267 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 268 | CLANG_WARN_EMPTY_BODY = YES; 269 | CLANG_WARN_ENUM_CONVERSION = YES; 270 | CLANG_WARN_INFINITE_RECURSION = YES; 271 | CLANG_WARN_INT_CONVERSION = YES; 272 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 273 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 274 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 275 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 276 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 277 | CLANG_WARN_STRICT_PROTOTYPES = YES; 278 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 279 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 280 | CLANG_WARN_UNREACHABLE_CODE = YES; 281 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 282 | CODE_SIGN_IDENTITY = "iPhone Developer"; 283 | COPY_PHASE_STRIP = NO; 284 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 285 | ENABLE_NS_ASSERTIONS = NO; 286 | ENABLE_STRICT_OBJC_MSGSEND = YES; 287 | GCC_C_LANGUAGE_STANDARD = gnu11; 288 | GCC_NO_COMMON_BLOCKS = YES; 289 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 290 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 291 | GCC_WARN_UNDECLARED_SELECTOR = YES; 292 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 293 | GCC_WARN_UNUSED_FUNCTION = YES; 294 | GCC_WARN_UNUSED_VARIABLE = YES; 295 | IPHONEOS_DEPLOYMENT_TARGET = 12.2; 296 | MTL_ENABLE_DEBUG_INFO = NO; 297 | MTL_FAST_MATH = YES; 298 | SDKROOT = iphoneos; 299 | SWIFT_COMPILATION_MODE = wholemodule; 300 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 301 | VALIDATE_PRODUCT = YES; 302 | }; 303 | name = Release; 304 | }; 305 | 67B2E76922A4DBD100F5FFAD /* Debug */ = { 306 | isa = XCBuildConfiguration; 307 | buildSettings = { 308 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 309 | CODE_SIGN_STYLE = Automatic; 310 | INFOPLIST_FILE = HSLocationManager/Info.plist; 311 | LD_RUNPATH_SEARCH_PATHS = ( 312 | "$(inherited)", 313 | "@executable_path/Frameworks", 314 | ); 315 | PRODUCT_BUNDLE_IDENTIFIER = com.hs.HSLocationManager.HSLocationManager; 316 | PRODUCT_NAME = "$(TARGET_NAME)"; 317 | SWIFT_VERSION = 5.0; 318 | TARGETED_DEVICE_FAMILY = "1,2"; 319 | }; 320 | name = Debug; 321 | }; 322 | 67B2E76A22A4DBD100F5FFAD /* Release */ = { 323 | isa = XCBuildConfiguration; 324 | buildSettings = { 325 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 326 | CODE_SIGN_STYLE = Automatic; 327 | INFOPLIST_FILE = HSLocationManager/Info.plist; 328 | LD_RUNPATH_SEARCH_PATHS = ( 329 | "$(inherited)", 330 | "@executable_path/Frameworks", 331 | ); 332 | PRODUCT_BUNDLE_IDENTIFIER = com.hs.HSLocationManager.HSLocationManager; 333 | PRODUCT_NAME = "$(TARGET_NAME)"; 334 | SWIFT_VERSION = 5.0; 335 | TARGETED_DEVICE_FAMILY = "1,2"; 336 | }; 337 | name = Release; 338 | }; 339 | /* End XCBuildConfiguration section */ 340 | 341 | /* Begin XCConfigurationList section */ 342 | 67B2E75122A4DBD000F5FFAD /* Build configuration list for PBXProject "HSLocationManager" */ = { 343 | isa = XCConfigurationList; 344 | buildConfigurations = ( 345 | 67B2E76622A4DBD100F5FFAD /* Debug */, 346 | 67B2E76722A4DBD100F5FFAD /* Release */, 347 | ); 348 | defaultConfigurationIsVisible = 0; 349 | defaultConfigurationName = Release; 350 | }; 351 | 67B2E76822A4DBD100F5FFAD /* Build configuration list for PBXNativeTarget "HSLocationManager" */ = { 352 | isa = XCConfigurationList; 353 | buildConfigurations = ( 354 | 67B2E76922A4DBD100F5FFAD /* Debug */, 355 | 67B2E76A22A4DBD100F5FFAD /* Release */, 356 | ); 357 | defaultConfigurationIsVisible = 0; 358 | defaultConfigurationName = Release; 359 | }; 360 | /* End XCConfigurationList section */ 361 | }; 362 | rootObject = 67B2E74E22A4DBD000F5FFAD /* Project object */; 363 | } 364 | -------------------------------------------------------------------------------- /HSLocationManager.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /HSLocationManager.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /HSLocationManager.xcodeproj/project.xcworkspace/xcuserdata/hitesh.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IMHitesh/HSLocationManager/6ef81a5e554ce7f4f425588cccf26d95574811f6/HSLocationManager.xcodeproj/project.xcworkspace/xcuserdata/hitesh.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /HSLocationManager.xcodeproj/xcuserdata/hitesh.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /HSLocationManager.xcodeproj/xcuserdata/hitesh.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | HSLocationManager.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /HSLocationManager/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // HSLocationManager 4 | // 5 | // Created by Hitesh on 03/06/19. 6 | // Copyright © 2019 Hitesh. 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: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | HSLogger.logger.cleanup() 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 | -------------------------------------------------------------------------------- /HSLocationManager/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /HSLocationManager/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /HSLocationManager/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 | -------------------------------------------------------------------------------- /HSLocationManager/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 | 31 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /HSLocationManager/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 | NSLocationAlwaysAndWhenInUseUsageDescription 45 | We need to access your location to enable location tracking while traveling from one place to another and notify you to create meaningful moments for the captured locations. Don't worry, we won't drain your battery! 46 | NSLocationAlwaysUsageDescription 47 | We need to access your location to enable location tracking while traveling from one place to another and notify you to create meaningful moments for the captured locations. Don't worry, we won't drain your battery! 48 | NSLocationWhenInUseUsageDescription 49 | We need to access your location to enable location tracking while traveling from one place to another and notify you to create meaningful moments for the captured locations. Don't worry, we won't drain your battery! 50 | UIBackgroundModes 51 | 52 | location 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /HSLocationManager/Location/HSLocationManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HSLocationManager.swift 3 | // HSLocationManager 4 | // 5 | // Created by Hitesh on 03/06/19. 6 | // Copyright © 2019 Hitesh. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import CoreLocation 11 | import UIKit 12 | 13 | public protocol HSLocationManagerDelegate { 14 | 15 | func scheduledLocationManager(_ manager: HSLocationManager, didFailWithError error: Error) 16 | func scheduledLocationManager(_ manager: HSLocationManager, didUpdateLocations locations: [CLLocation]) 17 | func scheduledLocationManager(_ manager: HSLocationManager, didChangeAuthorization status: CLAuthorizationStatus) 18 | } 19 | 20 | 21 | public class HSLocationManager: NSObject, CLLocationManagerDelegate { 22 | 23 | private let MaxBGTime: TimeInterval = 170 24 | private let MinBGTime: TimeInterval = 2 25 | private let MinAcceptableLocationAccuracy: CLLocationAccuracy = 5 26 | private let WaitForLocationsTime: TimeInterval = 3 27 | 28 | private let delegate: HSLocationManagerDelegate 29 | private let manager = CLLocationManager() 30 | 31 | private var isManagerRunning = false 32 | private var checkLocationTimer: Timer? 33 | private var waitTimer: Timer? 34 | private var bgTask: UIBackgroundTaskIdentifier = UIBackgroundTaskIdentifier.invalid 35 | private var lastLocations = [CLLocation]() 36 | 37 | public private(set) var acceptableLocationAccuracy: CLLocationAccuracy = 100 38 | public private(set) var checkLocationInterval: TimeInterval = 10 39 | public private(set) var isRunning = false 40 | 41 | public init(delegate: HSLocationManagerDelegate) { 42 | self.delegate = delegate 43 | super.init() 44 | configureLocationManager() 45 | } 46 | 47 | private func configureLocationManager(){ 48 | manager.allowsBackgroundLocationUpdates = true 49 | manager.pausesLocationUpdatesAutomatically = false 50 | manager.delegate = self 51 | } 52 | 53 | public func requestAlwaysAuthorization() { 54 | manager.requestAlwaysAuthorization() 55 | } 56 | 57 | public func startUpdatingLocation(interval: TimeInterval, acceptableLocationAccuracy: CLLocationAccuracy = 100) { 58 | 59 | if isRunning { 60 | stopUpdatingLocation() 61 | } 62 | 63 | checkLocationInterval -= WaitForLocationsTime 64 | checkLocationInterval = interval > MaxBGTime ? MaxBGTime : interval 65 | checkLocationInterval = interval < MinBGTime ? MinBGTime : interval 66 | 67 | self.acceptableLocationAccuracy = acceptableLocationAccuracy < MinAcceptableLocationAccuracy ? MinAcceptableLocationAccuracy : acceptableLocationAccuracy 68 | 69 | isRunning = true 70 | 71 | addNotifications() 72 | startLocationManager() 73 | } 74 | 75 | public func stopUpdatingLocation() { 76 | isRunning = false 77 | stopWaitTimer() 78 | stopLocationManager() 79 | stopBackgroundTask() 80 | stopCheckLocationTimer() 81 | removeNotifications() 82 | } 83 | 84 | private func addNotifications() { 85 | 86 | removeNotifications() 87 | 88 | NotificationCenter.default.addObserver(self, selector: #selector(applicationDidEnterBackground), 89 | name: UIApplication.didEnterBackgroundNotification, 90 | object: nil) 91 | NotificationCenter.default.addObserver(self, selector: #selector(applicationDidBecomeActive), 92 | name: UIApplication.didBecomeActiveNotification, 93 | object: nil) 94 | } 95 | 96 | private func removeNotifications() { 97 | NotificationCenter.default.removeObserver(self) 98 | } 99 | 100 | private func startLocationManager() { 101 | isManagerRunning = true 102 | manager.desiredAccuracy = kCLLocationAccuracyBestForNavigation 103 | manager.distanceFilter = 5 104 | manager.startUpdatingLocation() 105 | } 106 | 107 | private func pauseLocationManager(){ 108 | manager.desiredAccuracy = kCLLocationAccuracyThreeKilometers 109 | manager.distanceFilter = 99999 110 | } 111 | private func stopLocationManager() { 112 | isManagerRunning = false 113 | manager.stopUpdatingLocation() 114 | } 115 | 116 | @objc func applicationDidEnterBackground() { 117 | stopBackgroundTask() 118 | startBackgroundTask() 119 | } 120 | 121 | @objc func applicationDidBecomeActive() { 122 | stopBackgroundTask() 123 | } 124 | 125 | public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { 126 | delegate.scheduledLocationManager(self, didChangeAuthorization: status) 127 | } 128 | 129 | public func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { 130 | delegate.scheduledLocationManager(self, didFailWithError: error) 131 | } 132 | 133 | public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { 134 | 135 | guard isManagerRunning else { return } 136 | guard locations.count>0 else { return } 137 | 138 | lastLocations = locations 139 | 140 | if waitTimer == nil { 141 | startWaitTimer() 142 | } 143 | } 144 | 145 | private func startCheckLocationTimer() { 146 | 147 | stopCheckLocationTimer() 148 | 149 | checkLocationTimer = Timer.scheduledTimer(timeInterval: checkLocationInterval, target: self, selector: #selector(checkLocationTimerEvent), userInfo: nil, repeats: false) 150 | } 151 | 152 | private func stopCheckLocationTimer() { 153 | if let timer = checkLocationTimer { 154 | timer.invalidate() 155 | checkLocationTimer=nil 156 | } 157 | } 158 | 159 | @objc func checkLocationTimerEvent() { 160 | stopCheckLocationTimer() 161 | startLocationManager() 162 | 163 | // starting from iOS 7 and above stop background task with delay, otherwise location service won't start 164 | self.perform(#selector(stopAndResetBgTaskIfNeeded), with: nil, afterDelay: 1) 165 | } 166 | 167 | private func startWaitTimer() { 168 | stopWaitTimer() 169 | 170 | waitTimer = Timer.scheduledTimer(timeInterval: WaitForLocationsTime, target: self, selector: #selector(waitTimerEvent), userInfo: nil, repeats: false) 171 | } 172 | 173 | private func stopWaitTimer() { 174 | 175 | if let timer = waitTimer { 176 | 177 | timer.invalidate() 178 | waitTimer=nil 179 | } 180 | } 181 | 182 | @objc func waitTimerEvent() { 183 | 184 | stopWaitTimer() 185 | 186 | if acceptableLocationAccuracyRetrieved() { 187 | startBackgroundTask() 188 | startCheckLocationTimer() 189 | pauseLocationManager() 190 | delegate.scheduledLocationManager(self, didUpdateLocations: lastLocations) 191 | }else{ 192 | startWaitTimer() 193 | } 194 | } 195 | 196 | private func acceptableLocationAccuracyRetrieved() -> Bool { 197 | let location = lastLocations.last! 198 | return location.horizontalAccuracy <= acceptableLocationAccuracy ? true : false 199 | } 200 | 201 | @objc func stopAndResetBgTaskIfNeeded() { 202 | 203 | if isManagerRunning { 204 | stopBackgroundTask() 205 | }else{ 206 | stopBackgroundTask() 207 | startBackgroundTask() 208 | } 209 | } 210 | 211 | private func startBackgroundTask() { 212 | let state = UIApplication.shared.applicationState 213 | 214 | if ((state == .background || state == .inactive) && bgTask == UIBackgroundTaskIdentifier.invalid) { 215 | bgTask = UIApplication.shared.beginBackgroundTask(expirationHandler: { 216 | self.checkLocationTimerEvent() 217 | }) 218 | } 219 | } 220 | 221 | @objc private func stopBackgroundTask() { 222 | guard bgTask != UIBackgroundTaskIdentifier.invalid else { return } 223 | UIApplication.shared.endBackgroundTask(bgTask) 224 | bgTask = UIBackgroundTaskIdentifier.invalid 225 | } 226 | } 227 | 228 | -------------------------------------------------------------------------------- /HSLocationManager/Location/HSLocationTracking.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HSLocationTracking.swift 3 | // HSLocationManager 4 | // 5 | // Created by Hitesh on 03/06/19. 6 | // Copyright © 2019 Hitesh. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import CoreLocation 11 | import UIKit 12 | 13 | class HSLocationTracking: NSObject { 14 | 15 | //Constant 16 | static let timeInternal = 30 17 | static let accuracy = 200 18 | 19 | 20 | var manager: HSLocationManager! 21 | var statusCheckedOnce = false 22 | private static var privateShared : HSLocationTracking? 23 | 24 | override init() { 25 | super.init() 26 | manager = HSLocationManager(delegate: self) 27 | } 28 | 29 | 30 | class func shared() -> HSLocationTracking { 31 | guard let uwShared = privateShared else { 32 | privateShared = HSLocationTracking() 33 | return privateShared! 34 | } 35 | return uwShared 36 | } 37 | 38 | class func destroy() { 39 | privateShared = nil 40 | } 41 | 42 | 43 | func isLocationServiceEnable()->Bool{ 44 | if CLLocationManager.authorizationStatus() == .denied{ 45 | // showLocationAlert() 46 | return false 47 | }else{ 48 | return true 49 | } 50 | } 51 | 52 | 53 | func showLocationAlert(){ 54 | print("Please enalble location service") 55 | } 56 | 57 | func startLocationTracking(){ 58 | if CLLocationManager.authorizationStatus() == .authorizedAlways || CLLocationManager.authorizationStatus() == .authorizedWhenInUse{ 59 | manager.startUpdatingLocation(interval: 30, acceptableLocationAccuracy: 200) 60 | }else if CLLocationManager.authorizationStatus() == .denied{ 61 | logh("Location service is disable") 62 | }else{ 63 | manager.requestAlwaysAuthorization() 64 | } 65 | } 66 | 67 | func stopLocationTracking(){ 68 | manager.stopUpdatingLocation() 69 | } 70 | } 71 | 72 | 73 | extension HSLocationTracking:HSLocationManagerDelegate{ 74 | 75 | func scheduledLocationManager(_ manager: HSLocationManager, didUpdateLocations locations: [CLLocation]) { 76 | let recentLocation = locations.last! 77 | logh("Location retrive successfully:\(recentLocation.debugDescription)") 78 | } 79 | 80 | func scheduledLocationManager(_ manager: HSLocationManager, didFailWithError error: Error) { 81 | logh("Location Error \(error.localizedDescription)") 82 | } 83 | 84 | func scheduledLocationManager(_ manager: HSLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { 85 | if CLLocationManager.authorizationStatus() == .denied{ 86 | logh("Location service is disable...") 87 | }else{ 88 | startLocationTracking() 89 | } 90 | } 91 | 92 | 93 | } 94 | -------------------------------------------------------------------------------- /HSLocationManager/Location/HSLogger.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HSLogger.swift 3 | // HSLocationManager 4 | // 5 | // Created by Hitesh on 03/06/19. 6 | // Copyright © 2019 Hitesh. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | open class HSLogger:NSObject,UIDocumentInteractionControllerDelegate { 13 | 14 | ///The max size a log file can be in Kilobytes. Default is 1024 (1 MB) 15 | open var maxFileSize: UInt64 = 2048 16 | 17 | ///The max number of log file that will be stored. Once this point is reached, the oldest file is deleted. 18 | open var maxFileCount = 8 19 | 20 | ///The directory in which the log files will be written 21 | open var directory = HSLogger.defaultDirectory() { 22 | didSet { 23 | directory = NSString(string: directory).expandingTildeInPath 24 | 25 | let fileManager = FileManager.default 26 | if !fileManager.fileExists(atPath: directory) { 27 | do { 28 | try fileManager.createDirectory(atPath: directory, withIntermediateDirectories: true, attributes: nil) 29 | } catch { 30 | NSLog("Couldn't create directory at \(directory)") 31 | } 32 | } 33 | } 34 | } 35 | 36 | open var currentPath: String { 37 | return "\(directory)/\(logName(0))" 38 | } 39 | 40 | ///The name of the log files 41 | open var name = "logfile" 42 | 43 | ///Whether or not logging also prints to the console 44 | open var printToConsole = true 45 | 46 | ///logging singleton 47 | open class var logger: HSLogger { 48 | 49 | struct Static { 50 | static let instance: HSLogger = HSLogger() 51 | } 52 | return Static.instance 53 | } 54 | //the date formatter 55 | var dateFormatter: DateFormatter { 56 | let formatter = DateFormatter() 57 | formatter.timeStyle = .medium 58 | formatter.dateStyle = .medium 59 | return formatter 60 | } 61 | 62 | open func exportLogFile(){ 63 | 64 | let url = NSURL.fileURL(withPath:currentPath) 65 | let docController = UIDocumentInteractionController(url:url ) 66 | docController.uti = "public.comma-separated-values-text" 67 | docController.delegate = self 68 | docController.presentPreview(animated: true) 69 | 70 | } 71 | 72 | public func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController{ 73 | return UIApplication.topViewController()! 74 | } 75 | 76 | ///write content to the current log file. 77 | open func write(_ text: String) { 78 | let path = currentPath 79 | let fileManager = FileManager.default 80 | if !fileManager.fileExists(atPath: path) { 81 | do { 82 | try "".write(toFile: path, atomically: true, encoding: String.Encoding.utf8) 83 | } catch _ { 84 | } 85 | } 86 | if let fileHandle = FileHandle(forWritingAtPath: path) { 87 | let dateStr = dateFormatter.string(from: Date()) 88 | let writeText = "[\(dateStr)]: \(text)\n" 89 | fileHandle.seekToEndOfFile() 90 | fileHandle.write(writeText.data(using: String.Encoding.utf8)!) 91 | fileHandle.closeFile() 92 | if printToConsole { 93 | print(writeText, terminator: "") 94 | } 95 | cleanup() 96 | } 97 | } 98 | ///do the checks and cleanup 99 | func cleanup() { 100 | let path = "\(directory)/\(logName(0))" 101 | let size = fileSize(path) 102 | let maxSize: UInt64 = maxFileSize*1024 103 | if size > 0 && size >= maxSize && maxSize > 0 && maxFileCount > 0 { 104 | rename(0) 105 | //delete the oldest file 106 | let deletePath = "\(directory)/\(logName(maxFileCount))" 107 | let fileManager = FileManager.default 108 | do { 109 | try fileManager.removeItem(atPath: deletePath) 110 | } catch _ { 111 | } 112 | } 113 | } 114 | 115 | ///check the size of a file 116 | func fileSize(_ path: String) -> UInt64 { 117 | let fileManager = FileManager.default 118 | let attrs: NSDictionary? = try? fileManager.attributesOfItem(atPath: path) as NSDictionary 119 | if let dict = attrs { 120 | return dict.fileSize() 121 | } 122 | return 0 123 | } 124 | 125 | ///Recursive method call to rename log files 126 | func rename(_ index: Int) { 127 | let fileManager = FileManager.default 128 | let path = "\(directory)/\(logName(index))" 129 | let newPath = "\(directory)/\(logName(index+1))" 130 | if fileManager.fileExists(atPath: newPath) { 131 | rename(index+1) 132 | } 133 | do { 134 | try fileManager.moveItem(atPath: path, toPath: newPath) 135 | } catch _ { 136 | } 137 | } 138 | 139 | ///gets the log name 140 | func logName(_ num :Int) -> String { 141 | return "\(name)-\(num).log" 142 | } 143 | 144 | ///get the default log directory 145 | class func defaultDirectory() -> String { 146 | var path = "" 147 | let fileManager = FileManager.default 148 | #if os(iOS) 149 | let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true) 150 | path = "\(paths[0])/Logs" 151 | #elseif os(macOS) 152 | let urls = fileManager.urls(for: .libraryDirectory, in: .userDomainMask) 153 | if let url = urls.last { 154 | path = "\(url.path)/Logs" 155 | } 156 | #endif 157 | if !fileManager.fileExists(atPath: path) && path != "" { 158 | do { 159 | try fileManager.createDirectory(atPath: path, withIntermediateDirectories: false, attributes: nil) 160 | } catch _ { 161 | } 162 | } 163 | return path 164 | } 165 | 166 | } 167 | 168 | ///Writes content to the current log file 169 | public func logh(_ text: String) { 170 | HSLogger.logger.write(text) 171 | } 172 | -------------------------------------------------------------------------------- /HSLocationManager/Location/UIApplication+Extension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UIApplication+Extension.swift 3 | // HSLocationManager 4 | // 5 | // Created by Hitesh on 03/06/19. 6 | // Copyright © 2019 Hitesh. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import UIKit 11 | 12 | extension UIApplication { 13 | 14 | class func topViewController(_ viewController: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? { 15 | if let nav = viewController as? UINavigationController { 16 | return topViewController(nav.visibleViewController) 17 | } 18 | if let tab = viewController as? UITabBarController { 19 | if let selected = tab.selectedViewController { 20 | return topViewController(selected) 21 | } 22 | } 23 | if let presented = viewController?.presentedViewController { 24 | return topViewController(presented) 25 | } 26 | 27 | 28 | return viewController 29 | } 30 | 31 | class func topNavigation(_ viewController: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UINavigationController? { 32 | 33 | if let nav = viewController as? UINavigationController { 34 | return nav 35 | } 36 | if let tab = viewController as? UITabBarController { 37 | if let selected = tab.selectedViewController { 38 | return selected.navigationController 39 | } 40 | } 41 | if let presented = viewController?.presentedViewController { 42 | return topNavigation(presented) 43 | } 44 | 45 | 46 | return viewController?.navigationController 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /HSLocationManager/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // HSLocationManager 4 | // 5 | // Created by Hitesh on 03/06/19. 6 | // Copyright © 2019 Hitesh. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | } 16 | 17 | 18 | @IBAction func exportLogFile(){ 19 | HSLogger.logger.exportLogFile() 20 | } 21 | 22 | @IBAction func startTracking(sender:UIButton){ 23 | if sender.isSelected{ 24 | HSLocationTracking.shared().stopLocationTracking() 25 | }else{ 26 | HSLocationTracking.shared().startLocationTracking() 27 | } 28 | sender.isSelected = !sender.isSelected 29 | } 30 | } 31 | 32 | 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HSLocationManager 2 | 3 | Location manager that allows to get background location updates every n seconds with desired location accuracy. 4 | 5 | **Advantage:** 6 | 7 | - OS will never kill our app if the location manager is currently running. 8 | 9 | - Give periodically location update when it required(range is between 2 - 170 seconds (limited by max allowed background task time)) 10 | 11 | - Customizable location accuracy and time period. 12 | 13 | - Low memory consumption(Singleton class) 14 | 15 | 16 | Default time to retrive location is 30 sec and accuracy is 200. 17 | 18 | static let timeInternal = 30 19 | static let accuracy = 200 20 | 21 | # Usage 22 | Configure Xcode project 23 | 24 | - In target Capabilities enable Background Modes and check Location updates 25 | 26 | - In Info.plist add 27 | 28 | Privacy - Location Always and When In Use Usage Description 29 | 30 | Privacy - Location Always Usage Description 31 | 32 | Privacy - Location When In Use Usage Description 33 | 34 | - key and value that will specify the reason for your app to access the user’s location information at all times. 35 | 36 | 37 | Now, Add location folder into your project. 38 | 39 | # Start Location tracking: 40 | 41 | HSLocationTracking.shared().startLocationTracking() 42 | 43 | **This method is called in every 30 sec if location is available with specified accuracy(static let timeInternal = 30)** 44 | 45 | func scheduledLocationManager(_ manager: HSLocationManager, didUpdateLocations locations: [CLLocation]) { 46 | } 47 | 48 | # Other: 49 | You can able to see location log by using 50 | 51 | HSLogger.logger.exportLogFile() 52 | 53 | # See an example app HSLocationManager in the repository 54 | 55 | Note, if you test on a stimulater edit scheme and set default location. 56 | 57 | 58 | # Raise issue if you are found or ask your queries or concern anytime: 59 | 60 | Stack overflow: https://stackoverflow.com/users/5036586/imhitesh-surani 61 | 62 | LinkedIn: https://www.linkedin.com/in/hiteshsurani/ 63 | 64 | Email: hiteshsurani314@gmail.com 65 | --------------------------------------------------------------------------------