├── .gitignore ├── .swift-version ├── .travis.yml ├── CHANGELOG.md ├── IGZLocation.podspec ├── IGZLocation.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── IGZLocation.xcscheme │ └── IGZLocationMap.xcscheme ├── IGZLocation ├── IGZLocation.h ├── IGZLocation.swift ├── IGZLocationDelegate.swift ├── IGZLocationError.swift ├── IGZLocationHandlers.swift ├── IGZLocationManager.swift ├── IGZLocationManagerDelegate.swift ├── IGZLocationManagerExtension.swift ├── IGZLocationNotifications.swift └── Info.plist ├── IGZLocationMap ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist └── ViewController.swift ├── IGZLocationMapUITests ├── IGZLocationMapUITests.swift └── Info.plist ├── IGZLocationTests ├── IGZLocationTests.swift └── Info.plist ├── LICENSE ├── Package.swift ├── README.md ├── _config.yml └── screenshot.gif /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xcuserstate 23 | 24 | ## Obj-C/Swift specific 25 | *.hmap 26 | *.ipa 27 | *.dSYM.zip 28 | *.dSYM 29 | 30 | ## Playgrounds 31 | timeline.xctimeline 32 | playground.xcworkspace 33 | 34 | # Swift Package Manager 35 | # 36 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 37 | # Packages/ 38 | .build/ 39 | 40 | # CocoaPods 41 | # 42 | # We recommend against adding the Pods directory to your .gitignore. However 43 | # you should judge for yourself, the pros and cons are mentioned at: 44 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 45 | # 46 | # Pods/ 47 | 48 | # Carthage 49 | # 50 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 51 | # Carthage/Checkouts 52 | 53 | Carthage/Build 54 | 55 | # fastlane 56 | # 57 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 58 | # screenshots whenever they are needed. 59 | # For more information about the recommended setup visit: 60 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 61 | 62 | fastlane/report.xml 63 | fastlane/Preview.html 64 | fastlane/screenshots 65 | fastlane/test_output -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 4.0 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: swift 2 | osx_image: xcode9 3 | script: 4 | - xcodebuild -project IGZLocation.xcodeproj -scheme IGZLocation -destination "platform=iOS 5 | Simulator,name=iPhone 7,OS=11.0" -configuration Debug -enableCodeCoverage YES clean 6 | build test 7 | after_success: 8 | - bash <(curl -s https://codecov.io/bash) 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ### IGZLocation 1.1.0 2 | 3 | * Swift 4.0 4 | 5 | ### IGZLocation 1.0.4 6 | 7 | * Compatible with Swift Package Manager. 8 | * Everything public becomes open. 9 | 10 | ### IGZLocation 1.0.3 11 | 12 | * IGZLocationNotifications deprecated, use NSNotification.Name extension instead. 13 | -------------------------------------------------------------------------------- /IGZLocation.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | 3 | s.name = "IGZLocation" 4 | s.version = "1.1.0" 5 | s.summary = "CLLocationManager Swift 4 wrapper with multiple closure handlers and delegates allowed, notifications, sequential geofencing, self-authorization and, of course, everything is testable. #InCodeWeTrust" 6 | s.description = <<-DESC 7 | # IGZLocation 8 | CLLocationManager Swift 4 wrapper with multiple closure handlers and delegates allowed, notifications, sequential geofencing, self-authorization and, of course, everything is testable. #InCodeWeTrust 9 | DESC 10 | 11 | s.homepage = "https://github.com/intelygenz/IGZLocation" 12 | s.screenshots = "https://raw.githubusercontent.com/intelygenz/IGZLocation/master/screenshot.gif" 13 | s.license = "MIT" 14 | 15 | s.authors = { "Alex Rupérez" => "alejandro.ruperez@intelygenz.com" } 16 | s.social_media_url = "http://twitter.com/intelygenz" 17 | 18 | s.platform = :ios, "8.0" 19 | s.source = { :git => "https://github.com/intelygenz/IGZLocation.git", :tag => "#{s.version}" } 20 | 21 | s.source_files = "IGZLocation/*.swift" 22 | s.frameworks = "Foundation", "CoreLocation" 23 | 24 | end -------------------------------------------------------------------------------- /IGZLocation.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 8159B42A1E43378400D0D587 /* IGZLocationHandlers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8159B4291E43378400D0D587 /* IGZLocationHandlers.swift */; }; 11 | 8159B42C1E4337A900D0D587 /* IGZLocationNotifications.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8159B42B1E4337A900D0D587 /* IGZLocationNotifications.swift */; }; 12 | 8159B42E1E4337D100D0D587 /* IGZLocationManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8159B42D1E4337D100D0D587 /* IGZLocationManager.swift */; }; 13 | 8159B4301E4337F300D0D587 /* IGZLocationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8159B42F1E4337F300D0D587 /* IGZLocationDelegate.swift */; }; 14 | 8159B4321E43382300D0D587 /* IGZLocationError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8159B4311E43382300D0D587 /* IGZLocationError.swift */; }; 15 | 8159B4341E43389A00D0D587 /* IGZLocationManagerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8159B4331E43389A00D0D587 /* IGZLocationManagerDelegate.swift */; }; 16 | 8159B4361E4339C600D0D587 /* IGZLocationManagerExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8159B4351E4339C600D0D587 /* IGZLocationManagerExtension.swift */; }; 17 | 8159B43E1E447F3C00D0D587 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8159B43D1E447F3C00D0D587 /* AppDelegate.swift */; }; 18 | 8159B4401E447F3D00D0D587 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8159B43F1E447F3C00D0D587 /* ViewController.swift */; }; 19 | 8159B4431E447F3D00D0D587 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8159B4411E447F3D00D0D587 /* Main.storyboard */; }; 20 | 8159B4451E447F3D00D0D587 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8159B4441E447F3D00D0D587 /* Assets.xcassets */; }; 21 | 8159B4481E447F3D00D0D587 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8159B4461E447F3D00D0D587 /* LaunchScreen.storyboard */; }; 22 | 8159B4531E447F3D00D0D587 /* IGZLocationMapUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8159B4521E447F3D00D0D587 /* IGZLocationMapUITests.swift */; }; 23 | 8159B45B1E447F7700D0D587 /* IGZLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 81925D161E40AA78001701F3 /* IGZLocation.framework */; }; 24 | 8159B45C1E447F7700D0D587 /* IGZLocation.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 81925D161E40AA78001701F3 /* IGZLocation.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 25 | 81925D201E40AA78001701F3 /* IGZLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 81925D161E40AA78001701F3 /* IGZLocation.framework */; }; 26 | 81925D251E40AA78001701F3 /* IGZLocationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81925D241E40AA78001701F3 /* IGZLocationTests.swift */; }; 27 | 81925D271E40AA78001701F3 /* IGZLocation.h in Headers */ = {isa = PBXBuildFile; fileRef = 81925D191E40AA78001701F3 /* IGZLocation.h */; settings = {ATTRIBUTES = (Public, ); }; }; 28 | 81925D311E40AB25001701F3 /* IGZLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81925D301E40AB25001701F3 /* IGZLocation.swift */; }; 29 | /* End PBXBuildFile section */ 30 | 31 | /* Begin PBXContainerItemProxy section */ 32 | 8159B44F1E447F3D00D0D587 /* PBXContainerItemProxy */ = { 33 | isa = PBXContainerItemProxy; 34 | containerPortal = 81925D0D1E40AA78001701F3 /* Project object */; 35 | proxyType = 1; 36 | remoteGlobalIDString = 8159B43A1E447F3C00D0D587; 37 | remoteInfo = IGZLocationMap; 38 | }; 39 | 8159B45D1E447F7700D0D587 /* PBXContainerItemProxy */ = { 40 | isa = PBXContainerItemProxy; 41 | containerPortal = 81925D0D1E40AA78001701F3 /* Project object */; 42 | proxyType = 1; 43 | remoteGlobalIDString = 81925D151E40AA78001701F3; 44 | remoteInfo = IGZLocation; 45 | }; 46 | 81925D211E40AA78001701F3 /* PBXContainerItemProxy */ = { 47 | isa = PBXContainerItemProxy; 48 | containerPortal = 81925D0D1E40AA78001701F3 /* Project object */; 49 | proxyType = 1; 50 | remoteGlobalIDString = 81925D151E40AA78001701F3; 51 | remoteInfo = IGZLocation; 52 | }; 53 | /* End PBXContainerItemProxy section */ 54 | 55 | /* Begin PBXCopyFilesBuildPhase section */ 56 | 8159B45F1E447F7700D0D587 /* Embed Frameworks */ = { 57 | isa = PBXCopyFilesBuildPhase; 58 | buildActionMask = 2147483647; 59 | dstPath = ""; 60 | dstSubfolderSpec = 10; 61 | files = ( 62 | 8159B45C1E447F7700D0D587 /* IGZLocation.framework in Embed Frameworks */, 63 | ); 64 | name = "Embed Frameworks"; 65 | runOnlyForDeploymentPostprocessing = 0; 66 | }; 67 | /* End PBXCopyFilesBuildPhase section */ 68 | 69 | /* Begin PBXFileReference section */ 70 | 8159B4291E43378400D0D587 /* IGZLocationHandlers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = IGZLocationHandlers.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 71 | 8159B42B1E4337A900D0D587 /* IGZLocationNotifications.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IGZLocationNotifications.swift; sourceTree = ""; }; 72 | 8159B42D1E4337D100D0D587 /* IGZLocationManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = IGZLocationManager.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 73 | 8159B42F1E4337F300D0D587 /* IGZLocationDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = IGZLocationDelegate.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 74 | 8159B4311E43382300D0D587 /* IGZLocationError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = IGZLocationError.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 75 | 8159B4331E43389A00D0D587 /* IGZLocationManagerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = IGZLocationManagerDelegate.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 76 | 8159B4351E4339C600D0D587 /* IGZLocationManagerExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IGZLocationManagerExtension.swift; sourceTree = ""; }; 77 | 8159B43B1E447F3C00D0D587 /* IGZLocationMap.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = IGZLocationMap.app; sourceTree = BUILT_PRODUCTS_DIR; }; 78 | 8159B43D1E447F3C00D0D587 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 79 | 8159B43F1E447F3C00D0D587 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 80 | 8159B4421E447F3D00D0D587 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 81 | 8159B4441E447F3D00D0D587 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 82 | 8159B4471E447F3D00D0D587 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 83 | 8159B4491E447F3D00D0D587 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 84 | 8159B44E1E447F3D00D0D587 /* IGZLocationMapUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = IGZLocationMapUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 85 | 8159B4521E447F3D00D0D587 /* IGZLocationMapUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IGZLocationMapUITests.swift; sourceTree = ""; }; 86 | 8159B4541E447F3D00D0D587 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 87 | 81925D161E40AA78001701F3 /* IGZLocation.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = IGZLocation.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 88 | 81925D191E40AA78001701F3 /* IGZLocation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = IGZLocation.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 89 | 81925D1A1E40AA78001701F3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 90 | 81925D1F1E40AA78001701F3 /* IGZLocationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = IGZLocationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 91 | 81925D241E40AA78001701F3 /* IGZLocationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IGZLocationTests.swift; sourceTree = ""; }; 92 | 81925D261E40AA78001701F3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 93 | 81925D301E40AB25001701F3 /* IGZLocation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = IGZLocation.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; 94 | /* End PBXFileReference section */ 95 | 96 | /* Begin PBXFrameworksBuildPhase section */ 97 | 8159B4381E447F3C00D0D587 /* Frameworks */ = { 98 | isa = PBXFrameworksBuildPhase; 99 | buildActionMask = 2147483647; 100 | files = ( 101 | 8159B45B1E447F7700D0D587 /* IGZLocation.framework in Frameworks */, 102 | ); 103 | runOnlyForDeploymentPostprocessing = 0; 104 | }; 105 | 8159B44B1E447F3D00D0D587 /* Frameworks */ = { 106 | isa = PBXFrameworksBuildPhase; 107 | buildActionMask = 2147483647; 108 | files = ( 109 | ); 110 | runOnlyForDeploymentPostprocessing = 0; 111 | }; 112 | 81925D121E40AA78001701F3 /* Frameworks */ = { 113 | isa = PBXFrameworksBuildPhase; 114 | buildActionMask = 2147483647; 115 | files = ( 116 | ); 117 | runOnlyForDeploymentPostprocessing = 0; 118 | }; 119 | 81925D1C1E40AA78001701F3 /* Frameworks */ = { 120 | isa = PBXFrameworksBuildPhase; 121 | buildActionMask = 2147483647; 122 | files = ( 123 | 81925D201E40AA78001701F3 /* IGZLocation.framework in Frameworks */, 124 | ); 125 | runOnlyForDeploymentPostprocessing = 0; 126 | }; 127 | /* End PBXFrameworksBuildPhase section */ 128 | 129 | /* Begin PBXGroup section */ 130 | 8159B43C1E447F3C00D0D587 /* IGZLocationMap */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | 8159B43D1E447F3C00D0D587 /* AppDelegate.swift */, 134 | 8159B43F1E447F3C00D0D587 /* ViewController.swift */, 135 | 8159B4411E447F3D00D0D587 /* Main.storyboard */, 136 | 8159B4441E447F3D00D0D587 /* Assets.xcassets */, 137 | 8159B4461E447F3D00D0D587 /* LaunchScreen.storyboard */, 138 | 8159B4491E447F3D00D0D587 /* Info.plist */, 139 | ); 140 | path = IGZLocationMap; 141 | sourceTree = ""; 142 | }; 143 | 8159B4511E447F3D00D0D587 /* IGZLocationMapUITests */ = { 144 | isa = PBXGroup; 145 | children = ( 146 | 8159B4521E447F3D00D0D587 /* IGZLocationMapUITests.swift */, 147 | 8159B4541E447F3D00D0D587 /* Info.plist */, 148 | ); 149 | path = IGZLocationMapUITests; 150 | sourceTree = ""; 151 | }; 152 | 81925D0C1E40AA78001701F3 = { 153 | isa = PBXGroup; 154 | children = ( 155 | 81925D181E40AA78001701F3 /* IGZLocation */, 156 | 81925D231E40AA78001701F3 /* IGZLocationTests */, 157 | 8159B43C1E447F3C00D0D587 /* IGZLocationMap */, 158 | 8159B4511E447F3D00D0D587 /* IGZLocationMapUITests */, 159 | 81925D171E40AA78001701F3 /* Products */, 160 | ); 161 | sourceTree = ""; 162 | }; 163 | 81925D171E40AA78001701F3 /* Products */ = { 164 | isa = PBXGroup; 165 | children = ( 166 | 81925D161E40AA78001701F3 /* IGZLocation.framework */, 167 | 81925D1F1E40AA78001701F3 /* IGZLocationTests.xctest */, 168 | 8159B43B1E447F3C00D0D587 /* IGZLocationMap.app */, 169 | 8159B44E1E447F3D00D0D587 /* IGZLocationMapUITests.xctest */, 170 | ); 171 | name = Products; 172 | sourceTree = ""; 173 | }; 174 | 81925D181E40AA78001701F3 /* IGZLocation */ = { 175 | isa = PBXGroup; 176 | children = ( 177 | 81925D1A1E40AA78001701F3 /* Info.plist */, 178 | 81925D191E40AA78001701F3 /* IGZLocation.h */, 179 | 81925D301E40AB25001701F3 /* IGZLocation.swift */, 180 | 8159B42D1E4337D100D0D587 /* IGZLocationManager.swift */, 181 | 8159B4351E4339C600D0D587 /* IGZLocationManagerExtension.swift */, 182 | 8159B4331E43389A00D0D587 /* IGZLocationManagerDelegate.swift */, 183 | 8159B4291E43378400D0D587 /* IGZLocationHandlers.swift */, 184 | 8159B42B1E4337A900D0D587 /* IGZLocationNotifications.swift */, 185 | 8159B42F1E4337F300D0D587 /* IGZLocationDelegate.swift */, 186 | 8159B4311E43382300D0D587 /* IGZLocationError.swift */, 187 | ); 188 | path = IGZLocation; 189 | sourceTree = ""; 190 | }; 191 | 81925D231E40AA78001701F3 /* IGZLocationTests */ = { 192 | isa = PBXGroup; 193 | children = ( 194 | 81925D241E40AA78001701F3 /* IGZLocationTests.swift */, 195 | 81925D261E40AA78001701F3 /* Info.plist */, 196 | ); 197 | path = IGZLocationTests; 198 | sourceTree = ""; 199 | }; 200 | /* End PBXGroup section */ 201 | 202 | /* Begin PBXHeadersBuildPhase section */ 203 | 81925D131E40AA78001701F3 /* Headers */ = { 204 | isa = PBXHeadersBuildPhase; 205 | buildActionMask = 2147483647; 206 | files = ( 207 | 81925D271E40AA78001701F3 /* IGZLocation.h in Headers */, 208 | ); 209 | runOnlyForDeploymentPostprocessing = 0; 210 | }; 211 | /* End PBXHeadersBuildPhase section */ 212 | 213 | /* Begin PBXNativeTarget section */ 214 | 8159B43A1E447F3C00D0D587 /* IGZLocationMap */ = { 215 | isa = PBXNativeTarget; 216 | buildConfigurationList = 8159B4591E447F3D00D0D587 /* Build configuration list for PBXNativeTarget "IGZLocationMap" */; 217 | buildPhases = ( 218 | 8159B4371E447F3C00D0D587 /* Sources */, 219 | 8159B4381E447F3C00D0D587 /* Frameworks */, 220 | 8159B4391E447F3C00D0D587 /* Resources */, 221 | 8159B45F1E447F7700D0D587 /* Embed Frameworks */, 222 | ); 223 | buildRules = ( 224 | ); 225 | dependencies = ( 226 | 8159B45E1E447F7700D0D587 /* PBXTargetDependency */, 227 | ); 228 | name = IGZLocationMap; 229 | productName = IGZLocationMap; 230 | productReference = 8159B43B1E447F3C00D0D587 /* IGZLocationMap.app */; 231 | productType = "com.apple.product-type.application"; 232 | }; 233 | 8159B44D1E447F3D00D0D587 /* IGZLocationMapUITests */ = { 234 | isa = PBXNativeTarget; 235 | buildConfigurationList = 8159B45A1E447F3D00D0D587 /* Build configuration list for PBXNativeTarget "IGZLocationMapUITests" */; 236 | buildPhases = ( 237 | 8159B44A1E447F3D00D0D587 /* Sources */, 238 | 8159B44B1E447F3D00D0D587 /* Frameworks */, 239 | 8159B44C1E447F3D00D0D587 /* Resources */, 240 | ); 241 | buildRules = ( 242 | ); 243 | dependencies = ( 244 | 8159B4501E447F3D00D0D587 /* PBXTargetDependency */, 245 | ); 246 | name = IGZLocationMapUITests; 247 | productName = IGZLocationMapUITests; 248 | productReference = 8159B44E1E447F3D00D0D587 /* IGZLocationMapUITests.xctest */; 249 | productType = "com.apple.product-type.bundle.ui-testing"; 250 | }; 251 | 81925D151E40AA78001701F3 /* IGZLocation */ = { 252 | isa = PBXNativeTarget; 253 | buildConfigurationList = 81925D2A1E40AA78001701F3 /* Build configuration list for PBXNativeTarget "IGZLocation" */; 254 | buildPhases = ( 255 | 81925D111E40AA78001701F3 /* Sources */, 256 | 81925D121E40AA78001701F3 /* Frameworks */, 257 | 81925D131E40AA78001701F3 /* Headers */, 258 | 81925D141E40AA78001701F3 /* Resources */, 259 | ); 260 | buildRules = ( 261 | ); 262 | dependencies = ( 263 | ); 264 | name = IGZLocation; 265 | productName = IGZLocation; 266 | productReference = 81925D161E40AA78001701F3 /* IGZLocation.framework */; 267 | productType = "com.apple.product-type.framework"; 268 | }; 269 | 81925D1E1E40AA78001701F3 /* IGZLocationTests */ = { 270 | isa = PBXNativeTarget; 271 | buildConfigurationList = 81925D2D1E40AA78001701F3 /* Build configuration list for PBXNativeTarget "IGZLocationTests" */; 272 | buildPhases = ( 273 | 81925D1B1E40AA78001701F3 /* Sources */, 274 | 81925D1C1E40AA78001701F3 /* Frameworks */, 275 | 81925D1D1E40AA78001701F3 /* Resources */, 276 | ); 277 | buildRules = ( 278 | ); 279 | dependencies = ( 280 | 81925D221E40AA78001701F3 /* PBXTargetDependency */, 281 | ); 282 | name = IGZLocationTests; 283 | productName = IGZLocationTests; 284 | productReference = 81925D1F1E40AA78001701F3 /* IGZLocationTests.xctest */; 285 | productType = "com.apple.product-type.bundle.unit-test"; 286 | }; 287 | /* End PBXNativeTarget section */ 288 | 289 | /* Begin PBXProject section */ 290 | 81925D0D1E40AA78001701F3 /* Project object */ = { 291 | isa = PBXProject; 292 | attributes = { 293 | LastSwiftUpdateCheck = 0820; 294 | LastUpgradeCheck = 0900; 295 | ORGANIZATIONNAME = Intelygenz; 296 | TargetAttributes = { 297 | 8159B43A1E447F3C00D0D587 = { 298 | CreatedOnToolsVersion = 8.2.1; 299 | DevelopmentTeam = 3VW789WSMP; 300 | LastSwiftMigration = 0900; 301 | ProvisioningStyle = Automatic; 302 | SystemCapabilities = { 303 | com.apple.BackgroundModes = { 304 | enabled = 1; 305 | }; 306 | }; 307 | }; 308 | 8159B44D1E447F3D00D0D587 = { 309 | CreatedOnToolsVersion = 8.2.1; 310 | DevelopmentTeam = 3VW789WSMP; 311 | LastSwiftMigration = 0900; 312 | ProvisioningStyle = Automatic; 313 | TestTargetID = 8159B43A1E447F3C00D0D587; 314 | }; 315 | 81925D151E40AA78001701F3 = { 316 | CreatedOnToolsVersion = 8.2.1; 317 | DevelopmentTeam = 3VW789WSMP; 318 | LastSwiftMigration = 0900; 319 | ProvisioningStyle = Automatic; 320 | }; 321 | 81925D1E1E40AA78001701F3 = { 322 | CreatedOnToolsVersion = 8.2.1; 323 | DevelopmentTeam = 3VW789WSMP; 324 | LastSwiftMigration = 0900; 325 | ProvisioningStyle = Automatic; 326 | }; 327 | }; 328 | }; 329 | buildConfigurationList = 81925D101E40AA78001701F3 /* Build configuration list for PBXProject "IGZLocation" */; 330 | compatibilityVersion = "Xcode 3.2"; 331 | developmentRegion = English; 332 | hasScannedForEncodings = 0; 333 | knownRegions = ( 334 | en, 335 | Base, 336 | ); 337 | mainGroup = 81925D0C1E40AA78001701F3; 338 | productRefGroup = 81925D171E40AA78001701F3 /* Products */; 339 | projectDirPath = ""; 340 | projectRoot = ""; 341 | targets = ( 342 | 81925D151E40AA78001701F3 /* IGZLocation */, 343 | 81925D1E1E40AA78001701F3 /* IGZLocationTests */, 344 | 8159B43A1E447F3C00D0D587 /* IGZLocationMap */, 345 | 8159B44D1E447F3D00D0D587 /* IGZLocationMapUITests */, 346 | ); 347 | }; 348 | /* End PBXProject section */ 349 | 350 | /* Begin PBXResourcesBuildPhase section */ 351 | 8159B4391E447F3C00D0D587 /* Resources */ = { 352 | isa = PBXResourcesBuildPhase; 353 | buildActionMask = 2147483647; 354 | files = ( 355 | 8159B4481E447F3D00D0D587 /* LaunchScreen.storyboard in Resources */, 356 | 8159B4451E447F3D00D0D587 /* Assets.xcassets in Resources */, 357 | 8159B4431E447F3D00D0D587 /* Main.storyboard in Resources */, 358 | ); 359 | runOnlyForDeploymentPostprocessing = 0; 360 | }; 361 | 8159B44C1E447F3D00D0D587 /* Resources */ = { 362 | isa = PBXResourcesBuildPhase; 363 | buildActionMask = 2147483647; 364 | files = ( 365 | ); 366 | runOnlyForDeploymentPostprocessing = 0; 367 | }; 368 | 81925D141E40AA78001701F3 /* Resources */ = { 369 | isa = PBXResourcesBuildPhase; 370 | buildActionMask = 2147483647; 371 | files = ( 372 | ); 373 | runOnlyForDeploymentPostprocessing = 0; 374 | }; 375 | 81925D1D1E40AA78001701F3 /* Resources */ = { 376 | isa = PBXResourcesBuildPhase; 377 | buildActionMask = 2147483647; 378 | files = ( 379 | ); 380 | runOnlyForDeploymentPostprocessing = 0; 381 | }; 382 | /* End PBXResourcesBuildPhase section */ 383 | 384 | /* Begin PBXSourcesBuildPhase section */ 385 | 8159B4371E447F3C00D0D587 /* Sources */ = { 386 | isa = PBXSourcesBuildPhase; 387 | buildActionMask = 2147483647; 388 | files = ( 389 | 8159B4401E447F3D00D0D587 /* ViewController.swift in Sources */, 390 | 8159B43E1E447F3C00D0D587 /* AppDelegate.swift in Sources */, 391 | ); 392 | runOnlyForDeploymentPostprocessing = 0; 393 | }; 394 | 8159B44A1E447F3D00D0D587 /* Sources */ = { 395 | isa = PBXSourcesBuildPhase; 396 | buildActionMask = 2147483647; 397 | files = ( 398 | 8159B4531E447F3D00D0D587 /* IGZLocationMapUITests.swift in Sources */, 399 | ); 400 | runOnlyForDeploymentPostprocessing = 0; 401 | }; 402 | 81925D111E40AA78001701F3 /* Sources */ = { 403 | isa = PBXSourcesBuildPhase; 404 | buildActionMask = 2147483647; 405 | files = ( 406 | 8159B42C1E4337A900D0D587 /* IGZLocationNotifications.swift in Sources */, 407 | 8159B42E1E4337D100D0D587 /* IGZLocationManager.swift in Sources */, 408 | 8159B4321E43382300D0D587 /* IGZLocationError.swift in Sources */, 409 | 8159B4301E4337F300D0D587 /* IGZLocationDelegate.swift in Sources */, 410 | 8159B42A1E43378400D0D587 /* IGZLocationHandlers.swift in Sources */, 411 | 8159B4361E4339C600D0D587 /* IGZLocationManagerExtension.swift in Sources */, 412 | 81925D311E40AB25001701F3 /* IGZLocation.swift in Sources */, 413 | 8159B4341E43389A00D0D587 /* IGZLocationManagerDelegate.swift in Sources */, 414 | ); 415 | runOnlyForDeploymentPostprocessing = 0; 416 | }; 417 | 81925D1B1E40AA78001701F3 /* Sources */ = { 418 | isa = PBXSourcesBuildPhase; 419 | buildActionMask = 2147483647; 420 | files = ( 421 | 81925D251E40AA78001701F3 /* IGZLocationTests.swift in Sources */, 422 | ); 423 | runOnlyForDeploymentPostprocessing = 0; 424 | }; 425 | /* End PBXSourcesBuildPhase section */ 426 | 427 | /* Begin PBXTargetDependency section */ 428 | 8159B4501E447F3D00D0D587 /* PBXTargetDependency */ = { 429 | isa = PBXTargetDependency; 430 | target = 8159B43A1E447F3C00D0D587 /* IGZLocationMap */; 431 | targetProxy = 8159B44F1E447F3D00D0D587 /* PBXContainerItemProxy */; 432 | }; 433 | 8159B45E1E447F7700D0D587 /* PBXTargetDependency */ = { 434 | isa = PBXTargetDependency; 435 | target = 81925D151E40AA78001701F3 /* IGZLocation */; 436 | targetProxy = 8159B45D1E447F7700D0D587 /* PBXContainerItemProxy */; 437 | }; 438 | 81925D221E40AA78001701F3 /* PBXTargetDependency */ = { 439 | isa = PBXTargetDependency; 440 | target = 81925D151E40AA78001701F3 /* IGZLocation */; 441 | targetProxy = 81925D211E40AA78001701F3 /* PBXContainerItemProxy */; 442 | }; 443 | /* End PBXTargetDependency section */ 444 | 445 | /* Begin PBXVariantGroup section */ 446 | 8159B4411E447F3D00D0D587 /* Main.storyboard */ = { 447 | isa = PBXVariantGroup; 448 | children = ( 449 | 8159B4421E447F3D00D0D587 /* Base */, 450 | ); 451 | name = Main.storyboard; 452 | sourceTree = ""; 453 | }; 454 | 8159B4461E447F3D00D0D587 /* LaunchScreen.storyboard */ = { 455 | isa = PBXVariantGroup; 456 | children = ( 457 | 8159B4471E447F3D00D0D587 /* Base */, 458 | ); 459 | name = LaunchScreen.storyboard; 460 | sourceTree = ""; 461 | }; 462 | /* End PBXVariantGroup section */ 463 | 464 | /* Begin XCBuildConfiguration section */ 465 | 8159B4551E447F3D00D0D587 /* Debug */ = { 466 | isa = XCBuildConfiguration; 467 | buildSettings = { 468 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 469 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 470 | CODE_SIGN_IDENTITY = "iPhone Developer"; 471 | DEVELOPMENT_TEAM = 3VW789WSMP; 472 | INFOPLIST_FILE = IGZLocationMap/Info.plist; 473 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 474 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 475 | PRODUCT_BUNDLE_IDENTIFIER = com.intelygenz.IGZLocationMap; 476 | PRODUCT_NAME = "$(TARGET_NAME)"; 477 | SWIFT_VERSION = 4.0; 478 | }; 479 | name = Debug; 480 | }; 481 | 8159B4561E447F3D00D0D587 /* Release */ = { 482 | isa = XCBuildConfiguration; 483 | buildSettings = { 484 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 485 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 486 | CODE_SIGN_IDENTITY = "iPhone Distribution"; 487 | DEVELOPMENT_TEAM = 3VW789WSMP; 488 | INFOPLIST_FILE = IGZLocationMap/Info.plist; 489 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 490 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 491 | PRODUCT_BUNDLE_IDENTIFIER = com.intelygenz.IGZLocationMap; 492 | PRODUCT_NAME = "$(TARGET_NAME)"; 493 | SWIFT_VERSION = 4.0; 494 | }; 495 | name = Release; 496 | }; 497 | 8159B4571E447F3D00D0D587 /* Debug */ = { 498 | isa = XCBuildConfiguration; 499 | buildSettings = { 500 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 501 | DEVELOPMENT_TEAM = 3VW789WSMP; 502 | INFOPLIST_FILE = IGZLocationMapUITests/Info.plist; 503 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 504 | PRODUCT_BUNDLE_IDENTIFIER = com.intelygenz.IGZLocationMapUITests; 505 | PRODUCT_NAME = "$(TARGET_NAME)"; 506 | SWIFT_VERSION = 4.0; 507 | TEST_TARGET_NAME = IGZLocationMap; 508 | }; 509 | name = Debug; 510 | }; 511 | 8159B4581E447F3D00D0D587 /* Release */ = { 512 | isa = XCBuildConfiguration; 513 | buildSettings = { 514 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 515 | DEVELOPMENT_TEAM = 3VW789WSMP; 516 | INFOPLIST_FILE = IGZLocationMapUITests/Info.plist; 517 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 518 | PRODUCT_BUNDLE_IDENTIFIER = com.intelygenz.IGZLocationMapUITests; 519 | PRODUCT_NAME = "$(TARGET_NAME)"; 520 | SWIFT_VERSION = 4.0; 521 | TEST_TARGET_NAME = IGZLocationMap; 522 | }; 523 | name = Release; 524 | }; 525 | 81925D281E40AA78001701F3 /* Debug */ = { 526 | isa = XCBuildConfiguration; 527 | buildSettings = { 528 | ALWAYS_SEARCH_USER_PATHS = NO; 529 | CLANG_ANALYZER_NONNULL = YES; 530 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 531 | CLANG_CXX_LIBRARY = "libc++"; 532 | CLANG_ENABLE_MODULES = YES; 533 | CLANG_ENABLE_OBJC_ARC = YES; 534 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 535 | CLANG_WARN_BOOL_CONVERSION = YES; 536 | CLANG_WARN_COMMA = YES; 537 | CLANG_WARN_CONSTANT_CONVERSION = YES; 538 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 539 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 540 | CLANG_WARN_EMPTY_BODY = YES; 541 | CLANG_WARN_ENUM_CONVERSION = YES; 542 | CLANG_WARN_INFINITE_RECURSION = YES; 543 | CLANG_WARN_INT_CONVERSION = YES; 544 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 545 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 546 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 547 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 548 | CLANG_WARN_STRICT_PROTOTYPES = YES; 549 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 550 | CLANG_WARN_UNREACHABLE_CODE = YES; 551 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 552 | COPY_PHASE_STRIP = NO; 553 | CURRENT_PROJECT_VERSION = "$(DYLIB_CURRENT_VERSION)"; 554 | DEBUG_INFORMATION_FORMAT = dwarf; 555 | DYLIB_COMPATIBILITY_VERSION = 1.1.0; 556 | DYLIB_CURRENT_VERSION = 1.1.0; 557 | ENABLE_STRICT_OBJC_MSGSEND = YES; 558 | ENABLE_TESTABILITY = YES; 559 | GCC_C_LANGUAGE_STANDARD = gnu99; 560 | GCC_DYNAMIC_NO_PIC = NO; 561 | GCC_NO_COMMON_BLOCKS = YES; 562 | GCC_OPTIMIZATION_LEVEL = 0; 563 | GCC_PREPROCESSOR_DEFINITIONS = ( 564 | "DEBUG=1", 565 | "$(inherited)", 566 | ); 567 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 568 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 569 | GCC_WARN_UNDECLARED_SELECTOR = YES; 570 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 571 | GCC_WARN_UNUSED_FUNCTION = YES; 572 | GCC_WARN_UNUSED_VARIABLE = YES; 573 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 574 | MTL_ENABLE_DEBUG_INFO = YES; 575 | ONLY_ACTIVE_ARCH = YES; 576 | SDKROOT = iphoneos; 577 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 578 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 579 | TARGETED_DEVICE_FAMILY = "1,2"; 580 | VERSIONING_SYSTEM = "apple-generic"; 581 | VERSION_INFO_PREFIX = ""; 582 | }; 583 | name = Debug; 584 | }; 585 | 81925D291E40AA78001701F3 /* Release */ = { 586 | isa = XCBuildConfiguration; 587 | buildSettings = { 588 | ALWAYS_SEARCH_USER_PATHS = NO; 589 | CLANG_ANALYZER_NONNULL = YES; 590 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 591 | CLANG_CXX_LIBRARY = "libc++"; 592 | CLANG_ENABLE_MODULES = YES; 593 | CLANG_ENABLE_OBJC_ARC = YES; 594 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 595 | CLANG_WARN_BOOL_CONVERSION = YES; 596 | CLANG_WARN_COMMA = YES; 597 | CLANG_WARN_CONSTANT_CONVERSION = YES; 598 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 599 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 600 | CLANG_WARN_EMPTY_BODY = YES; 601 | CLANG_WARN_ENUM_CONVERSION = YES; 602 | CLANG_WARN_INFINITE_RECURSION = YES; 603 | CLANG_WARN_INT_CONVERSION = YES; 604 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 605 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 606 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 607 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 608 | CLANG_WARN_STRICT_PROTOTYPES = YES; 609 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 610 | CLANG_WARN_UNREACHABLE_CODE = YES; 611 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 612 | COPY_PHASE_STRIP = NO; 613 | CURRENT_PROJECT_VERSION = "$(DYLIB_CURRENT_VERSION)"; 614 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 615 | DYLIB_COMPATIBILITY_VERSION = 1.1.0; 616 | DYLIB_CURRENT_VERSION = 1.1.0; 617 | ENABLE_NS_ASSERTIONS = NO; 618 | ENABLE_STRICT_OBJC_MSGSEND = YES; 619 | GCC_C_LANGUAGE_STANDARD = gnu99; 620 | GCC_NO_COMMON_BLOCKS = YES; 621 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 622 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 623 | GCC_WARN_UNDECLARED_SELECTOR = YES; 624 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 625 | GCC_WARN_UNUSED_FUNCTION = YES; 626 | GCC_WARN_UNUSED_VARIABLE = YES; 627 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 628 | MTL_ENABLE_DEBUG_INFO = NO; 629 | SDKROOT = iphoneos; 630 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 631 | TARGETED_DEVICE_FAMILY = "1,2"; 632 | VALIDATE_PRODUCT = YES; 633 | VERSIONING_SYSTEM = "apple-generic"; 634 | VERSION_INFO_PREFIX = ""; 635 | }; 636 | name = Release; 637 | }; 638 | 81925D2B1E40AA78001701F3 /* Debug */ = { 639 | isa = XCBuildConfiguration; 640 | buildSettings = { 641 | CLANG_ENABLE_MODULES = YES; 642 | DEFINES_MODULE = YES; 643 | DEVELOPMENT_TEAM = 3VW789WSMP; 644 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 645 | INFOPLIST_FILE = IGZLocation/Info.plist; 646 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 647 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 648 | PRODUCT_BUNDLE_IDENTIFIER = com.intelygenz.IGZLocation; 649 | PRODUCT_NAME = "$(TARGET_NAME)"; 650 | SKIP_INSTALL = YES; 651 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 652 | SWIFT_VERSION = 4.0; 653 | }; 654 | name = Debug; 655 | }; 656 | 81925D2C1E40AA78001701F3 /* Release */ = { 657 | isa = XCBuildConfiguration; 658 | buildSettings = { 659 | CLANG_ENABLE_MODULES = YES; 660 | DEFINES_MODULE = YES; 661 | DEVELOPMENT_TEAM = 3VW789WSMP; 662 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 663 | INFOPLIST_FILE = IGZLocation/Info.plist; 664 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 665 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 666 | PRODUCT_BUNDLE_IDENTIFIER = com.intelygenz.IGZLocation; 667 | PRODUCT_NAME = "$(TARGET_NAME)"; 668 | SKIP_INSTALL = YES; 669 | SWIFT_VERSION = 4.0; 670 | }; 671 | name = Release; 672 | }; 673 | 81925D2E1E40AA78001701F3 /* Debug */ = { 674 | isa = XCBuildConfiguration; 675 | buildSettings = { 676 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 677 | DEVELOPMENT_TEAM = 3VW789WSMP; 678 | INFOPLIST_FILE = IGZLocationTests/Info.plist; 679 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 680 | PRODUCT_BUNDLE_IDENTIFIER = com.intelygenz.IGZLocationTests; 681 | PRODUCT_NAME = "$(TARGET_NAME)"; 682 | SWIFT_VERSION = 4.0; 683 | }; 684 | name = Debug; 685 | }; 686 | 81925D2F1E40AA78001701F3 /* Release */ = { 687 | isa = XCBuildConfiguration; 688 | buildSettings = { 689 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 690 | DEVELOPMENT_TEAM = 3VW789WSMP; 691 | INFOPLIST_FILE = IGZLocationTests/Info.plist; 692 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 693 | PRODUCT_BUNDLE_IDENTIFIER = com.intelygenz.IGZLocationTests; 694 | PRODUCT_NAME = "$(TARGET_NAME)"; 695 | SWIFT_VERSION = 4.0; 696 | }; 697 | name = Release; 698 | }; 699 | /* End XCBuildConfiguration section */ 700 | 701 | /* Begin XCConfigurationList section */ 702 | 8159B4591E447F3D00D0D587 /* Build configuration list for PBXNativeTarget "IGZLocationMap" */ = { 703 | isa = XCConfigurationList; 704 | buildConfigurations = ( 705 | 8159B4551E447F3D00D0D587 /* Debug */, 706 | 8159B4561E447F3D00D0D587 /* Release */, 707 | ); 708 | defaultConfigurationIsVisible = 0; 709 | defaultConfigurationName = Release; 710 | }; 711 | 8159B45A1E447F3D00D0D587 /* Build configuration list for PBXNativeTarget "IGZLocationMapUITests" */ = { 712 | isa = XCConfigurationList; 713 | buildConfigurations = ( 714 | 8159B4571E447F3D00D0D587 /* Debug */, 715 | 8159B4581E447F3D00D0D587 /* Release */, 716 | ); 717 | defaultConfigurationIsVisible = 0; 718 | defaultConfigurationName = Release; 719 | }; 720 | 81925D101E40AA78001701F3 /* Build configuration list for PBXProject "IGZLocation" */ = { 721 | isa = XCConfigurationList; 722 | buildConfigurations = ( 723 | 81925D281E40AA78001701F3 /* Debug */, 724 | 81925D291E40AA78001701F3 /* Release */, 725 | ); 726 | defaultConfigurationIsVisible = 0; 727 | defaultConfigurationName = Release; 728 | }; 729 | 81925D2A1E40AA78001701F3 /* Build configuration list for PBXNativeTarget "IGZLocation" */ = { 730 | isa = XCConfigurationList; 731 | buildConfigurations = ( 732 | 81925D2B1E40AA78001701F3 /* Debug */, 733 | 81925D2C1E40AA78001701F3 /* Release */, 734 | ); 735 | defaultConfigurationIsVisible = 0; 736 | defaultConfigurationName = Release; 737 | }; 738 | 81925D2D1E40AA78001701F3 /* Build configuration list for PBXNativeTarget "IGZLocationTests" */ = { 739 | isa = XCConfigurationList; 740 | buildConfigurations = ( 741 | 81925D2E1E40AA78001701F3 /* Debug */, 742 | 81925D2F1E40AA78001701F3 /* Release */, 743 | ); 744 | defaultConfigurationIsVisible = 0; 745 | defaultConfigurationName = Release; 746 | }; 747 | /* End XCConfigurationList section */ 748 | }; 749 | rootObject = 81925D0D1E40AA78001701F3 /* Project object */; 750 | } 751 | -------------------------------------------------------------------------------- /IGZLocation.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /IGZLocation.xcodeproj/xcshareddata/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /IGZLocation.xcodeproj/xcshareddata/xcschemes/IGZLocation.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 32 | 33 | 35 | 41 | 42 | 43 | 44 | 45 | 51 | 52 | 53 | 54 | 55 | 56 | 67 | 68 | 74 | 75 | 76 | 77 | 78 | 81 | 82 | 83 | 89 | 90 | 96 | 97 | 98 | 99 | 101 | 102 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /IGZLocation.xcodeproj/xcshareddata/xcschemes/IGZLocationMap.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 32 | 33 | 35 | 41 | 42 | 43 | 45 | 51 | 52 | 53 | 54 | 55 | 61 | 62 | 63 | 64 | 65 | 66 | 77 | 79 | 85 | 86 | 87 | 88 | 89 | 90 | 96 | 98 | 104 | 105 | 106 | 107 | 109 | 110 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /IGZLocation/IGZLocation.h: -------------------------------------------------------------------------------- 1 | // 2 | // IGZLocation.h 3 | // IGZLocation 4 | // 5 | // Created by Alejandro Ruperez Hernando on 31/1/17. 6 | // Copyright © 2017 Intelygenz. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for IGZLocation. 12 | FOUNDATION_EXPORT double IGZLocationVersionNumber; 13 | 14 | //! Project version string for IGZLocation. 15 | FOUNDATION_EXPORT const unsigned char IGZLocationVersionString[]; 16 | -------------------------------------------------------------------------------- /IGZLocation/IGZLocation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IGZLocation.swift 3 | // IGZLocation 4 | // 5 | // Created by Alejandro Ruperez Hernando on 31/1/17. 6 | // Copyright © 2017 Intelygenz. All rights reserved. 7 | // 8 | 9 | import CoreLocation 10 | 11 | /** 12 | IGZLocationManager 13 | 14 | The IGZLocation is your entry point to the location service. 15 | */ 16 | open class IGZLocation: NSObject { 17 | 18 | open var location: CLLocation? { 19 | return locationManager.location 20 | } 21 | 22 | open var locationHandlers = [IGZLocationHandler]() 23 | open var locationsHandlers = [IGZLocationsHandler]() 24 | open var errorHandlers = [IGZErrorHandler]() 25 | open var headingHandlers = [IGZHeadingHandler]() 26 | open var regionHandlers = [IGZRegionHandler]() 27 | open var authorizationHandlers = [IGZAuthorizationHandler]() 28 | open var visitHandlers = [IGZVisitHandler]() 29 | open var delegates = [IGZLocationDelegate]() 30 | 31 | var locationTemporaryHandlers = [IGZLocationHandler]() 32 | var locationsTemporaryHandlers = [IGZLocationsHandler]() 33 | var errorTemporaryHandlers = [IGZErrorHandler]() 34 | var headingTemporaryHandlers = [IGZHeadingHandler]() 35 | var regionTemporaryHandlers = [IGZRegionHandler]() 36 | var authorizationTemporaryHandlers = [IGZAuthorizationHandler]() 37 | var visitTemporaryHandlers = [IGZVisitHandler]() 38 | 39 | var displayHeadingCalibration = false 40 | var sequentialRegions = false 41 | final let locationManager = CLLocationManager() 42 | final let notificationCenter = NotificationCenter.default 43 | 44 | public override init() { 45 | super.init() 46 | locationManager.delegate = self 47 | } 48 | 49 | deinit { 50 | locationManager.delegate = nil 51 | delegates.removeAll() 52 | locationTemporaryHandlers.removeAll() 53 | locationsTemporaryHandlers.removeAll() 54 | errorTemporaryHandlers.removeAll() 55 | headingTemporaryHandlers.removeAll() 56 | regionTemporaryHandlers.removeAll() 57 | authorizationTemporaryHandlers.removeAll() 58 | visitTemporaryHandlers.removeAll() 59 | locationHandlers.removeAll() 60 | locationsHandlers.removeAll() 61 | errorHandlers.removeAll() 62 | headingHandlers.removeAll() 63 | regionHandlers.removeAll() 64 | authorizationHandlers.removeAll() 65 | visitHandlers.removeAll() 66 | } 67 | 68 | open func startLocationUpdates(_ handler: IGZLocationsHandler? = nil) { 69 | guard authorized && locationAvailable else { 70 | _ = authorize(authorization, { newStatus in 71 | if self.authorized(newStatus) { 72 | if let handler = handler { 73 | self.locationsTemporaryHandlers.append(handler) 74 | } 75 | self.locationManager.startUpdatingLocation() 76 | } 77 | }) 78 | return 79 | } 80 | 81 | if let handler = handler { 82 | locationsTemporaryHandlers.append(handler) 83 | } 84 | locationManager.startUpdatingLocation() 85 | } 86 | 87 | open func requestLocation(_ handler: IGZLocationHandler? = nil) { 88 | guard #available(iOS 9.0, *) else { 89 | let error = NSError(domain: kCLErrorDomain, code: CLError.denied.rawValue, userInfo: [NSLocalizedDescriptionKey: "Request location is only available on iOS 9 or newer."]) 90 | let backgroundError = IGZLocationError(error) 91 | delegates.forEach { delegate in 92 | delegate.didFail(backgroundError) 93 | } 94 | errorHandlers.forEach { errorHandler in 95 | errorHandler(backgroundError) 96 | } 97 | return 98 | } 99 | 100 | guard authorized && locationAvailable else { 101 | _ = authorize(authorization, { newStatus in 102 | if self.authorized(newStatus) { 103 | if let handler = handler { 104 | self.locationTemporaryHandlers.append(handler) 105 | } 106 | self.locationManager.requestLocation() 107 | } 108 | }) 109 | return 110 | } 111 | 112 | if let handler = handler { 113 | locationTemporaryHandlers.append(handler) 114 | } 115 | locationManager.requestLocation() 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /IGZLocation/IGZLocationDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IGZLocationDelegate.swift 3 | // IGZLocation 4 | // 5 | // Created by Alejandro Ruperez Hernando on 2/2/17. 6 | // Copyright © 2017 Intelygenz. All rights reserved. 7 | // 8 | 9 | import CoreLocation 10 | 11 | public protocol IGZLocationDelegate { 12 | 13 | func didUpdateLocation(_ location: CLLocation) 14 | func didUpdateLocations(_ locations: [CLLocation]) 15 | func didUpdateHeading(_ heading: CLHeading) 16 | func didUpdateRegion(_ region: CLRegion, _ state: CLRegionState) 17 | func didFail(_ error: IGZLocationError) 18 | func didChangeAuthorization(_ status: CLAuthorizationStatus) 19 | func didVisit(_ visit: CLVisit, _ visiting: Bool) 20 | 21 | } 22 | 23 | public extension IGZLocationDelegate { 24 | 25 | func didUpdateLocation(_ location: CLLocation) {} 26 | func didUpdateLocations(_ locations: [CLLocation]) {} 27 | func didUpdateHeading(_ heading: CLHeading) {} 28 | func didUpdateRegion(_ region: CLRegion, _ state: CLRegionState) {} 29 | func didFail(_ error: IGZLocationError) {} 30 | func didChangeAuthorization(_ status: CLAuthorizationStatus) {} 31 | func didVisit(_ visit: CLVisit, _ visiting: Bool) {} 32 | 33 | } 34 | -------------------------------------------------------------------------------- /IGZLocation/IGZLocationError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IGZLocationError.swift 3 | // IGZLocation 4 | // 5 | // Created by Alejandro Ruperez Hernando on 2/2/17. 6 | // Copyright © 2017 Intelygenz. All rights reserved. 7 | // 8 | 9 | import CoreLocation 10 | 11 | open class IGZLocationError: NSError { 12 | 13 | fileprivate(set) var region: CLRegion? 14 | 15 | public convenience init(_ error: Error) { 16 | self.init(error: error as NSError, region: nil) 17 | } 18 | 19 | public convenience init(_ error: Error, region: CLRegion? = nil) { 20 | self.init(error: error as NSError, region: nil) 21 | } 22 | 23 | public convenience init(error: NSError) { 24 | self.init(error, region: nil) 25 | } 26 | 27 | public init(error: NSError, region: CLRegion? = nil) { 28 | var userInfo = error.userInfo 29 | userInfo[NSUnderlyingErrorKey] = error 30 | super.init(domain: error.domain, code: error.code, userInfo: userInfo) 31 | } 32 | 33 | required public init?(coder aDecoder: NSCoder) { 34 | fatalError("init(coder:) has not been implemented") 35 | } 36 | 37 | open var underlyingError: NSError? { 38 | return userInfo[NSUnderlyingErrorKey] as? NSError 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /IGZLocation/IGZLocationHandlers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IGZLocationHandlers.swift 3 | // IGZLocation 4 | // 5 | // Created by Alejandro Ruperez Hernando on 2/2/17. 6 | // Copyright © 2017 Intelygenz. All rights reserved. 7 | // 8 | 9 | import CoreLocation 10 | 11 | public typealias IGZLocationHandler = (_ location: CLLocation) -> Void 12 | public typealias IGZLocationsHandler = (_ locations: [CLLocation]) -> Void 13 | public typealias IGZErrorHandler = (_ error: IGZLocationError) -> Void 14 | public typealias IGZHeadingHandler = (_ heading: CLHeading) -> Void 15 | public typealias IGZRegionHandler = (_ region: CLRegion, _ state: CLRegionState) -> Void 16 | public typealias IGZAuthorizationHandler = (_ status: CLAuthorizationStatus) -> Void 17 | public typealias IGZVisitHandler = (_ visit: CLVisit, _ visiting: Bool) -> Void 18 | -------------------------------------------------------------------------------- /IGZLocation/IGZLocationManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IGZLocationManager.swift 3 | // IGZLocation 4 | // 5 | // Created by Alejandro Ruperez Hernando on 2/2/17. 6 | // Copyright © 2017 Intelygenz. All rights reserved. 7 | // 8 | 9 | import CoreLocation 10 | 11 | /** 12 | IGZLocationManager 13 | 14 | The IGZLocationManager protocol implementation is your entry point to the location service. 15 | */ 16 | public protocol IGZLocationManager { 17 | 18 | /// IGZLocationManager protocol implementation shared instance 19 | static var shared: IGZLocationManager { get } 20 | 21 | var locationHandlers: [IGZLocationHandler] { get set } 22 | var errorHandlers: [IGZErrorHandler] { get set } 23 | var locationsHandlers: [IGZLocationsHandler] { get set } 24 | var headingHandlers: [IGZHeadingHandler] { get set } 25 | var regionHandlers: [IGZRegionHandler] { get set } 26 | var authorizationHandlers: [IGZAuthorizationHandler] { get set } 27 | var visitHandlers: [IGZVisitHandler] { get set } 28 | var delegates: [IGZLocationDelegate] { get set } 29 | 30 | /** 31 | activity 32 | 33 | Specifies the type of user activity. Currently affects behavior such as 34 | the determination of when location updates may be automatically paused. 35 | By default, CLActivityTypeOther is used. 36 | */ 37 | var activity: CLActivityType { get set } 38 | 39 | /** 40 | distanceFilter 41 | 42 | Specifies the minimum update distance in meters. Client will not be notified of movements of less 43 | than the stated value, unless the accuracy has improved. Pass in kCLDistanceFilterNone to be 44 | notified of all movements. By default, kCLDistanceFilterNone is used. 45 | */ 46 | var distanceFilter: CLLocationDistance { get set } 47 | 48 | /** 49 | accuracy 50 | 51 | The desired location accuracy. The location service will try its best to achieve 52 | your desired accuracy. However, it is not guaranteed. To optimize 53 | power performance, be sure to specify an appropriate accuracy for your usage scenario (eg, 54 | use a large accuracy value when only a coarse location is needed). Use kCLLocationAccuracyBest to 55 | achieve the best possible accuracy. Use kCLLocationAccuracyBestForNavigation for navigation. 56 | The default value varies by platform. 57 | */ 58 | var accuracy: CLLocationAccuracy { get set } 59 | 60 | /** 61 | pausesAutomatically 62 | 63 | Specifies that location updates may automatically be paused when possible. 64 | By default, this is true for applications linked against iOS 8.0 or later. 65 | */ 66 | var pausesAutomatically: Bool { get set } 67 | 68 | /** 69 | background 70 | 71 | By default, this is false for applications linked against iOS 9.0 or later, 72 | regardless of minimum deployment target. 73 | 74 | With UIBackgroundModes set to include "location" in Info.plist, you must 75 | also set this property to true at runtime whenever calling 76 | -startLocationUpdates: with the intent to continue in the background. 77 | 78 | Setting this property to true when UIBackgroundModes does not include 79 | "location" is a fatal error. 80 | 81 | Resetting this property to false is equivalent to omitting "location" from 82 | the UIBackgroundModes value. Access to location is still permitted 83 | whenever the application is running (ie not suspended), and has 84 | sufficient authorization (ie it has WhenInUse authorization and is in 85 | use, or it has Always authorization). However, the app will still be 86 | subject to the usual task suspension rules. 87 | 88 | See -authorize: for 89 | more details on possible authorization values. 90 | */ 91 | @available(iOS 9.0, *) 92 | var background: Bool { get set } 93 | 94 | /** 95 | headingFilter 96 | 97 | Specifies the minimum amount of change in degrees needed for a heading service update. Client will not 98 | be notified of updates less than the stated filter value. Pass in kCLHeadingFilterNone to be 99 | notified of all updates. By default, 1 degree is used. 100 | */ 101 | var headingFilter: CLLocationDegrees { get set } 102 | 103 | /** 104 | headingOrientation 105 | 106 | Specifies a physical device orientation from which heading calculation should be referenced. By default, 107 | CLDeviceOrientationPortrait is used. CLDeviceOrientationUnknown, CLDeviceOrientationFaceUp, and 108 | CLDeviceOrientationFaceDown are ignored. 109 | 110 | */ 111 | var orientation: CLDeviceOrientation { get set } 112 | 113 | /** 114 | authorized 115 | 116 | Returns if the current authorization status of the calling application is "always" or "when in use". 117 | */ 118 | var authorized: Bool { get } 119 | 120 | /** 121 | locationAvailable 122 | 123 | Determines whether the user has location services enabled. 124 | If false, and you proceed to call other CoreLocation API, user will be prompted with the warning 125 | dialog. You may want to check this property and use location services only when explicitly requested by the user. 126 | */ 127 | var locationAvailable: Bool { get } 128 | 129 | /** 130 | headingAvailable 131 | 132 | Returns true if the device supports the heading service, otherwise false. 133 | */ 134 | var headingAvailable: Bool { get } 135 | 136 | /** 137 | significantLocationAvailable 138 | 139 | Returns true if the device supports significant location change monitoring, otherwise false. 140 | */ 141 | var significantLocationAvailable: Bool { get } 142 | 143 | /** 144 | deferredLocationAvailable 145 | 146 | Returns true if the device supports deferred location updates, otherwise false. 147 | */ 148 | var deferredLocationAvailable: Bool { get } 149 | 150 | /** 151 | authorization 152 | 153 | Returns the current authorization status of the calling application. 154 | */ 155 | var authorization: CLAuthorizationStatus { get } 156 | 157 | /** 158 | location 159 | 160 | The last location received. Will be nil until a location has been received. 161 | */ 162 | var location: CLLocation? { get } 163 | 164 | /** 165 | heading 166 | 167 | Returns the latest heading update received, or nil if none is available. 168 | */ 169 | var heading: CLHeading? { get } 170 | 171 | /** 172 | maximumRegionDistance 173 | 174 | The maximum region size, in terms of a distance from a central point, that the framework can support. 175 | Attempts to register a region larger than this will generate a kCLErrorRegionMonitoringFailure. 176 | This value may vary based on the hardware features of the device, as well as on dynamically changing resource constraints. 177 | */ 178 | var maximumRegionDistance: CLLocationDistance { get } 179 | 180 | /** 181 | regions 182 | 183 | Retrieve a set of objects for the regions that are currently being monitored. If any location manager 184 | has been instructed to monitor a region, during this or previous launches of your application, it will 185 | be present in this set. 186 | */ 187 | var regions: Set { get } 188 | 189 | /** 190 | shouldDisplayHeadingCalibration: 191 | 192 | Shows the heading calibration when needed. 193 | 194 | - Parameters: 195 | - display: Should display heading calibration. 196 | */ 197 | func shouldDisplayHeadingCalibration(_ display: Bool) 198 | 199 | /** 200 | dismissHeadingCalibrationDisplay 201 | 202 | Dismiss the heading calibration immediately. 203 | */ 204 | func dismissHeadingCalibration() 205 | 206 | /** 207 | regionAvailable: 208 | 209 | Determines whether the device supports monitoring for the specified type of region. 210 | If false, all attempts to monitor the specified type of region will fail. 211 | 212 | - Parameters: 213 | - regionClass: The specified type of region. 214 | 215 | - Returns: If the device supports monitoring for the specified type of region. 216 | */ 217 | func regionAvailable(_ regionClass: CLRegion.Type) -> Bool 218 | 219 | /** 220 | authorized 221 | 222 | Returns if status is "always" or "when in use". 223 | 224 | - Parameters: 225 | - status: The authorization status. 226 | 227 | - Returns: If status is "always" or "when in use". 228 | */ 229 | func authorized(_ status: CLAuthorizationStatus) -> Bool 230 | 231 | /** 232 | authorize: 233 | 234 | When authorization == kCLAuthorizationStatusNotDetermined, 235 | calling this method will trigger a prompt to request 236 | authorization from the user. If possible, perform this call in response 237 | to direct user request for a location-based service so that the reason 238 | for the prompt will be clear. 239 | 240 | If "always" authorization is received, grants access to the user's 241 | location via any CLLocationManager API, and grants access to 242 | launch-capable monitoring API such as geofencing/region monitoring, 243 | significante location visits, etc. Even if killed by the user, launch 244 | events triggered by monitored regions or visit patterns will cause a 245 | relaunch. 246 | 247 | "Always" authorization presents a significant risk to user privacy, and 248 | as such requesting it is discouraged unless background launch behavior 249 | is genuinely required. Do not call with "always" unless 250 | you think users will thank you for doing so. 251 | 252 | When authorization != kCLAuthorizationStatusNotDetermined, (ie 253 | generally after the first call) this method will do nothing. 254 | 255 | If the location usage description key is not specified in your 256 | Info.plist, this method will do nothing, as your app will be assumed not 257 | to support location updates. 258 | 259 | - Parameters: 260 | - status: The requested authorization. 261 | - handler: The single request handler. 262 | 263 | - Returns: Authorization request result. 264 | */ 265 | func authorize(_ status: CLAuthorizationStatus, _ handler: IGZAuthorizationHandler?) -> Bool 266 | 267 | /** 268 | startLocationUpdates: 269 | 270 | Start updating locations. 271 | 272 | - Parameters: 273 | - handler: The single request handler. 274 | */ 275 | func startLocationUpdates(_ handler: IGZLocationsHandler?) 276 | 277 | /** 278 | stopLocationUpdates 279 | 280 | Stop updating locations. 281 | */ 282 | func stopLocationUpdates() 283 | 284 | /** 285 | requestLocation: 286 | 287 | Request a single location update. 288 | 289 | The service will attempt to determine location with accuracy according 290 | to the desiredAccuracy property. 291 | 292 | If the best available location has lower accuracy, then it will be 293 | delivered via the standard delegate callback after timeout. 294 | 295 | There can only be one outstanding location request and this method can 296 | not be used concurrently with startLocationUpdates: or 297 | startDeferredLocationUpdates:. Calling either of those methods will 298 | immediately cancel the location request. The method 299 | stopLocationUpdates can be used to explicitly cancel the request. 300 | 301 | - Parameters: 302 | - handler: The single request handler. 303 | */ 304 | @available(iOS 9.0, *) 305 | func requestLocation(_ handler: IGZLocationHandler?) 306 | 307 | /** 308 | startHeadingUpdates: 309 | 310 | Start updating heading. 311 | 312 | - Parameters: 313 | - handler: The single request handler. 314 | */ 315 | func startHeadingUpdates(_ handler: IGZHeadingHandler?) 316 | 317 | /** 318 | stopUpdatingHeading: 319 | 320 | Stop updating heading. 321 | 322 | - Parameters: 323 | - handler: The single request handler. 324 | */ 325 | func stopHeadingUpdates() 326 | 327 | /** 328 | startSignificantLocationUpdates: 329 | 330 | Start monitoring significant location changes. The behavior of this service is not affected by the desiredAccuracy 331 | or distanceFilter properties. 332 | 333 | - Parameters: 334 | - handler: The single request handler. 335 | */ 336 | func startSignificantLocationUpdates(_ handler: IGZLocationsHandler?) 337 | 338 | /** 339 | stopSignificantLocationUpdates 340 | 341 | Stop monitoring significant location changes. 342 | */ 343 | func stopSignificantLocationUpdates() 344 | 345 | /** 346 | startRegionUpdates:sequential:notify: 347 | 348 | Start monitoring the specified region. 349 | 350 | If a region of the same type with the same identifier is already being monitored for this application, 351 | it will be removed from monitoring. For circular regions, the region monitoring service will prioritize 352 | regions by their size, favoring smaller regions over larger regions. 353 | 354 | This is done asynchronously and may not be immediately reflected in regions. 355 | 356 | - Parameters: 357 | - region: The region object that defines the boundary to monitor. This parameter must not be nil. 358 | - sequential: When using CLCircularRegion, the center will be updated with the user current location when the user exits the region. By default, this is false. 359 | - notify: App will be launched when the user enters or exits the region. If false, only notifies when requestRegion: and sequential is disabled. By default, this is true. 360 | - handler: The single request handler. 361 | */ 362 | func startRegionUpdates(_ region: CLRegion, sequential: Bool, notify: Bool?, _ handler: IGZRegionHandler?) 363 | 364 | /** 365 | stopRegionUpdates: 366 | 367 | Stop monitoring the specified region. It is valid to call stopMonitoringForRegion: for a region that was registered 368 | for monitoring with a different location manager object, during this or previous launches of your application. 369 | 370 | This is done asynchronously and may not be immediately reflected in regions. 371 | 372 | - Parameters: 373 | - region: The region object currently being monitored. If it's nil, all region updates will be stopped. 374 | 375 | - Returns: When there is an active region updates request. 376 | */ 377 | func stopRegionUpdates(_ region: CLRegion?) -> Bool 378 | 379 | /** 380 | requestRegion: 381 | 382 | Asynchronously retrieve the cached state of the specified region. 383 | 384 | - Parameters: 385 | - region: The region whose state you want to know. This object must be an instance of one of the standard region subclasses provided by Map Kit. You cannot use this method to determine the state of custom regions you define yourself. 386 | - handler: The single request handler. 387 | 388 | - Returns: When there is an active region updates request. 389 | */ 390 | func requestRegion(_ region: CLRegion?, _ handler: IGZRegionHandler?) -> Bool 391 | 392 | /** 393 | startDeferredLocationUpdatesForDistance:timeout: 394 | 395 | Indicate that the application will allow the location manager to defer 396 | location updates until an exit criterion is met. This may allow the 397 | device to enter a low-power state in which updates are held for later 398 | delivery. Once an exit condition is met, the location manager will 399 | continue normal updates until this method is invoked again. 400 | 401 | Exit conditions, distance and timeout, can be specified using the constants 402 | CLLocationDistanceMax and CLTimeIntervalMax, respectively, if you are 403 | trying to achieve an unlimited distance or timeout. 404 | 405 | The CLLocationManagerDelegate will continue to receive normal updates as 406 | long as the application remains in the foreground. While the process is 407 | in the background, the device may be able to enter a low-power state for 408 | portions of the specified distance and time interval. While in this 409 | state, locations will be coalesced for later delivery. 410 | 411 | Location updates will be deferred as much as is reasonable to save 412 | power. If another process is using location, the device may not enter a 413 | low-power state and instead updates will continue normally. Deferred 414 | updates may be interspersed with normal updates if the device exits and 415 | re-enters a low-power state. 416 | 417 | - Parameters: 418 | - distance: The distance (in meters) from the current location that must be travelled before event delivery resumes. To specify an unlimited distance, pass the CLLocationDistanceMax constant. 419 | - timeout: The amount of time (in seconds) from the current time that must pass before event delivery resumes. To specify an unlimited amount of time, pass the CLTimeIntervalMax constant. 420 | - handler: The single request handler. 421 | */ 422 | func startDeferredLocationUpdates(distance: CLLocationDistance, timeout: TimeInterval, _ handler: IGZLocationsHandler?) 423 | 424 | /** 425 | stopDeferredLocationUpdates: 426 | 427 | Disallow deferred location updates if previously enabled. Any outstanding 428 | updates will be sent and regular location updates will resume. 429 | */ 430 | func stopDeferredLocationUpdates() 431 | 432 | /** 433 | startVisitUpdates: 434 | 435 | Begin monitoring for visits. All CLLLocationManagers allocated by your 436 | application, both current and future, will deliver detected visits to 437 | their delegates. This will continue until -stopMonitoringVisits is sent 438 | to any such CLLocationManager, even across application relaunch events. 439 | 440 | - Parameters: 441 | - handler: The single request handler. 442 | */ 443 | func startVisitUpdates(_ handler: IGZVisitHandler?) 444 | 445 | /** 446 | stopVisitUpdates 447 | 448 | Stop monitoring for visits. To resume visit monitoring, send 449 | -startVisitUpdates:. 450 | 451 | Note that stopping and starting are asynchronous operations and may not 452 | immediately reflect in delegate callback patterns. 453 | */ 454 | func stopVisitUpdates() 455 | 456 | } 457 | -------------------------------------------------------------------------------- /IGZLocation/IGZLocationManagerDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IGZLocationManagerDelegate.swift 3 | // IGZLocation 4 | // 5 | // Created by Alejandro Ruperez Hernando on 2/2/17. 6 | // Copyright © 2017 Intelygenz. All rights reserved. 7 | // 8 | 9 | import CoreLocation 10 | 11 | extension IGZLocation: CLLocationManagerDelegate { 12 | 13 | open func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { 14 | notificationCenter.post(name: .IGZLocationDidUpdateLocations, object: locations) 15 | delegates.forEach { delegate in 16 | delegate.didUpdateLocations(locations) 17 | } 18 | locationsTemporaryHandlers.forEach { locationsTemporaryHandler in 19 | locationsTemporaryHandler(locations) 20 | } 21 | locationsHandlers.forEach { locationsHandler in 22 | locationsHandler(locations) 23 | } 24 | if let lastLocation = locations.last { 25 | notificationCenter.post(name: .IGZLocationDidUpdateLocation, object: lastLocation) 26 | delegates.forEach { delegate in 27 | delegate.didUpdateLocation(lastLocation) 28 | } 29 | locationTemporaryHandlers.forEach { locationTemporaryHandler in 30 | locationTemporaryHandler(lastLocation) 31 | } 32 | locationTemporaryHandlers.removeAll() 33 | locationHandlers.forEach { locationHandler in 34 | locationHandler(lastLocation) 35 | } 36 | } 37 | } 38 | 39 | open func locationManager(_ manager: CLLocationManager, didUpdateHeading newHeading: CLHeading) { 40 | notificationCenter.post(name: .IGZLocationDidUpdateHeading, object: newHeading) 41 | delegates.forEach { delegate in 42 | delegate.didUpdateHeading(newHeading) 43 | } 44 | headingTemporaryHandlers.forEach { headingTemporaryHandler in 45 | headingTemporaryHandler(newHeading) 46 | } 47 | headingHandlers.forEach { headingHandler in 48 | headingHandler(newHeading) 49 | } 50 | } 51 | 52 | open func locationManagerShouldDisplayHeadingCalibration(_ manager: CLLocationManager) -> Bool { 53 | return displayHeadingCalibration 54 | } 55 | 56 | open func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) { 57 | notificationCenter.post(name: .IGZLocationDidUpdateRegion, object: region, userInfo: [IGZLocationRegionStateUserInfoKey: state]) 58 | delegates.forEach { delegate in 59 | delegate.didUpdateRegion(region, state) 60 | } 61 | regionTemporaryHandlers.forEach { regionTemporaryHandler in 62 | regionTemporaryHandler(region, state) 63 | } 64 | regionHandlers.forEach { regionHandler in 65 | regionHandler(region, state) 66 | } 67 | if let lastLocation = location, let circularRegion = region as? CLCircularRegion, sequentialRegions, state == .outside { 68 | let temporaryHandlers = regionTemporaryHandlers 69 | if stopRegionUpdates(region) { 70 | let newRegion = CLCircularRegion(center: lastLocation.coordinate, radius: circularRegion.radius, identifier: region.identifier) 71 | startRegionUpdates(newRegion, sequential: true, temporaryHandlers.last) 72 | } 73 | } 74 | } 75 | 76 | open func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) { 77 | notificationCenter.post(name: .IGZLocationDidUpdateRegion, object: region, userInfo: [IGZLocationRegionStateUserInfoKey: CLRegionState.inside]) 78 | delegates.forEach { delegate in 79 | delegate.didUpdateRegion(region, .inside) 80 | } 81 | regionTemporaryHandlers.forEach { regionTemporaryHandler in 82 | regionTemporaryHandler(region, .inside) 83 | } 84 | regionHandlers.forEach { regionHandler in 85 | regionHandler(region, .inside) 86 | } 87 | } 88 | 89 | open func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) { 90 | notificationCenter.post(name: .IGZLocationDidUpdateRegion, object: region, userInfo: [IGZLocationRegionStateUserInfoKey: CLRegionState.outside]) 91 | delegates.forEach { delegate in 92 | delegate.didUpdateRegion(region, .outside) 93 | } 94 | regionTemporaryHandlers.forEach { regionTemporaryHandler in 95 | regionTemporaryHandler(region, .outside) 96 | } 97 | regionHandlers.forEach { regionHandler in 98 | regionHandler(region, .outside) 99 | } 100 | if let lastLocation = location, let circularRegion = region as? CLCircularRegion, sequentialRegions { 101 | let temporaryHandlers = regionTemporaryHandlers 102 | if stopRegionUpdates(region) { 103 | let newRegion = CLCircularRegion(center: lastLocation.coordinate, radius: circularRegion.radius, identifier: region.identifier) 104 | startRegionUpdates(newRegion, sequential: true, temporaryHandlers.last) 105 | } 106 | } 107 | } 108 | 109 | open func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { 110 | let locationError = IGZLocationError(error) 111 | notificationCenter.post(name: .IGZLocationDidFail, object: locationError) 112 | delegates.forEach { delegate in 113 | delegate.didFail(locationError) 114 | } 115 | errorTemporaryHandlers.forEach { errorTemporaryHandler in 116 | errorTemporaryHandler(locationError) 117 | } 118 | errorTemporaryHandlers.removeAll() 119 | errorHandlers.forEach { errorHandler in 120 | errorHandler(locationError) 121 | } 122 | } 123 | 124 | open func locationManager(_ manager: CLLocationManager, monitoringDidFailFor region: CLRegion?, withError error: Error) { 125 | let locationError = IGZLocationError(error, region: region) 126 | notificationCenter.post(name: .IGZLocationDidFail, object: locationError) 127 | delegates.forEach { delegate in 128 | delegate.didFail(locationError) 129 | } 130 | errorTemporaryHandlers.forEach { errorTemporaryHandler in 131 | errorTemporaryHandler(locationError) 132 | } 133 | errorTemporaryHandlers.removeAll() 134 | errorHandlers.forEach { errorHandler in 135 | errorHandler(locationError) 136 | } 137 | } 138 | 139 | open func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { 140 | notificationCenter.post(name: .IGZLocationDidChangeAuthorization, object: status) 141 | delegates.forEach { delegate in 142 | delegate.didChangeAuthorization(status) 143 | } 144 | authorizationTemporaryHandlers.forEach { authorizationTemporaryHandler in 145 | authorizationTemporaryHandler(status) 146 | } 147 | if status != .notDetermined { 148 | authorizationTemporaryHandlers.removeAll() 149 | } 150 | authorizationHandlers.forEach { authorizationHandler in 151 | authorizationHandler(status) 152 | } 153 | } 154 | 155 | open func locationManager(_ manager: CLLocationManager, didStartMonitoringFor region: CLRegion) { 156 | notificationCenter.post(name: .IGZLocationDidUpdateRegion, object: region, userInfo: [IGZLocationRegionStateUserInfoKey: CLRegionState.unknown]) 157 | delegates.forEach { delegate in 158 | delegate.didUpdateRegion(region, .unknown) 159 | } 160 | regionTemporaryHandlers.forEach { regionTemporaryHandler in 161 | regionTemporaryHandler(region, .unknown) 162 | } 163 | regionHandlers.forEach { regionHandler in 164 | regionHandler(region, .unknown) 165 | } 166 | } 167 | 168 | open func locationManagerDidPauseLocationUpdates(_ manager: CLLocationManager) { 169 | 170 | } 171 | 172 | open func locationManagerDidResumeLocationUpdates(_ manager: CLLocationManager) { 173 | 174 | } 175 | 176 | open func locationManager(_ manager: CLLocationManager, didFinishDeferredUpdatesWithError error: Error?) { 177 | if let error = error { 178 | let locationError = IGZLocationError(error) 179 | notificationCenter.post(name: .IGZLocationDidFail, object: locationError) 180 | delegates.forEach { delegate in 181 | delegate.didFail(locationError) 182 | } 183 | errorTemporaryHandlers.forEach { errorTemporaryHandler in 184 | errorTemporaryHandler(locationError) 185 | } 186 | errorTemporaryHandlers.removeAll() 187 | errorHandlers.forEach { errorHandler in 188 | errorHandler(locationError) 189 | } 190 | } 191 | } 192 | 193 | open func locationManager(_ manager: CLLocationManager, didVisit visit: CLVisit) { 194 | let date = Date() 195 | let visiting = visit.arrivalDate < date && visit.departureDate > date 196 | notificationCenter.post(name: .IGZLocationDidVisit, object: visit, userInfo: [IGZLocationVisitingUserInfoKey: visiting]) 197 | delegates.forEach { delegate in 198 | delegate.didVisit(visit, visiting) 199 | } 200 | visitTemporaryHandlers.forEach { visitTemporaryHandler in 201 | visitTemporaryHandler(visit, visiting) 202 | } 203 | visitHandlers.forEach { visitHandler in 204 | visitHandler(visit, visiting) 205 | } 206 | } 207 | 208 | } 209 | -------------------------------------------------------------------------------- /IGZLocation/IGZLocationManagerExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IGZLocationManagerExtension.swift 3 | // IGZLocation 4 | // 5 | // Created by Alejandro Ruperez Hernando on 2/2/17. 6 | // Copyright © 2017 Intelygenz. All rights reserved. 7 | // 8 | 9 | import CoreLocation 10 | 11 | extension IGZLocation: IGZLocationManager { 12 | 13 | open static var shared: IGZLocationManager = IGZLocation() 14 | 15 | open var authorized: Bool { 16 | return authorized(authorization) 17 | } 18 | 19 | open var locationAvailable: Bool { 20 | return CLLocationManager.locationServicesEnabled() 21 | } 22 | open var headingAvailable: Bool { 23 | return CLLocationManager.headingAvailable() 24 | } 25 | open var significantLocationAvailable: Bool { 26 | return CLLocationManager.significantLocationChangeMonitoringAvailable() 27 | } 28 | open var deferredLocationAvailable: Bool { 29 | return CLLocationManager.deferredLocationUpdatesAvailable() 30 | } 31 | open var authorization: CLAuthorizationStatus { 32 | return CLLocationManager.authorizationStatus() 33 | } 34 | open var heading: CLHeading? { 35 | return locationManager.heading 36 | } 37 | open var maximumRegionDistance: CLLocationDistance { 38 | return locationManager.maximumRegionMonitoringDistance 39 | } 40 | open var regions: Set { 41 | return locationManager.monitoredRegions 42 | } 43 | 44 | open var activity: CLActivityType { 45 | get { 46 | return locationManager.activityType 47 | } 48 | set { 49 | locationManager.activityType = newValue 50 | } 51 | } 52 | open var distanceFilter: CLLocationDistance { 53 | get { 54 | return locationManager.distanceFilter 55 | } 56 | set { 57 | locationManager.distanceFilter = newValue 58 | } 59 | } 60 | open var accuracy: CLLocationAccuracy { 61 | get { 62 | return locationManager.desiredAccuracy 63 | } 64 | set { 65 | locationManager.desiredAccuracy = newValue 66 | } 67 | } 68 | open var pausesAutomatically: Bool { 69 | get { 70 | return locationManager.pausesLocationUpdatesAutomatically 71 | } 72 | set { 73 | locationManager.pausesLocationUpdatesAutomatically = newValue 74 | } 75 | } 76 | open var background: Bool { 77 | get { 78 | if #available(iOS 9.0, *) { 79 | return locationManager.allowsBackgroundLocationUpdates 80 | } else { 81 | return false 82 | } 83 | } 84 | set { 85 | guard #available(iOS 9.0, *) else { 86 | let error = NSError(domain: kCLErrorDomain, code: CLError.denied.rawValue, userInfo: [NSLocalizedDescriptionKey: "Background location updates is only available on iOS 9 or newer."]) 87 | let backgroundError = IGZLocationError(error) 88 | delegates.forEach { delegate in 89 | delegate.didFail(backgroundError) 90 | } 91 | errorHandlers.forEach { errorHandler in 92 | errorHandler(backgroundError) 93 | } 94 | return 95 | } 96 | if let backgroundModes = Bundle.main.infoDictionary?["UIBackgroundModes"] as? [String], backgroundModes.contains("location") { 97 | locationManager.allowsBackgroundLocationUpdates = newValue 98 | } 99 | else { 100 | let error = NSError(domain: kCLErrorDomain, code: CLError.denied.rawValue, userInfo: [NSLocalizedDescriptionKey: "The app's Info.plist must contain an UIBackgroundModes key with \"location\" value."]) 101 | let backgroundError = IGZLocationError(error) 102 | delegates.forEach { delegate in 103 | delegate.didFail(backgroundError) 104 | } 105 | errorHandlers.forEach { errorHandler in 106 | errorHandler(backgroundError) 107 | } 108 | } 109 | } 110 | } 111 | open var headingFilter: CLLocationDegrees { 112 | get { 113 | return locationManager.headingFilter 114 | } 115 | set { 116 | locationManager.headingFilter = newValue 117 | } 118 | } 119 | open var orientation: CLDeviceOrientation { 120 | get { 121 | return locationManager.headingOrientation 122 | } 123 | set { 124 | locationManager.headingOrientation = newValue 125 | } 126 | } 127 | 128 | open func shouldDisplayHeadingCalibration(_ display: Bool = true) { 129 | displayHeadingCalibration = display 130 | } 131 | 132 | open func dismissHeadingCalibration() { 133 | locationManager.dismissHeadingCalibrationDisplay() 134 | } 135 | 136 | open func regionAvailable(_ regionClass: CLRegion.Type) -> Bool { 137 | return CLLocationManager.isMonitoringAvailable(for: regionClass) 138 | } 139 | 140 | open func authorized(_ status: CLAuthorizationStatus) -> Bool { 141 | return status.rawValue >= CLAuthorizationStatus.authorizedAlways.rawValue 142 | } 143 | 144 | open func authorize(_ status: CLAuthorizationStatus, _ handler: IGZAuthorizationHandler? = nil) -> Bool { 145 | guard status != authorization else { 146 | if let handler = handler { 147 | handler(status) 148 | } 149 | return authorized(status) 150 | } 151 | if let handler = handler { 152 | authorizationTemporaryHandlers.append(handler) 153 | } 154 | switch status { 155 | case .authorizedAlways: 156 | locationManager.requestAlwaysAuthorization() 157 | return true 158 | case .authorizedWhenInUse: 159 | locationManager.requestWhenInUseAuthorization() 160 | return true 161 | default: 162 | let error = NSError(domain: kCLErrorDomain, code: CLError.denied.rawValue, userInfo: [NSLocalizedDescriptionKey: "This app has attempted to access location data without user's authorization."]) 163 | let authorizationError = IGZLocationError(error) 164 | delegates.forEach { delegate in 165 | delegate.didFail(authorizationError) 166 | } 167 | errorHandlers.forEach { errorHandler in 168 | errorHandler(authorizationError) 169 | } 170 | return false 171 | } 172 | } 173 | 174 | open func stopLocationUpdates() { 175 | locationsTemporaryHandlers.removeAll() 176 | locationTemporaryHandlers.removeAll() 177 | locationManager.stopUpdatingLocation() 178 | } 179 | 180 | open func startHeadingUpdates(_ handler: IGZHeadingHandler? = nil) { 181 | guard authorized && headingAvailable else { 182 | _ = authorize(authorization, { newStatus in 183 | if self.authorized(newStatus) { 184 | if let handler = handler { 185 | self.headingTemporaryHandlers.append(handler) 186 | } 187 | self.locationManager.startUpdatingHeading() 188 | } 189 | }) 190 | return 191 | } 192 | 193 | if let handler = handler { 194 | headingTemporaryHandlers.append(handler) 195 | } 196 | locationManager.startUpdatingHeading() 197 | } 198 | 199 | open func stopHeadingUpdates() { 200 | headingTemporaryHandlers.removeAll() 201 | locationManager.stopUpdatingHeading() 202 | } 203 | 204 | open func startSignificantLocationUpdates(_ handler: IGZLocationsHandler? = nil) { 205 | guard authorized && significantLocationAvailable else { 206 | _ = authorize(authorization, { newStatus in 207 | if self.authorized(newStatus) { 208 | if let handler = handler { 209 | self.locationsTemporaryHandlers.append(handler) 210 | } 211 | self.locationManager.startMonitoringSignificantLocationChanges() 212 | } 213 | }) 214 | return 215 | } 216 | 217 | if let handler = handler { 218 | locationsTemporaryHandlers.append(handler) 219 | } 220 | locationManager.startMonitoringSignificantLocationChanges() 221 | } 222 | 223 | open func stopSignificantLocationUpdates() { 224 | locationsTemporaryHandlers.removeAll() 225 | locationManager.stopMonitoringSignificantLocationChanges() 226 | } 227 | 228 | open func startRegionUpdates(_ region: CLRegion, sequential: Bool = false, notify: Bool? = nil, _ handler: IGZRegionHandler? = nil) { 229 | if let notify = notify { 230 | region.notifyOnEntry = notify 231 | region.notifyOnExit = notify 232 | } 233 | guard authorized && regionAvailable(type(of: region)) && (region as? CLCircularRegion)?.radius ?? 0 < maximumRegionDistance else { 234 | _ = authorize(authorization, { newStatus in 235 | if self.authorized(newStatus) { 236 | self.sequentialRegions = sequential 237 | if let handler = handler { 238 | self.regionTemporaryHandlers.append(handler) 239 | } 240 | self.locationManager.startMonitoring(for: region) 241 | } 242 | }) 243 | return 244 | } 245 | 246 | sequentialRegions = sequential 247 | if let handler = handler { 248 | regionTemporaryHandlers.append(handler) 249 | } 250 | locationManager.startMonitoring(for: region) 251 | } 252 | 253 | open func stopRegionUpdates(_ region: CLRegion? = nil) -> Bool { 254 | guard regions.count > 0 else { 255 | let error = NSError(domain: kCLErrorDomain, code: CLError.regionMonitoringDenied.rawValue, userInfo: [NSLocalizedDescriptionKey: "You don't have any monitored regions."]) 256 | let regionError = IGZLocationError(error) 257 | delegates.forEach { delegate in 258 | delegate.didFail(regionError) 259 | } 260 | errorHandlers.forEach { errorHandler in 261 | errorHandler(regionError) 262 | } 263 | return false 264 | } 265 | 266 | sequentialRegions = false 267 | regionTemporaryHandlers.removeAll() 268 | if let region = region { 269 | locationManager.stopMonitoring(for: region) 270 | } 271 | else { 272 | regions.forEach { region in 273 | locationManager.stopMonitoring(for: region) 274 | } 275 | } 276 | return true 277 | } 278 | 279 | open func requestRegion(_ region: CLRegion? = nil, _ handler: IGZRegionHandler? = nil) -> Bool { 280 | guard regions.count > 0 else { 281 | let error = NSError(domain: kCLErrorDomain, code: CLError.regionMonitoringDenied.rawValue, userInfo: [NSLocalizedDescriptionKey: "You don't have any monitored regions."]) 282 | let regionError = IGZLocationError(error) 283 | delegates.forEach { delegate in 284 | delegate.didFail(regionError) 285 | } 286 | errorHandlers.forEach { errorHandler in 287 | errorHandler(regionError) 288 | } 289 | return false 290 | } 291 | 292 | guard authorized && regionAvailable(region != nil ? type(of: region!) : CLRegion.self) else { 293 | _ = authorize(authorization, { newStatus in 294 | if self.authorized(newStatus) { 295 | if let handler = handler { 296 | self.regionTemporaryHandlers.append(handler) 297 | } 298 | if let region = region { 299 | self.locationManager.requestState(for: region) 300 | } 301 | else { 302 | self.regions.forEach { region in 303 | self.locationManager.requestState(for: region) 304 | } 305 | } 306 | } 307 | }) 308 | return true 309 | } 310 | 311 | if let handler = handler { 312 | regionTemporaryHandlers.append(handler) 313 | } 314 | if let region = region { 315 | locationManager.requestState(for: region) 316 | } 317 | else { 318 | regions.forEach { region in 319 | locationManager.requestState(for: region) 320 | } 321 | } 322 | return true 323 | } 324 | 325 | open func startDeferredLocationUpdates(distance: CLLocationDistance, timeout: TimeInterval, _ handler: IGZLocationsHandler? = nil) { 326 | guard authorized && deferredLocationAvailable else { 327 | _ = authorize(authorization, { newStatus in 328 | if self.authorized(newStatus) { 329 | if let handler = handler { 330 | self.locationsTemporaryHandlers.append(handler) 331 | } 332 | self.locationManager.allowDeferredLocationUpdates(untilTraveled: distance, timeout: timeout) 333 | } 334 | }) 335 | return 336 | } 337 | 338 | if let handler = handler { 339 | locationsTemporaryHandlers.append(handler) 340 | } 341 | locationManager.allowDeferredLocationUpdates(untilTraveled: distance, timeout: timeout) 342 | } 343 | 344 | open func stopDeferredLocationUpdates() { 345 | locationsTemporaryHandlers.removeAll() 346 | locationManager.disallowDeferredLocationUpdates() 347 | } 348 | 349 | open func startVisitUpdates(_ handler: IGZVisitHandler? = nil) { 350 | guard authorized else { 351 | _ = authorize(authorization, { newStatus in 352 | if self.authorized(newStatus) { 353 | if let handler = handler { 354 | self.visitTemporaryHandlers.append(handler) 355 | } 356 | self.locationManager.startMonitoringVisits() 357 | } 358 | }) 359 | return 360 | } 361 | 362 | if let handler = handler { 363 | visitTemporaryHandlers.append(handler) 364 | } 365 | locationManager.startMonitoringVisits() 366 | } 367 | 368 | open func stopVisitUpdates() { 369 | visitTemporaryHandlers.removeAll() 370 | locationManager.stopMonitoringVisits() 371 | } 372 | 373 | } 374 | -------------------------------------------------------------------------------- /IGZLocation/IGZLocationNotifications.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IGZLocationNotifications.swift 3 | // IGZLocation 4 | // 5 | // Created by Alejandro Ruperez Hernando on 2/2/17. 6 | // Copyright © 2017 Intelygenz. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public struct IGZLocationNotifications { 12 | @available(*, deprecated, message: "Please use .IGZLocationDidUpdateLocation instead") 13 | public static let didUpdateLocation = NSNotification.Name("IGZLocationDidUpdateLocationNotification") 14 | @available(*, deprecated, message: "Please use .IGZLocationDidUpdateLocations instead") 15 | public static let didUpdateLocations = NSNotification.Name("IGZLocationDidUpdateLocationsNotification") 16 | @available(*, deprecated, message: "Please use .IGZLocationDidUpdateHeading instead") 17 | public static let didUpdateHeading = NSNotification.Name("IGZLocationDidUpdateHeadingNotification") 18 | /// Includes regionState in userInfo 19 | @available(*, deprecated, message: "Please use .IGZLocationDidUpdateRegion instead") 20 | public static let didUpdateRegion = NSNotification.Name("IGZLocationDidUpdateRegionNotification") 21 | @available(*, deprecated, message: "Please use .IGZLocationDidFail instead") 22 | public static let didFail = NSNotification.Name("IGZLocationDidFailNotification") 23 | @available(*, deprecated, message: "Please use .IGZLocationDidChangeAuthorization instead") 24 | public static let didChangeAuthorization = NSNotification.Name("IGZLocationDidChangeAuthorizationNotification") 25 | /// Includes visiting in userInfo 26 | @available(*, deprecated, message: "Please use .IGZLocationDidVisit instead") 27 | public static let didVisit = NSNotification.Name("IGZLocationDidVisitNotification") 28 | 29 | public struct userInfoKeys { 30 | @available(*, deprecated, message: "Please use IGZLocationRegionStateUserInfoKey instead") 31 | public static let regionState = "IGZLocationRegionStateNotificationUserInfoKey" 32 | @available(*, deprecated, message: "Please use IGZLocationVisitingUserInfoKey instead") 33 | public static let visiting = "IGZLocationVisitingNotificationUserInfoKey" 34 | } 35 | } 36 | 37 | public extension NSNotification.Name { 38 | public static let IGZLocationDidUpdateLocation = NSNotification.Name("IGZLocationDidUpdateLocationNotification") 39 | public static let IGZLocationDidUpdateLocations = NSNotification.Name("IGZLocationDidUpdateLocationsNotification") 40 | public static let IGZLocationDidUpdateHeading = NSNotification.Name("IGZLocationDidUpdateHeadingNotification") 41 | /// Includes regionState in userInfo 42 | public static let IGZLocationDidUpdateRegion = NSNotification.Name("IGZLocationDidUpdateRegionNotification") 43 | public static let IGZLocationDidFail = NSNotification.Name("IGZLocationDidFailNotification") 44 | public static let IGZLocationDidChangeAuthorization = NSNotification.Name("IGZLocationDidChangeAuthorizationNotification") 45 | /// Includes visiting in userInfo 46 | public static let IGZLocationDidVisit = NSNotification.Name("IGZLocationDidVisitNotification") 47 | } 48 | 49 | public let IGZLocationRegionStateUserInfoKey = "IGZLocationRegionStateNotificationUserInfoKey" 50 | public let IGZLocationVisitingUserInfoKey = "IGZLocationVisitingNotificationUserInfoKey" 51 | -------------------------------------------------------------------------------- /IGZLocation/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /IGZLocationMap/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // IGZLocationMap 4 | // 5 | // Created by Alejandro Ruperez Hernando on 3/2/17. 6 | // Copyright © 2017 Intelygenz. 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 | -------------------------------------------------------------------------------- /IGZLocationMap/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /IGZLocationMap/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /IGZLocationMap/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 40 | 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 | -------------------------------------------------------------------------------- /IGZLocationMap/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | NSLocationAlwaysAndWhenInUseUsageDescription 24 | 25 | NSLocationAlwaysUsageDescription 26 | 27 | NSLocationWhenInUseUsageDescription 28 | 29 | UIBackgroundModes 30 | 31 | location 32 | 33 | UILaunchStoryboardName 34 | LaunchScreen 35 | UIMainStoryboardFile 36 | Main 37 | UIRequiredDeviceCapabilities 38 | 39 | armv7 40 | 41 | UISupportedInterfaceOrientations 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationLandscapeLeft 45 | UIInterfaceOrientationLandscapeRight 46 | 47 | UISupportedInterfaceOrientations~ipad 48 | 49 | UIInterfaceOrientationPortrait 50 | UIInterfaceOrientationPortraitUpsideDown 51 | UIInterfaceOrientationLandscapeLeft 52 | UIInterfaceOrientationLandscapeRight 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /IGZLocationMap/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // IGZLocationMap 4 | // 5 | // Created by Alejandro Ruperez Hernando on 3/2/17. 6 | // Copyright © 2017 Intelygenz. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import MapKit 11 | import IGZLocation 12 | 13 | extension CLLocation: MKAnnotation {} 14 | 15 | extension CLCircularRegion: MKOverlay { 16 | public var coordinate: CLLocationCoordinate2D { 17 | return center 18 | } 19 | 20 | public var boundingMapRect: MKMapRect { 21 | let coordinateRegion = MKCoordinateRegionMakeWithDistance(center, radius*2, radius*2) 22 | let a = MKMapPointForCoordinate(CLLocationCoordinate2DMake(coordinateRegion.center.latitude + coordinateRegion.span.latitudeDelta / 2, coordinateRegion.center.longitude - coordinateRegion.span.longitudeDelta / 2)) 23 | let b = MKMapPointForCoordinate(CLLocationCoordinate2DMake(coordinateRegion.center.latitude - coordinateRegion.span.latitudeDelta / 2, coordinateRegion.center.longitude + coordinateRegion.span.longitudeDelta / 2)) 24 | return MKMapRectMake(min(a.x,b.x), min(a.y,b.y), abs(a.x-b.x), abs(a.y-b.y)) 25 | } 26 | 27 | open override func isEqual(_ region: Any?) -> Bool { 28 | guard let region = region as? CLCircularRegion else { 29 | return false 30 | } 31 | return identifier == region.identifier && center == region.center && radius == region.radius 32 | } 33 | } 34 | 35 | extension CLLocationCoordinate2D: Equatable { 36 | public static func ==(lhs: CLLocationCoordinate2D, rhs: CLLocationCoordinate2D) -> Bool { 37 | return lhs.latitude == rhs.latitude && lhs.longitude == rhs.longitude 38 | } 39 | } 40 | 41 | class ViewController: UIViewController { 42 | 43 | @IBOutlet private weak var mapView: MKMapView! 44 | @IBOutlet private weak var visitLabel: UILabel! 45 | @IBOutlet private weak var headingLabel: UILabel! 46 | 47 | private var locationManager: IGZLocationManager = IGZLocation.shared 48 | 49 | override func viewDidLoad() { 50 | super.viewDidLoad() 51 | 52 | self.locationManager.delegates.append(self) 53 | } 54 | 55 | override func viewWillAppear(_ animated: Bool) { 56 | super.viewWillAppear(animated) 57 | 58 | launchLocation() 59 | } 60 | 61 | func launchLocation() { 62 | _ = locationManager.authorize(.authorizedAlways) { status in 63 | if status == .authorizedAlways { 64 | if self.locationManager.regions.count > 0 { 65 | _ = self.locationManager.stopRegionUpdates(nil) 66 | } 67 | if #available(iOS 9.0, *) { 68 | self.locationManager.background = true 69 | self.locationManager.requestLocation { location in 70 | self.mapView.showsUserLocation = true 71 | let region = CLCircularRegion(center: location.coordinate, radius: 100, identifier: UUID().uuidString) 72 | self.locationManager.startRegionUpdates(region, sequential: true, notify: true, { region, state in 73 | if let region = region as? CLCircularRegion, !self.mapView.overlays.contains(where: { overlay -> Bool in 74 | return overlay as? CLCircularRegion == region 75 | }) { 76 | self.mapView.addOverlays([region]) 77 | } 78 | }) 79 | } 80 | } 81 | 82 | self.locationManager.startLocationUpdates { locations in 83 | self.mapView.addAnnotations(locations) 84 | } 85 | 86 | self.locationManager.startVisitUpdates { visit, visiting in 87 | self.visitLabel.text = visiting ? "VISITING: \(visit.coordinate.latitude), \(visit.coordinate.longitude)" : nil 88 | } 89 | 90 | self.locationManager.startHeadingUpdates { heading in 91 | self.headingLabel.text = "\(heading.magneticHeading)" 92 | } 93 | } 94 | } 95 | } 96 | 97 | } 98 | 99 | extension ViewController: IGZLocationDelegate { 100 | func didFail(_ error: IGZLocationError) { 101 | let alertController = UIAlertController(title: "ERROR", message: error.localizedDescription, preferredStyle: .alert) 102 | alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) 103 | present(alertController, animated: true, completion: nil) 104 | } 105 | } 106 | 107 | extension ViewController: MKMapViewDelegate { 108 | func mapView(_ mapView: MKMapView, didUpdate userLocation: MKUserLocation) { 109 | mapView.userTrackingMode = .followWithHeading 110 | } 111 | 112 | func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer { 113 | if let region = overlay as? CLCircularRegion { 114 | let renderer = MKCircleRenderer(circle: MKCircle(center: region.center, radius: region.radius)) 115 | renderer.fillColor = #colorLiteral(red: 0.01680417731, green: 0.1983509958, blue: 1, alpha: 0.5) 116 | return renderer 117 | } 118 | 119 | return MKOverlayRenderer(overlay: overlay) 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /IGZLocationMapUITests/IGZLocationMapUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IGZLocationMapUITests.swift 3 | // IGZLocationMapUITests 4 | // 5 | // Created by Alejandro Ruperez Hernando on 3/2/17. 6 | // Copyright © 2017 Intelygenz. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | @available(iOS 9.0, *) 12 | class IGZLocationMapUITests: XCTestCase { 13 | 14 | let app = XCUIApplication() 15 | 16 | override func setUp() { 17 | super.setUp() 18 | 19 | continueAfterFailure = true 20 | app.launch() 21 | 22 | checkLocationAuthorization() 23 | } 24 | 25 | func checkLocationAuthorization() { 26 | addUIInterruptionMonitor(withDescription: "Location Authorization") { alert -> Bool in 27 | guard alert.buttons["Always Allow"].exists else { 28 | alert.buttons["Allow"].tap() 29 | return true 30 | } 31 | alert.buttons["Always Allow"].tap() 32 | return true 33 | } 34 | app.tap() 35 | } 36 | 37 | // func testMapPin() { 38 | // // Map load 39 | // sleep(2) 40 | // 41 | // // Find any map pin 42 | // let element = app.otherElements.containing(.staticText, identifier:" ").children(matching: .other).element.children(matching: .other).element.children(matching: .other).element 43 | // XCTAssert(element.children(matching: .other).matching(identifier: "Map pin").element.exists) 44 | // } 45 | 46 | override func tearDown() { 47 | super.tearDown() 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /IGZLocationMapUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /IGZLocationTests/IGZLocationTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // IGZLocationTests.swift 3 | // IGZLocationTests 4 | // 5 | // Created by Alejandro Ruperez Hernando on 31/1/17. 6 | // Copyright © 2017 Intelygenz. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import CoreLocation 11 | @testable import IGZLocation 12 | 13 | class IGZLocationMock: IGZLocation { 14 | private let mockLocation = CLLocation(latitude: 0, longitude: 0) 15 | 16 | override var location: CLLocation? { 17 | return mockLocation 18 | } 19 | 20 | override func startLocationUpdates(_ handler: IGZLocationsHandler? = nil) { 21 | super.startLocationUpdates(handler) 22 | locationManager.delegate?.locationManager?(locationManager, didChangeAuthorization: .authorizedAlways) 23 | locationManager.delegate?.locationManager?(locationManager, didUpdateLocations: [mockLocation]) 24 | } 25 | 26 | override func requestLocation(_ handler: IGZLocationHandler? = nil) { 27 | super.requestLocation(handler) 28 | locationManager.delegate?.locationManager?(locationManager, didChangeAuthorization: .authorizedAlways) 29 | locationManager.delegate?.locationManager?(locationManager, didUpdateLocations: [mockLocation]) 30 | } 31 | 32 | } 33 | 34 | class IGZLocationTests: XCTestCase { 35 | 36 | var locationManager: IGZLocationManager! 37 | 38 | override func setUp() { 39 | super.setUp() 40 | 41 | locationManager = IGZLocationMock() 42 | locationManager.delegates.append(self) 43 | 44 | } 45 | 46 | func testRegionAvailable() { 47 | XCTAssertTrue(locationManager.regionAvailable(CLCircularRegion.self)) 48 | } 49 | 50 | func testAuthorized() { 51 | XCTAssertFalse(locationManager.authorized(.notDetermined)) 52 | XCTAssertFalse(locationManager.authorized(.restricted)) 53 | XCTAssertFalse(locationManager.authorized(.denied)) 54 | XCTAssertTrue(locationManager.authorized(.authorizedAlways)) 55 | XCTAssertTrue(locationManager.authorized(.authorizedWhenInUse)) 56 | } 57 | 58 | func testLocationsUpdates() { 59 | locationManager.locationsHandlers.append { locations in 60 | XCTAssertNotNil(locations) 61 | XCTAssertNotNil(self.locationManager.location) 62 | XCTAssertTrue(locations.contains(self.locationManager.location!)) 63 | } 64 | locationManager.startLocationUpdates { locations in 65 | XCTAssertNotNil(locations) 66 | XCTAssertNotNil(self.locationManager.location) 67 | XCTAssertTrue(locations.contains(self.locationManager.location!)) 68 | } 69 | } 70 | 71 | func testLocationUpdates() { 72 | locationManager.locationHandlers.append { location in 73 | XCTAssertNotNil(location) 74 | XCTAssertNotNil(self.locationManager.location) 75 | XCTAssertEqual(location, self.locationManager.location) 76 | } 77 | if #available(iOS 9.0, *) { 78 | locationManager.requestLocation { location in 79 | XCTAssertNotNil(location) 80 | XCTAssertNotNil(self.locationManager.location) 81 | XCTAssertEqual(location, self.locationManager.location) 82 | } 83 | } 84 | } 85 | 86 | override func tearDown() { 87 | 88 | locationManager = nil 89 | 90 | super.tearDown() 91 | } 92 | 93 | } 94 | 95 | extension IGZLocationTests: IGZLocationDelegate { 96 | 97 | func didUpdateLocations(_ locations: [CLLocation]) { 98 | XCTAssertNotNil(locations) 99 | XCTAssertNotNil(self.locationManager.location) 100 | XCTAssertTrue(locations.contains(self.locationManager.location!)) 101 | } 102 | 103 | func didUpdateLocation(_ location: CLLocation) { 104 | XCTAssertNotNil(location) 105 | XCTAssertNotNil(self.locationManager.location) 106 | XCTAssertEqual(location, self.locationManager.location) 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /IGZLocationTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Intelygenz 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. -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | import PackageDescription 2 | 3 | let package = Package( 4 | name: "IGZLocation", 5 | dependencies : [], 6 | exclude: ["IGZLocationMap", "IGZLocationMapUITests", "IGZLocationTests"] 7 | ) 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # IGZLocation 2 | 3 | [![Twitter](https://img.shields.io/badge/contact-@intelygenz-0FABFF.svg?style=flat)](http://twitter.com/intelygenz) 4 | [![Version](https://img.shields.io/cocoapods/v/IGZLocation.svg?style=flat)](http://cocoapods.org/pods/IGZLocation) 5 | [![License](https://img.shields.io/cocoapods/l/IGZLocation.svg?style=flat)](http://cocoapods.org/pods/IGZLocation) 6 | [![Platform](https://img.shields.io/cocoapods/p/IGZLocation.svg?style=flat)](http://cocoapods.org/pods/IGZLocation) 7 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 8 | [![Swift Package Manager Compatible](https://img.shields.io/badge/Swift%20Package%20Manager-compatible-4BC51D.svg?style=flat)](https://github.com/apple/swift-package-manager) 9 | [![Build Status](https://travis-ci.org/intelygenz/IGZLocation.svg?branch=master)](https://travis-ci.org/intelygenz/IGZLocation) 10 | 11 | CLLocationManager Swift 4 wrapper with multiple closure handlers and delegates allowed, notifications, sequential geofencing, self-authorization and, of course, everything is testable. #InCodeWeTrust 12 | 13 | ![IGZLocation Screenshot](https://raw.githubusercontent.com/intelygenz/IGZLocation/master/screenshot.gif) 14 | 15 | ## Installation 16 | 17 | IGZLocation is available through [CocoaPods](http://cocoapods.org). To install 18 | it, simply add the following line to your Podfile: 19 | 20 | ```ruby 21 | pod "IGZLocation" 22 | ``` 23 | 24 | For Swift 3 compatibility use: 25 | 26 | ```ruby 27 | pod 'IGZLocation', '~> 1.0' 28 | ``` 29 | 30 | #### Or you can install it with [Carthage](https://github.com/Carthage/Carthage): 31 | 32 | ```ogdl 33 | github "intelygenz/IGZLocation" 34 | ``` 35 | 36 | #### Or install it with [Swift Package Manager](https://swift.org/package-manager/): 37 | 38 | ```swift 39 | dependencies: [ 40 | .Package(url: "https://github.com/intelygenz/IGZLocation.git") 41 | ] 42 | ``` 43 | 44 | ## Usage 45 | 46 | ```swift 47 | _ = IGZLocation.shared.authorize(.authorizedAlways) { status in 48 | 49 | } 50 | 51 | IGZLocation.shared.requestLocation { location in 52 | 53 | } 54 | 55 | IGZLocation.shared.startRegionUpdates(region, sequential: true, notify: true, { region, state in 56 | 57 | }) 58 | 59 | IGZLocation.shared.startVisitUpdates { visit, visiting in 60 | 61 | } 62 | 63 | IGZLocation.shared.startHeadingUpdates { heading in 64 | 65 | } 66 | ``` 67 | 68 | ## Etc. 69 | 70 | * Contributions are very welcome. 71 | * Attribution is appreciated (let's spread the word!), but not mandatory. 72 | 73 | ## Author 74 | 75 | [alexruperez](https://github.com/alexruperez), alejandro.ruperez@intelygenz.com 76 | 77 | ## License 78 | 79 | IGZLocation is available under the MIT license. See the LICENSE file for more info. 80 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | remote_theme: intelygenz/architect 2 | -------------------------------------------------------------------------------- /screenshot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intelygenz/IGZLocation/de54a260579cb157faeacda566cfc9726a901e44/screenshot.gif --------------------------------------------------------------------------------