├── .editorconfig ├── .gitignore ├── .gitmodules ├── .swift-version ├── .travis.yml ├── Example ├── Example.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── Example.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── Example │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── Info.plist │ └── ViewController.swift ├── Podfile └── Podfile.lock ├── GoogleMaps.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── GoogleMapsDirections.podspec ├── GoogleMapsDirections ├── GoogleMapsDirections.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ ├── GoogleMapsDirections iOS.xcscheme │ │ ├── GoogleMapsDirections macOS.xcscheme │ │ ├── GoogleMapsDirections tvOS.xcscheme │ │ └── GoogleMapsDirections watchOS.xcscheme ├── GoogleMapsDirections │ ├── GoogleMapsDirections.h │ └── Info.plist ├── GoogleMapsDirectionsTests │ ├── GoogleMapsDirectionsTests.swift │ └── Info.plist └── Podfile ├── GooglePlaces ├── GooglePlaces.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ ├── GooglePlaces iOS.xcscheme │ │ ├── GooglePlaces macOS.xcscheme │ │ ├── GooglePlaces tvOS.xcscheme │ │ └── GooglePlaces watchOS.xcscheme ├── GooglePlaces │ ├── GooglePlaces.h │ └── Info.plist └── GooglePlacesTests │ ├── Info.plist │ ├── PlaceAutocompleteTests.swift │ └── PlaceDetailsTests.swift ├── GooglePlacesAPI.podspec ├── LICENSE ├── README.md └── Source ├── Core ├── Dictionary+Extensions.swift ├── GoogleMapsService.swift ├── ObjectMapperTransformers │ ├── DateTransformInteger.swift │ └── LocationCoordinate2DTransform.swift └── SharedTypes.swift ├── Google Maps Directions API ├── GoogleMapsDirections.swift ├── Response.swift └── Types.swift └── Google Places API ├── GooglePlaces.swift ├── PlaceAutocompleteResponse.swift ├── PlaceDetailsResponse.swift └── Types.swift /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{h,m,mm,swift}] 2 | indent_style = space 3 | indent_size = 4 -------------------------------------------------------------------------------- /.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 | *.xccheckout 22 | *.moved-aside 23 | *.xcuserstate 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 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 | Example/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/docs/Gitignore.md 61 | 62 | fastlane/report.xml 63 | fastlane/screenshots 64 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Submodules/ObjectMapper"] 2 | path = Submodules/ObjectMapper 3 | url = https://github.com/Hearst-DD/ObjectMapper.git 4 | [submodule "Submodules/Alamofire"] 5 | path = Submodules/Alamofire 6 | url = https://github.com/Alamofire/Alamofire.git 7 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 4.2 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: swift 2 | osx_image: xcode10 3 | env: 4 | global: 5 | - LC_CTYPE=en_US.UTF-8 6 | - LANG=en_US.UTF-8 7 | 8 | - WORKSPACE=GoogleMaps.xcworkspace 9 | 10 | - DIRECTIONS_IOS_FRAMEWORK_SCHEME="GoogleMapsDirections iOS" 11 | - DIRECTIONS_MACOS_FRAMEWORK_SCHEME="GoogleMapsDirections macOS" 12 | - DIRECTIONS_TVOS_FRAMEWORK_SCHEME="GoogleMapsDirections tvOS" 13 | - DIRECTIONS_WATCHOS_FRAMEWORK_SCHEME="GoogleMapsDirections watchOS" 14 | 15 | - PLACES_IOS_FRAMEWORK_SCHEME="GooglePlaces iOS" 16 | - PLACES_MACOS_FRAMEWORK_SCHEME="GooglePlaces macOS" 17 | - PLACES_TVOS_FRAMEWORK_SCHEME="GooglePlaces tvOS" 18 | - PLACES_WATCHOS_FRAMEWORK_SCHEME="GooglePlaces watchOS" 19 | 20 | - EXAMPLE_SCHEME="iOS Example" 21 | 22 | matrix: 23 | # GoogleMapsDirections 24 | ## iOS 25 | - DESTINATION="OS=12.0,name=iPhone XS Max" SCHEME="$DIRECTIONS_IOS_FRAMEWORK_SCHEME" RUN_TESTS="YES" 26 | # - DESTINATION="OS=11.4,name=iPhone X" SCHEME="$DIRECTIONS_IOS_FRAMEWORK_SCHEME" RUN_TESTS="YES" 27 | # - DESTINATION="OS=10.3.1,name=iPhone 7 Plus" SCHEME="$DIRECTIONS_IOS_FRAMEWORK_SCHEME" RUN_TESTS="YES" 28 | - DESTINATION="OS=9.3,name=iPhone 6s Plus" SCHEME="$DIRECTIONS_IOS_FRAMEWORK_SCHEME" RUN_TESTS="YES" 29 | 30 | ## macOS 31 | - DESTINATION="arch=x86_64" SCHEME="$DIRECTIONS_MACOS_FRAMEWORK_SCHEME" RUN_TESTS="YES" 32 | 33 | ## tvOS 34 | - DESTINATION="OS=12.0,name=Apple TV 4K" SCHEME="$DIRECTIONS_TVOS_FRAMEWORK_SCHEME" RUN_TESTS="YES" 35 | - DESTINATION="OS=11.4,name=Apple TV 4K" SCHEME="$DIRECTIONS_TVOS_FRAMEWORK_SCHEME" RUN_TESTS="YES" 36 | - DESTINATION="OS=10.2,name=Apple TV 1080p" SCHEME="$DIRECTIONS_TVOS_FRAMEWORK_SCHEME" RUN_TESTS="YES" 37 | - DESTINATION="OS=9.2,name=Apple TV 1080p" SCHEME="$DIRECTIONS_TVOS_FRAMEWORK_SCHEME" RUN_TESTS="YES" 38 | 39 | ## watchOS 40 | - DESTINATION="OS=5.0,name=Apple Watch Series 4 - 44mm" SCHEME="$DIRECTIONS_WATCHOS_FRAMEWORK_SCHEME" RUN_TESTS="NO" 41 | - DESTINATION="OS=4.2,name=Apple Watch Series 3 - 42mm" SCHEME="$DIRECTIONS_WATCHOS_FRAMEWORK_SCHEME" RUN_TESTS="NO" 42 | - DESTINATION="OS=3.2,name=Apple Watch Series 2 - 42mm" SCHEME="$DIRECTIONS_WATCHOS_FRAMEWORK_SCHEME" RUN_TESTS="NO" 43 | - DESTINATION="OS=2.2,name=Apple Watch - 42mm" SCHEME="$DIRECTIONS_WATCHOS_FRAMEWORK_SCHEME" RUN_TESTS="NO" 44 | 45 | # GooglePlaces 46 | ## iOS 47 | - DESTINATION="OS=12.0,name=iPhone XS Max" SCHEME="$PLACES_IOS_FRAMEWORK_SCHEME" RUN_TESTS="YES" 48 | # - DESTINATION="OS=11.4,name=iPhone X" SCHEME="$PLACES_IOS_FRAMEWORK_SCHEME" RUN_TESTS="YES" 49 | # - DESTINATION="OS=10.3.1,name=iPhone 7 Plus" SCHEME="$PLACES_IOS_FRAMEWORK_SCHEME" RUN_TESTS="YES" 50 | - DESTINATION="OS=9.3,name=iPhone 6s Plus" SCHEME="$PLACES_IOS_FRAMEWORK_SCHEME" RUN_TESTS="YES" 51 | 52 | ## macOS 53 | - DESTINATION="arch=x86_64" SCHEME="$PLACES_MACOS_FRAMEWORK_SCHEME" RUN_TESTS="YES" 54 | 55 | ## tvOS 56 | - DESTINATION="OS=12.0,name=Apple TV 4K" SCHEME="$PLACES_TVOS_FRAMEWORK_SCHEME" RUN_TESTS="YES" 57 | - DESTINATION="OS=11.4,name=Apple TV 4K" SCHEME="$PLACES_TVOS_FRAMEWORK_SCHEME" RUN_TESTS="YES" 58 | - DESTINATION="OS=10.2,name=Apple TV 1080p" SCHEME="$PLACES_TVOS_FRAMEWORK_SCHEME" RUN_TESTS="YES" 59 | - DESTINATION="OS=9.2,name=Apple TV 1080p" SCHEME="$PLACES_TVOS_FRAMEWORK_SCHEME" RUN_TESTS="YES" 60 | 61 | ## watchOS 62 | - DESTINATION="OS=5.0,name=Apple Watch Series 4 - 44mm" SCHEME="$PLACES_WATCHOS_FRAMEWORK_SCHEME" RUN_TESTS="NO" 63 | - DESTINATION="OS=4.2,name=Apple Watch Series 3 - 42mm" SCHEME="$PLACES_WATCHOS_FRAMEWORK_SCHEME" RUN_TESTS="NO" 64 | - DESTINATION="OS=3.2,name=Apple Watch Series 2 - 42mm" SCHEME="$PLACES_WATCHOS_FRAMEWORK_SCHEME" RUN_TESTS="NO" 65 | - DESTINATION="OS=2.2,name=Apple Watch - 42mm" SCHEME="$PLACES_WATCHOS_FRAMEWORK_SCHEME" RUN_TESTS="NO" 66 | 67 | before_install: 68 | - gem install cocoapods --no-rdoc --no-ri --no-document --quiet 69 | - gem install xcpretty --no-rdoc --no-ri --no-document --quiet 70 | 71 | script: 72 | - set -o pipefail 73 | - xcodebuild -version 74 | - xcodebuild -showsdks 75 | - xcodebuild -showdestinations -workspace "$WORKSPACE" -scheme "$SCHEME" 76 | 77 | # Build Framework in Debug and Run Tests if specified 78 | - if [ $RUN_TESTS == "YES" ]; then 79 | xcodebuild clean test -workspace "$WORKSPACE" -scheme "$SCHEME" -destination "$DESTINATION" -configuration Debug | xcpretty; 80 | else 81 | xcodebuild clean build -workspace "$WORKSPACE" -scheme "$SCHEME" -destination "$DESTINATION" -configuration Debug | xcpretty; 82 | fi 83 | 84 | # Build Framework in Release 85 | - xcodebuild clean build -workspace "$WORKSPACE" -scheme "$SCHEME" -destination "$DESTINATION" -configuration Release | xcpretty; 86 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 02DDFDEE1C6E9DBB008413ED /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02DDFDED1C6E9DBB008413ED /* AppDelegate.swift */; }; 11 | 02DDFDF01C6E9DBB008413ED /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02DDFDEF1C6E9DBB008413ED /* ViewController.swift */; }; 12 | 02DDFDF31C6E9DBB008413ED /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 02DDFDF11C6E9DBB008413ED /* Main.storyboard */; }; 13 | 02DDFDF51C6E9DBB008413ED /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 02DDFDF41C6E9DBB008413ED /* Assets.xcassets */; }; 14 | 02DDFDF81C6E9DBB008413ED /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 02DDFDF61C6E9DBB008413ED /* LaunchScreen.storyboard */; }; 15 | 3033556586137811004E906F /* Pods_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9ECEF166F3448C28391CA4AF /* Pods_Example.framework */; }; 16 | /* End PBXBuildFile section */ 17 | 18 | /* Begin PBXFileReference section */ 19 | 02DDFDEA1C6E9DBB008413ED /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; 20 | 02DDFDED1C6E9DBB008413ED /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 21 | 02DDFDEF1C6E9DBB008413ED /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 22 | 02DDFDF21C6E9DBB008413ED /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 23 | 02DDFDF41C6E9DBB008413ED /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 24 | 02DDFDF71C6E9DBB008413ED /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 25 | 02DDFDF91C6E9DBB008413ED /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 26 | 3A451F48E382EF801E893E6C /* Pods-Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Example/Pods-Example.debug.xcconfig"; sourceTree = ""; }; 27 | 9ECEF166F3448C28391CA4AF /* Pods_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 28 | D9FCE7B39072DC8E77B9046A /* Pods-Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-Example/Pods-Example.release.xcconfig"; sourceTree = ""; }; 29 | /* End PBXFileReference section */ 30 | 31 | /* Begin PBXFrameworksBuildPhase section */ 32 | 02DDFDE71C6E9DBB008413ED /* Frameworks */ = { 33 | isa = PBXFrameworksBuildPhase; 34 | buildActionMask = 2147483647; 35 | files = ( 36 | 3033556586137811004E906F /* Pods_Example.framework in Frameworks */, 37 | ); 38 | runOnlyForDeploymentPostprocessing = 0; 39 | }; 40 | /* End PBXFrameworksBuildPhase section */ 41 | 42 | /* Begin PBXGroup section */ 43 | 02DDFDE11C6E9DBB008413ED = { 44 | isa = PBXGroup; 45 | children = ( 46 | 02DDFDEC1C6E9DBB008413ED /* Example */, 47 | 02DDFDEB1C6E9DBB008413ED /* Products */, 48 | 31DB3C9F4E9095263B21CCD9 /* Pods */, 49 | 38AB9233A8E32A008D534A61 /* Frameworks */, 50 | ); 51 | sourceTree = ""; 52 | }; 53 | 02DDFDEB1C6E9DBB008413ED /* Products */ = { 54 | isa = PBXGroup; 55 | children = ( 56 | 02DDFDEA1C6E9DBB008413ED /* Example.app */, 57 | ); 58 | name = Products; 59 | sourceTree = ""; 60 | }; 61 | 02DDFDEC1C6E9DBB008413ED /* Example */ = { 62 | isa = PBXGroup; 63 | children = ( 64 | 02DDFDED1C6E9DBB008413ED /* AppDelegate.swift */, 65 | 02DDFDEF1C6E9DBB008413ED /* ViewController.swift */, 66 | 02DDFDF11C6E9DBB008413ED /* Main.storyboard */, 67 | 02DDFDF41C6E9DBB008413ED /* Assets.xcassets */, 68 | 02DDFDF61C6E9DBB008413ED /* LaunchScreen.storyboard */, 69 | 02DDFDF91C6E9DBB008413ED /* Info.plist */, 70 | ); 71 | path = Example; 72 | sourceTree = ""; 73 | }; 74 | 31DB3C9F4E9095263B21CCD9 /* Pods */ = { 75 | isa = PBXGroup; 76 | children = ( 77 | 3A451F48E382EF801E893E6C /* Pods-Example.debug.xcconfig */, 78 | D9FCE7B39072DC8E77B9046A /* Pods-Example.release.xcconfig */, 79 | ); 80 | name = Pods; 81 | sourceTree = ""; 82 | }; 83 | 38AB9233A8E32A008D534A61 /* Frameworks */ = { 84 | isa = PBXGroup; 85 | children = ( 86 | 9ECEF166F3448C28391CA4AF /* Pods_Example.framework */, 87 | ); 88 | name = Frameworks; 89 | sourceTree = ""; 90 | }; 91 | /* End PBXGroup section */ 92 | 93 | /* Begin PBXNativeTarget section */ 94 | 02DDFDE91C6E9DBB008413ED /* Example */ = { 95 | isa = PBXNativeTarget; 96 | buildConfigurationList = 02DDFDFC1C6E9DBB008413ED /* Build configuration list for PBXNativeTarget "Example" */; 97 | buildPhases = ( 98 | E13F36E8EA63337E8C58969A /* [CP] Check Pods Manifest.lock */, 99 | 02DDFDE61C6E9DBB008413ED /* Sources */, 100 | 02DDFDE71C6E9DBB008413ED /* Frameworks */, 101 | 02DDFDE81C6E9DBB008413ED /* Resources */, 102 | 184F39A19AFC84E9217F7A06 /* [CP] Embed Pods Frameworks */, 103 | 2F846405A3CF42C554865D21 /* [CP] Copy Pods Resources */, 104 | ); 105 | buildRules = ( 106 | ); 107 | dependencies = ( 108 | ); 109 | name = Example; 110 | productName = Example; 111 | productReference = 02DDFDEA1C6E9DBB008413ED /* Example.app */; 112 | productType = "com.apple.product-type.application"; 113 | }; 114 | /* End PBXNativeTarget section */ 115 | 116 | /* Begin PBXProject section */ 117 | 02DDFDE21C6E9DBB008413ED /* Project object */ = { 118 | isa = PBXProject; 119 | attributes = { 120 | LastSwiftUpdateCheck = 0720; 121 | LastUpgradeCheck = 0800; 122 | ORGANIZATIONNAME = "Honghao Zhang"; 123 | TargetAttributes = { 124 | 02DDFDE91C6E9DBB008413ED = { 125 | CreatedOnToolsVersion = 7.2.1; 126 | DevelopmentTeam = UYW9ZSKZAQ; 127 | LastSwiftMigration = 1000; 128 | }; 129 | }; 130 | }; 131 | buildConfigurationList = 02DDFDE51C6E9DBB008413ED /* Build configuration list for PBXProject "Example" */; 132 | compatibilityVersion = "Xcode 3.2"; 133 | developmentRegion = English; 134 | hasScannedForEncodings = 0; 135 | knownRegions = ( 136 | en, 137 | Base, 138 | ); 139 | mainGroup = 02DDFDE11C6E9DBB008413ED; 140 | productRefGroup = 02DDFDEB1C6E9DBB008413ED /* Products */; 141 | projectDirPath = ""; 142 | projectRoot = ""; 143 | targets = ( 144 | 02DDFDE91C6E9DBB008413ED /* Example */, 145 | ); 146 | }; 147 | /* End PBXProject section */ 148 | 149 | /* Begin PBXResourcesBuildPhase section */ 150 | 02DDFDE81C6E9DBB008413ED /* Resources */ = { 151 | isa = PBXResourcesBuildPhase; 152 | buildActionMask = 2147483647; 153 | files = ( 154 | 02DDFDF81C6E9DBB008413ED /* LaunchScreen.storyboard in Resources */, 155 | 02DDFDF51C6E9DBB008413ED /* Assets.xcassets in Resources */, 156 | 02DDFDF31C6E9DBB008413ED /* Main.storyboard in Resources */, 157 | ); 158 | runOnlyForDeploymentPostprocessing = 0; 159 | }; 160 | /* End PBXResourcesBuildPhase section */ 161 | 162 | /* Begin PBXShellScriptBuildPhase section */ 163 | 184F39A19AFC84E9217F7A06 /* [CP] Embed Pods Frameworks */ = { 164 | isa = PBXShellScriptBuildPhase; 165 | buildActionMask = 2147483647; 166 | files = ( 167 | ); 168 | inputPaths = ( 169 | "${PODS_ROOT}/Target Support Files/Pods-Example/Pods-Example-frameworks.sh", 170 | "${BUILT_PRODUCTS_DIR}/Alamofire/Alamofire.framework", 171 | "${BUILT_PRODUCTS_DIR}/GoogleMapsDirections/GoogleMapsDirections.framework", 172 | "${BUILT_PRODUCTS_DIR}/GooglePlacesAPI/GooglePlacesAPI.framework", 173 | "${BUILT_PRODUCTS_DIR}/ObjectMapper/ObjectMapper.framework", 174 | ); 175 | name = "[CP] Embed Pods Frameworks"; 176 | outputPaths = ( 177 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Alamofire.framework", 178 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleMapsDirections.framework", 179 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GooglePlacesAPI.framework", 180 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/ObjectMapper.framework", 181 | ); 182 | runOnlyForDeploymentPostprocessing = 0; 183 | shellPath = /bin/sh; 184 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Example/Pods-Example-frameworks.sh\"\n"; 185 | showEnvVarsInLog = 0; 186 | }; 187 | 2F846405A3CF42C554865D21 /* [CP] Copy Pods Resources */ = { 188 | isa = PBXShellScriptBuildPhase; 189 | buildActionMask = 2147483647; 190 | files = ( 191 | ); 192 | inputPaths = ( 193 | "${PODS_ROOT}/Target Support Files/Pods-Example/Pods-Example-resources.sh", 194 | "${PODS_ROOT}/GoogleMaps/Maps/Frameworks/GoogleMaps.framework/Resources/GoogleMaps.bundle", 195 | ); 196 | name = "[CP] Copy Pods Resources"; 197 | outputPaths = ( 198 | "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/GoogleMaps.bundle", 199 | ); 200 | runOnlyForDeploymentPostprocessing = 0; 201 | shellPath = /bin/sh; 202 | shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Example/Pods-Example-resources.sh\"\n"; 203 | showEnvVarsInLog = 0; 204 | }; 205 | E13F36E8EA63337E8C58969A /* [CP] Check Pods Manifest.lock */ = { 206 | isa = PBXShellScriptBuildPhase; 207 | buildActionMask = 2147483647; 208 | files = ( 209 | ); 210 | inputPaths = ( 211 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock", 212 | "${PODS_ROOT}/Manifest.lock", 213 | ); 214 | name = "[CP] Check Pods Manifest.lock"; 215 | outputPaths = ( 216 | "$(DERIVED_FILE_DIR)/Pods-Example-checkManifestLockResult.txt", 217 | ); 218 | runOnlyForDeploymentPostprocessing = 0; 219 | shellPath = /bin/sh; 220 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; 221 | showEnvVarsInLog = 0; 222 | }; 223 | /* End PBXShellScriptBuildPhase section */ 224 | 225 | /* Begin PBXSourcesBuildPhase section */ 226 | 02DDFDE61C6E9DBB008413ED /* Sources */ = { 227 | isa = PBXSourcesBuildPhase; 228 | buildActionMask = 2147483647; 229 | files = ( 230 | 02DDFDF01C6E9DBB008413ED /* ViewController.swift in Sources */, 231 | 02DDFDEE1C6E9DBB008413ED /* AppDelegate.swift in Sources */, 232 | ); 233 | runOnlyForDeploymentPostprocessing = 0; 234 | }; 235 | /* End PBXSourcesBuildPhase section */ 236 | 237 | /* Begin PBXVariantGroup section */ 238 | 02DDFDF11C6E9DBB008413ED /* Main.storyboard */ = { 239 | isa = PBXVariantGroup; 240 | children = ( 241 | 02DDFDF21C6E9DBB008413ED /* Base */, 242 | ); 243 | name = Main.storyboard; 244 | sourceTree = ""; 245 | }; 246 | 02DDFDF61C6E9DBB008413ED /* LaunchScreen.storyboard */ = { 247 | isa = PBXVariantGroup; 248 | children = ( 249 | 02DDFDF71C6E9DBB008413ED /* Base */, 250 | ); 251 | name = LaunchScreen.storyboard; 252 | sourceTree = ""; 253 | }; 254 | /* End PBXVariantGroup section */ 255 | 256 | /* Begin XCBuildConfiguration section */ 257 | 02DDFDFA1C6E9DBB008413ED /* Debug */ = { 258 | isa = XCBuildConfiguration; 259 | buildSettings = { 260 | ALWAYS_SEARCH_USER_PATHS = NO; 261 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 262 | CLANG_CXX_LIBRARY = "libc++"; 263 | CLANG_ENABLE_MODULES = YES; 264 | CLANG_ENABLE_OBJC_ARC = YES; 265 | CLANG_WARN_BOOL_CONVERSION = YES; 266 | CLANG_WARN_CONSTANT_CONVERSION = YES; 267 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 268 | CLANG_WARN_EMPTY_BODY = YES; 269 | CLANG_WARN_ENUM_CONVERSION = YES; 270 | CLANG_WARN_INFINITE_RECURSION = YES; 271 | CLANG_WARN_INT_CONVERSION = YES; 272 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 273 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 274 | CLANG_WARN_UNREACHABLE_CODE = YES; 275 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 276 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 277 | COPY_PHASE_STRIP = NO; 278 | DEBUG_INFORMATION_FORMAT = dwarf; 279 | ENABLE_STRICT_OBJC_MSGSEND = YES; 280 | ENABLE_TESTABILITY = YES; 281 | GCC_C_LANGUAGE_STANDARD = gnu99; 282 | GCC_DYNAMIC_NO_PIC = NO; 283 | GCC_NO_COMMON_BLOCKS = YES; 284 | GCC_OPTIMIZATION_LEVEL = 0; 285 | GCC_PREPROCESSOR_DEFINITIONS = ( 286 | "DEBUG=1", 287 | "$(inherited)", 288 | ); 289 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 290 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 291 | GCC_WARN_UNDECLARED_SELECTOR = YES; 292 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 293 | GCC_WARN_UNUSED_FUNCTION = YES; 294 | GCC_WARN_UNUSED_VARIABLE = YES; 295 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 296 | MTL_ENABLE_DEBUG_INFO = YES; 297 | ONLY_ACTIVE_ARCH = YES; 298 | SDKROOT = iphoneos; 299 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 300 | SWIFT_VERSION = 4.2; 301 | }; 302 | name = Debug; 303 | }; 304 | 02DDFDFB1C6E9DBB008413ED /* Release */ = { 305 | isa = XCBuildConfiguration; 306 | buildSettings = { 307 | ALWAYS_SEARCH_USER_PATHS = NO; 308 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 309 | CLANG_CXX_LIBRARY = "libc++"; 310 | CLANG_ENABLE_MODULES = YES; 311 | CLANG_ENABLE_OBJC_ARC = YES; 312 | CLANG_WARN_BOOL_CONVERSION = YES; 313 | CLANG_WARN_CONSTANT_CONVERSION = YES; 314 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 315 | CLANG_WARN_EMPTY_BODY = YES; 316 | CLANG_WARN_ENUM_CONVERSION = YES; 317 | CLANG_WARN_INFINITE_RECURSION = YES; 318 | CLANG_WARN_INT_CONVERSION = YES; 319 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 320 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 321 | CLANG_WARN_UNREACHABLE_CODE = YES; 322 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 323 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 324 | COPY_PHASE_STRIP = NO; 325 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 326 | ENABLE_NS_ASSERTIONS = NO; 327 | ENABLE_STRICT_OBJC_MSGSEND = YES; 328 | GCC_C_LANGUAGE_STANDARD = gnu99; 329 | GCC_NO_COMMON_BLOCKS = YES; 330 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 331 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 332 | GCC_WARN_UNDECLARED_SELECTOR = YES; 333 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 334 | GCC_WARN_UNUSED_FUNCTION = YES; 335 | GCC_WARN_UNUSED_VARIABLE = YES; 336 | IPHONEOS_DEPLOYMENT_TARGET = 9.2; 337 | MTL_ENABLE_DEBUG_INFO = NO; 338 | SDKROOT = iphoneos; 339 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 340 | SWIFT_VERSION = 4.2; 341 | VALIDATE_PRODUCT = YES; 342 | }; 343 | name = Release; 344 | }; 345 | 02DDFDFD1C6E9DBB008413ED /* Debug */ = { 346 | isa = XCBuildConfiguration; 347 | baseConfigurationReference = 3A451F48E382EF801E893E6C /* Pods-Example.debug.xcconfig */; 348 | buildSettings = { 349 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 350 | DEVELOPMENT_TEAM = UYW9ZSKZAQ; 351 | INFOPLIST_FILE = Example/Info.plist; 352 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 353 | PRODUCT_BUNDLE_IDENTIFIER = com.honghaoz.Example; 354 | PRODUCT_NAME = "$(TARGET_NAME)"; 355 | SWIFT_VERSION = 4.2; 356 | }; 357 | name = Debug; 358 | }; 359 | 02DDFDFE1C6E9DBB008413ED /* Release */ = { 360 | isa = XCBuildConfiguration; 361 | baseConfigurationReference = D9FCE7B39072DC8E77B9046A /* Pods-Example.release.xcconfig */; 362 | buildSettings = { 363 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 364 | DEVELOPMENT_TEAM = UYW9ZSKZAQ; 365 | INFOPLIST_FILE = Example/Info.plist; 366 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 367 | PRODUCT_BUNDLE_IDENTIFIER = com.honghaoz.Example; 368 | PRODUCT_NAME = "$(TARGET_NAME)"; 369 | SWIFT_VERSION = 4.2; 370 | }; 371 | name = Release; 372 | }; 373 | /* End XCBuildConfiguration section */ 374 | 375 | /* Begin XCConfigurationList section */ 376 | 02DDFDE51C6E9DBB008413ED /* Build configuration list for PBXProject "Example" */ = { 377 | isa = XCConfigurationList; 378 | buildConfigurations = ( 379 | 02DDFDFA1C6E9DBB008413ED /* Debug */, 380 | 02DDFDFB1C6E9DBB008413ED /* Release */, 381 | ); 382 | defaultConfigurationIsVisible = 0; 383 | defaultConfigurationName = Release; 384 | }; 385 | 02DDFDFC1C6E9DBB008413ED /* Build configuration list for PBXNativeTarget "Example" */ = { 386 | isa = XCConfigurationList; 387 | buildConfigurations = ( 388 | 02DDFDFD1C6E9DBB008413ED /* Debug */, 389 | 02DDFDFE1C6E9DBB008413ED /* Release */, 390 | ); 391 | defaultConfigurationIsVisible = 0; 392 | defaultConfigurationName = Release; 393 | }; 394 | /* End XCConfigurationList section */ 395 | }; 396 | rootObject = 02DDFDE21C6E9DBB008413ED /* Project object */; 397 | } 398 | -------------------------------------------------------------------------------- /Example/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/Example.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/Example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Example/Example/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Example 4 | // 5 | // Created by Honghao Zhang on 2016-02-12. 6 | // Copyright © 2016 Honghao Zhang. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 18 | // 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 throttle down OpenGL ES frame rates. 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 inactive 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 | -------------------------------------------------------------------------------- /Example/Example/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 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /Example/Example/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 | -------------------------------------------------------------------------------- /Example/Example/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 | -------------------------------------------------------------------------------- /Example/Example/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Example/Example/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // Example 4 | // 5 | // Created by Honghao Zhang on 2016-02-12. 6 | // Copyright © 2016 Honghao Zhang. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import GoogleMaps 11 | import GoogleMapsDirections 12 | import GooglePlacesAPI 13 | 14 | class ViewController: UIViewController { 15 | 16 | override func viewDidLoad() { 17 | super.viewDidLoad() 18 | 19 | // Google Maps Directions 20 | GoogleMapsDirections.provide(apiKey: "AIzaSyDftpY3fi6x_TL4rntL8pgZb-A8mf6D0Ss") 21 | 22 | let origin = GoogleMapsDirections.Place.stringDescription(address: "Davis Center, Waterloo, Canada") 23 | let destination = GoogleMapsDirections.Place.stringDescription(address: "Conestoga Mall, Waterloo, Canada") 24 | 25 | // You can also use coordinates or placeID for a place 26 | // let origin = Place.Coordinate(coordinate: LocationCoordinate2D(latitude: 43.4697354, longitude: -80.5397377)) 27 | // let origin = Place.PlaceID(id: "ChIJb9sw59k0K4gRZZlYrnOomfc") 28 | 29 | GoogleMapsDirections.direction(fromOrigin: origin, toDestination: destination) { (response, error) -> Void in 30 | // Check Status Code 31 | guard response?.status == GoogleMapsDirections.StatusCode.ok else { 32 | // Status Code is Not OK 33 | debugPrint(response?.errorMessage ?? "") 34 | return 35 | } 36 | 37 | // Use .result or .geocodedWaypoints to access response details 38 | // response will have same structure as what Google Maps Directions API returns 39 | debugPrint("it has \(response?.routes.count ?? 0) routes") 40 | } 41 | 42 | // Google Places 43 | GooglePlaces.provide(apiKey: "AIzaSyDftpY3fi6x_TL4rntL8pgZb-A8mf6D0Ss") 44 | 45 | GooglePlaces.placeAutocomplete(forInput: "Pub") { (response, error) -> Void in 46 | // Check Status Code 47 | guard response?.status == GooglePlaces.StatusCode.ok else { 48 | // Status Code is Not OK 49 | debugPrint(response?.errorMessage ?? "") 50 | return 51 | } 52 | 53 | // Use .predictions to access response details 54 | debugPrint("first matched result: \(response?.predictions.first?.description ?? "nil")") 55 | } 56 | 57 | GooglePlaces.placeDetails(forPlaceID: "ChIJb9sw59k0K4gRZZlYrnOomfc") { (response, error) -> Void in 58 | // Check Status Code 59 | guard response?.status == GooglePlaces.StatusCode.ok else { 60 | // Status Code is Not OK 61 | debugPrint(response?.errorMessage ?? "") 62 | return 63 | } 64 | 65 | // Use .result to access response details 66 | debugPrint("the formated address is: \(response?.result?.formattedAddress ?? "nil")") 67 | } 68 | } 69 | } 70 | 71 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | platform :ios, '9.0' 2 | 3 | target 'Example' do 4 | use_frameworks! 5 | 6 | pod 'GoogleMaps' 7 | pod 'GoogleMapsDirections', :path => '../GoogleMapsDirections.podspec' 8 | pod 'GooglePlacesAPI', :path => '../GooglePlacesAPI.podspec' 9 | 10 | end 11 | -------------------------------------------------------------------------------- /Example/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Alamofire (4.7.3) 3 | - GoogleMaps (2.7.0): 4 | - GoogleMaps/Maps (= 2.7.0) 5 | - GoogleMaps/Base (2.7.0) 6 | - GoogleMaps/Maps (2.7.0): 7 | - GoogleMaps/Base 8 | - GoogleMapsDirections (1.1.4): 9 | - Alamofire (~> 4) 10 | - ObjectMapper (~> 3) 11 | - GooglePlacesAPI (1.1.4): 12 | - Alamofire (~> 4) 13 | - ObjectMapper (~> 3) 14 | - ObjectMapper (3.3.0) 15 | 16 | DEPENDENCIES: 17 | - GoogleMaps 18 | - GoogleMapsDirections (from `../GoogleMapsDirections.podspec`) 19 | - GooglePlacesAPI (from `../GooglePlacesAPI.podspec`) 20 | 21 | SPEC REPOS: 22 | https://github.com/cocoapods/specs.git: 23 | - Alamofire 24 | - GoogleMaps 25 | - ObjectMapper 26 | 27 | EXTERNAL SOURCES: 28 | GoogleMapsDirections: 29 | :path: "../GoogleMapsDirections.podspec" 30 | GooglePlacesAPI: 31 | :path: "../GooglePlacesAPI.podspec" 32 | 33 | SPEC CHECKSUMS: 34 | Alamofire: c7287b6e5d7da964a70935e5db17046b7fde6568 35 | GoogleMaps: f79af95cb24d869457b1f961c93d3ce8b2f3b848 36 | GoogleMapsDirections: 7e6b825d50af94cfe47bfd8b0fac9508f760d6a2 37 | GooglePlacesAPI: 42600345b9df5b0b7dc2816f953c7cffe163092a 38 | ObjectMapper: b612bf8c8e99c4dc0bb6013a51f7c27966ed5da9 39 | 40 | PODFILE CHECKSUM: 161bb96c63f609f04c7568a1558b0e2c9c0b98a1 41 | 42 | COCOAPODS: 1.6.0.beta.1 43 | -------------------------------------------------------------------------------- /GoogleMaps.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /GoogleMaps.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /GoogleMapsDirections.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "GoogleMapsDirections" 3 | s.version = "1.1.4" 4 | s.summary = "Swift Wrapper on Google Maps Directions API" 5 | s.description = <<-DESC 6 | Swift Wrapper on Google Maps Directions API 7 | https://developers.google.com/maps/documentation/directions/intro 8 | 9 | DESC 10 | s.homepage = "https://github.com/honghaoz/Swift-Google-Maps-API" 11 | s.license = { :type => 'MIT', :file => 'LICENSE' } 12 | s.author = { "Honghao Zhang" => "zhh358@gmail.com" } 13 | s.source = { :git => "https://github.com/honghaoz/Swift-Google-Maps-API.git", :tag => s.version.to_s } 14 | 15 | s.ios.deployment_target = "8.0" 16 | s.osx.deployment_target = "10.10" 17 | s.watchos.deployment_target = "2.0" 18 | s.tvos.deployment_target = "9.0" 19 | 20 | s.requires_arc = true 21 | s.source_files = "Source/Core/**/*.*", "Source/Google Maps Directions API/**/*.*" 22 | s.module_name = "GoogleMapsDirections" 23 | 24 | s.dependency 'Alamofire', '~> 4' 25 | s.dependency 'ObjectMapper', '~> 3' 26 | 27 | end 28 | -------------------------------------------------------------------------------- /GoogleMapsDirections/GoogleMapsDirections.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /GoogleMapsDirections/GoogleMapsDirections.xcodeproj/xcshareddata/xcschemes/GoogleMapsDirections iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 65 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 84 | 90 | 91 | 92 | 93 | 95 | 96 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /GoogleMapsDirections/GoogleMapsDirections.xcodeproj/xcshareddata/xcschemes/GoogleMapsDirections macOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /GoogleMapsDirections/GoogleMapsDirections.xcodeproj/xcshareddata/xcschemes/GoogleMapsDirections tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /GoogleMapsDirections/GoogleMapsDirections.xcodeproj/xcshareddata/xcschemes/GoogleMapsDirections watchOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /GoogleMapsDirections/GoogleMapsDirections/GoogleMapsDirections.h: -------------------------------------------------------------------------------- 1 | // 2 | // GoogleMapsDirections.h 3 | // GoogleMapsDirections 4 | // 5 | // Created by Honghao Zhang on 2016-01-27. 6 | // Copyright © 2016 Honghao Zhang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for GoogleMapsDirections. 12 | FOUNDATION_EXPORT double GoogleMapsDirectionsVersionNumber; 13 | 14 | //! Project version string for GoogleMapsDirections. 15 | FOUNDATION_EXPORT const unsigned char GoogleMapsDirectionsVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /GoogleMapsDirections/GoogleMapsDirections/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.4 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /GoogleMapsDirections/GoogleMapsDirectionsTests/GoogleMapsDirectionsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GoogleMapsDirectionsTests.swift 3 | // GoogleMapsDirectionsTests 4 | // 5 | // Created by Honghao Zhang on 2016-01-27. 6 | // Copyright © 2016 Honghao Zhang. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import GoogleMapsDirections 11 | 12 | class GoogleMapsDirectionsTests: XCTestCase { 13 | typealias Place = GoogleMapsDirections.Place 14 | typealias LocationCoordinate2D = GoogleMapsService.LocationCoordinate2D 15 | 16 | let DCInStringDescription = Place.stringDescription(address: "Davis Center, Waterloo, Canada") 17 | let DCInPostalCode = Place.stringDescription(address: "N2L 3G1, Canada") 18 | let DCInCoordinate = Place.coordinate(coordinate: LocationCoordinate2D(latitude: 43.4697354, longitude: -80.5397377)) 19 | let CMallInStringDescription = Place.stringDescription(address: "Conestoga Mall, Waterloo, Canada") 20 | let CMallInPostalCode = Place.stringDescription(address: "N2L 5W6, Waterloo, Canada") 21 | 22 | override func setUp() { 23 | super.setUp() 24 | GoogleMapsDirections.provide(apiKey: "AIzaSyDftpY3fi6x_TL4rntL8pgZb-A8mf6D0Ss") 25 | } 26 | 27 | override func tearDown() { 28 | // Put teardown code here. This method is called after the invocation of each test method in the class. 29 | super.tearDown() 30 | } 31 | 32 | func testAPIIsInvalid() { 33 | let expectation = self.expectation(description: "Direcion from origin to destination") 34 | GoogleMapsDirections.provide(apiKey: "fake_key") 35 | 36 | GoogleMapsDirections.direction(fromOrigin: DCInStringDescription, toDestination: CMallInStringDescription) { (response, error) -> Void in 37 | XCTAssertNotNil(error) 38 | XCTAssertNotNil(response) 39 | XCTAssertNotNil(response?.errorMessage) 40 | XCTAssertEqual(response?.status, GoogleMapsDirections.StatusCode.requestDenied) 41 | expectation.fulfill() 42 | } 43 | 44 | waitForExpectations(timeout: 5.0, handler: nil) 45 | } 46 | 47 | func testAPIIsValid() { 48 | let expectation = self.expectation(description: "Direcion from origin to destination") 49 | 50 | GoogleMapsDirections.direction(fromOrigin: DCInPostalCode, toDestination: CMallInPostalCode) { (response, error) -> Void in 51 | XCTAssertNil(error) 52 | XCTAssertNotNil(response) 53 | XCTAssertEqual(response?.status, GoogleMapsDirections.StatusCode.ok) 54 | XCTAssertEqual(response?.geocodedWaypoints.count, 2) 55 | XCTAssertEqual(response?.routes.count, 1) 56 | expectation.fulfill() 57 | } 58 | 59 | waitForExpectations(timeout: 5.0, handler: nil) 60 | } 61 | 62 | func testAlternatives() { 63 | let expectation = self.expectation(description: "When alternatives if true, more than one routes returned") 64 | 65 | GoogleMapsDirections.direction(fromOrigin: DCInPostalCode, toDestination: CMallInPostalCode, alternatives: true) { (response, error) -> Void in 66 | XCTAssertNil(error) 67 | XCTAssertNotNil(response) 68 | XCTAssertEqual(response!.status, GoogleMapsDirections.StatusCode.ok) 69 | XCTAssertTrue(response!.routes.count > 1) 70 | expectation.fulfill() 71 | } 72 | 73 | waitForExpectations(timeout: 5.0, handler: nil) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /GoogleMapsDirections/GoogleMapsDirectionsTests/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.2 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /GoogleMapsDirections/Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment this line to define a global platform for your project 2 | # platform :ios, '8.0' 3 | use_frameworks! 4 | 5 | def dependency_pods 6 | pod 'ObjectMapper', '~> 1.0' 7 | pod 'Alamofire', '~> 3.0' 8 | end 9 | 10 | target 'GoogleMapsDirections iOS' do 11 | dependency_pods 12 | end 13 | 14 | target 'GoogleMapsDirections OSX' do 15 | dependency_pods 16 | end 17 | 18 | target 'GoogleMapsDirections watchOS' do 19 | dependency_pods 20 | end 21 | 22 | target 'GoogleMapsDirections tvOS' do 23 | dependency_pods 24 | end 25 | 26 | post_install do |installer| 27 | installer.pods_project.targets.each do |target| 28 | if target.name == 'Alamofire' or target.name == 'ObjectMapper' 29 | target.build_configurations.each do |config| 30 | config.build_settings['APPLICATION_EXTENSION_API_ONLY'] = 'YES' 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /GooglePlaces/GooglePlaces.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /GooglePlaces/GooglePlaces.xcodeproj/xcshareddata/xcschemes/GooglePlaces iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 65 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 84 | 90 | 91 | 92 | 93 | 95 | 96 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /GooglePlaces/GooglePlaces.xcodeproj/xcshareddata/xcschemes/GooglePlaces macOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /GooglePlaces/GooglePlaces.xcodeproj/xcshareddata/xcschemes/GooglePlaces tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /GooglePlaces/GooglePlaces.xcodeproj/xcshareddata/xcschemes/GooglePlaces watchOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 34 | 35 | 45 | 46 | 52 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 70 | 71 | 72 | 73 | 75 | 76 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /GooglePlaces/GooglePlaces/GooglePlaces.h: -------------------------------------------------------------------------------- 1 | // 2 | // GooglePlaces.h 3 | // GooglePlaces 4 | // 5 | // Created by Honghao Zhang on 2016-02-12. 6 | // Copyright © 2016 Honghao Zhang. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for GooglePlaces. 12 | FOUNDATION_EXPORT double GooglePlacesVersionNumber; 13 | 14 | //! Project version string for GooglePlaces. 15 | FOUNDATION_EXPORT const unsigned char GooglePlacesVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /GooglePlaces/GooglePlaces/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.4 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /GooglePlaces/GooglePlacesTests/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.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /GooglePlaces/GooglePlacesTests/PlaceAutocompleteTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PlaceAutocompleteTests.swift 3 | // GooglePlacesTests 4 | // 5 | // Created by Honghao Zhang on 2016-02-12. 6 | // Copyright © 2016 Honghao Zhang. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import GooglePlaces 11 | 12 | class PlaceAutocompleteTests: XCTestCase { 13 | typealias LocationCoordinate2D = GoogleMapsService.LocationCoordinate2D 14 | 15 | override func setUp() { 16 | super.setUp() 17 | GooglePlaces.provide(apiKey: "AIzaSyDftpY3fi6x_TL4rntL8pgZb-A8mf6D0Ss") 18 | } 19 | 20 | override func tearDown() { 21 | super.tearDown() 22 | } 23 | 24 | func testAPIIsInvalid() { 25 | let expectation = self.expectation(description: "results") 26 | GooglePlaces.provide(apiKey: "fake_key") 27 | 28 | GooglePlaces.placeAutocomplete(forInput: "Pub") { (response, error) -> Void in 29 | XCTAssertNotNil(error) 30 | XCTAssertNotNil(response) 31 | XCTAssertNotNil(response?.errorMessage) 32 | XCTAssertEqual(response?.status, GooglePlaces.StatusCode.requestDenied) 33 | expectation.fulfill() 34 | } 35 | 36 | waitForExpectations(timeout: 5.0, handler: nil) 37 | } 38 | 39 | func testAPIIsValid() { 40 | let expectation = self.expectation(description: "results") 41 | 42 | GooglePlaces.placeAutocomplete(forInput: "Pub") { (response, error) -> Void in 43 | XCTAssertNil(error) 44 | XCTAssertNotNil(response) 45 | XCTAssertEqual(response?.status, GooglePlaces.StatusCode.ok) 46 | expectation.fulfill() 47 | } 48 | 49 | waitForExpectations(timeout: 5.0, handler: nil) 50 | } 51 | 52 | func testResultsReturned() { 53 | let expectation = self.expectation(description: "It has at least one result returned for `pub`") 54 | 55 | GooglePlaces.placeAutocomplete(forInput: "pub") { (response, error) -> Void in 56 | XCTAssertNil(error) 57 | XCTAssertNotNil(response) 58 | XCTAssertEqual(response!.status, GooglePlaces.StatusCode.ok) 59 | XCTAssertTrue(response!.predictions.count > 0) 60 | expectation.fulfill() 61 | } 62 | 63 | waitForExpectations(timeout: 5.0, handler: nil) 64 | } 65 | 66 | func testResultsMatchedSubstrings() { 67 | let expectation = self.expectation(description: "It has at least one result returned for `pub`") 68 | 69 | let query = "Pub" 70 | 71 | GooglePlaces.placeAutocomplete(forInput: query, locationCoordinate: LocationCoordinate2D(latitude: 43.4697354, longitude: -80.5397377), radius: 10000) { (response, error) -> Void in 72 | XCTAssertNil(error) 73 | XCTAssertNotNil(response) 74 | XCTAssertEqual(response!.status, GooglePlaces.StatusCode.ok) 75 | XCTAssertTrue(response!.predictions.count > 0) 76 | 77 | guard let predictions = response?.predictions else { 78 | XCTAssert(false, "prediction is nil") 79 | return 80 | } 81 | 82 | for prediction in predictions { 83 | XCTAssertEqual(prediction.matchedSubstring[0].length, query.count) 84 | 85 | guard let description = prediction.description, 86 | let length = prediction.matchedSubstring[0].length, 87 | let offset = prediction.matchedSubstring[0].offset else { 88 | XCTAssert(false, "length/offset is nil") 89 | return 90 | } 91 | 92 | let start = description.index(description.startIndex, offsetBy: offset) 93 | let end = description.index(description.startIndex, offsetBy: offset + length) 94 | let substring = description.substring(with: start ..< end) 95 | 96 | XCTAssertEqual(substring.lowercased(), query.lowercased()) 97 | } 98 | 99 | expectation.fulfill() 100 | } 101 | 102 | waitForExpectations(timeout: 5.0, handler: nil) 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /GooglePlaces/GooglePlacesTests/PlaceDetailsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PlaceDetailsTests.swift 3 | // GooglePlaces 4 | // 5 | // Created by Honghao Zhang on 2016-02-20. 6 | // Copyright © 2016 Honghao Zhang. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import GooglePlaces 11 | 12 | class PlaceDetailsTests: XCTestCase { 13 | typealias LocationCoordinate2D = GoogleMapsService.LocationCoordinate2D 14 | 15 | override func setUp() { 16 | super.setUp() 17 | GooglePlaces.provide(apiKey: "AIzaSyDftpY3fi6x_TL4rntL8pgZb-A8mf6D0Ss") 18 | } 19 | 20 | override func tearDown() { 21 | super.tearDown() 22 | } 23 | 24 | func testAPIIsInvalid() { 25 | let expectation = self.expectation(description: "results") 26 | GooglePlaces.provide(apiKey: "fake_key") 27 | 28 | GooglePlaces.placeDetails(forPlaceID: "") { (response, error) -> Void in 29 | XCTAssertNotNil(error) 30 | XCTAssertNotNil(response) 31 | XCTAssertNotNil(response?.errorMessage) 32 | XCTAssertEqual(response?.status, GooglePlaces.StatusCode.requestDenied) 33 | expectation.fulfill() 34 | } 35 | 36 | waitForExpectations(timeout: 5.0, handler: nil) 37 | } 38 | 39 | func testAPIIsValid() { 40 | let expectation = self.expectation(description: "results") 41 | 42 | GooglePlaces.placeDetails(forPlaceID: "ChIJb9sw59k0K4gRZZlYrnOomfc") { (response, error) -> Void in 43 | XCTAssertNil(error) 44 | XCTAssertNotNil(response) 45 | XCTAssertEqual(response?.result?.placeID , "ChIJb9sw59k0K4gRZZlYrnOomfc") 46 | XCTAssertEqual(response?.status, GooglePlaces.StatusCode.ok) 47 | expectation.fulfill() 48 | } 49 | 50 | waitForExpectations(timeout: 5.0, handler: nil) 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /GooglePlacesAPI.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "GooglePlacesAPI" 3 | s.version = "1.1.4" 4 | s.summary = "Swift Wrapper on Google Places API" 5 | s.description = <<-DESC 6 | Swift Wrapper on Google Places API 7 | https://developers.google.com/places/web-service/ 8 | 9 | DESC 10 | s.homepage = "https://github.com/honghaoz/Swift-Google-Maps-API" 11 | s.license = { :type => 'MIT', :file => 'LICENSE' } 12 | s.author = { "Honghao Zhang" => "zhh358@gmail.com" } 13 | s.source = { :git => "https://github.com/honghaoz/Swift-Google-Maps-API.git", :tag => s.version.to_s } 14 | 15 | s.ios.deployment_target = "8.0" 16 | s.osx.deployment_target = "10.10" 17 | s.watchos.deployment_target = "2.0" 18 | s.tvos.deployment_target = "9.0" 19 | 20 | s.requires_arc = true 21 | s.source_files = "Source/Core/**/*.*", "Source/Google Places API/**/*.*" 22 | s.module_name = "GooglePlacesAPI" 23 | 24 | s.dependency 'Alamofire', '~> 4' 25 | s.dependency 'ObjectMapper', '~> 3' 26 | 27 | end 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Honghao Zhang 张宏昊 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Swift Google Maps API 2 | 3 | [![CI Status](https://travis-ci.org/honghaoz/Swift-Google-Maps-API.svg)](https://travis-ci.org/honghaoz/Swift-Google-Maps-API) 4 | 5 | Use [Google Maps Web Service APIs](https://developers.google.com/maps/get-started/#web-service-apis) in Swift 6 | 7 | **`GooglePlaces`** is renamed to **`GooglePlacesAPI`** as official `GooglePlaces` pod is coming. 8 | 9 | ## Features: 10 | - [x] [Google Maps Directions API](https://developers.google.com/maps/documentation/directions/) 11 | - [ ] [Google Places API Web Service](https://developers.google.com/places/web-service/) 12 | - [x] [Place Autocomplete](https://developers.google.com/places/web-service/autocomplete) 13 | - [x] [Place Details](https://developers.google.com/places/web-service/details) 14 | - [ ] More... 15 | 16 | ## Requirements 17 | - [x] iOS 9.0+ / Mac OS X 10.11+ / tvOS 9.0+ / watchOS 2.0+ 18 | - [x] Xcode 8.0+ 19 | - [x] Swift 3.0+ 20 | 21 | ## Installation 22 | 23 | ### [CocoaPods](http://cocoapods.org) 24 | - Google Maps Directions API 25 | 26 | ```ruby 27 | use_frameworks! 28 | pod 'GoogleMapsDirections', '~> 1.1' 29 | ``` 30 | - Google Places API 31 | 32 | ```ruby 33 | use_frameworks! 34 | pod 'GooglePlacesAPI', '~> 1.1' 35 | ``` 36 | 37 | ## Usage 38 | - Google Maps Directions API 39 | ```swift 40 | import GoogleMapsDirections 41 | 42 | GoogleMapsDirections.provide(apiKey: "A VALID GOOGLE MAPS KEY") 43 | 44 | let origin = GoogleMapsDirections.Place.stringDescription(address: "Davis Center, Waterloo, Canada") 45 | let destination = GoogleMapsDirections.Place.stringDescription(address: "Conestoga Mall, Waterloo, Canada") 46 | 47 | // You can also use coordinates or placeID for a place 48 | // let origin = Place.Coordinate(coordinate: LocationCoordinate2D(latitude: 43.4697354, longitude: -80.5397377)) 49 | // let origin = Place.PlaceID(id: "ChIJb9sw59k0K4gRZZlYrnOomfc") 50 | 51 | GoogleMapsDirections.direction(fromOrigin: origin, toDestination: destination) { (response, error) -> Void in 52 | // Check Status Code 53 | guard response?.status == GoogleMapsDirections.StatusCode.ok else { 54 | // Status Code is Not OK 55 | debugPrint(response?.errorMessage) 56 | return 57 | } 58 | 59 | // Use .result or .geocodedWaypoints to access response details 60 | // response will have same structure as what Google Maps Directions API returns 61 | debugPrint("it has \(response?.routes.count ?? 0) routes") 62 | } 63 | ``` 64 | - Google Places API 65 | - Place Autocomplete: 66 | ```swift 67 | import GooglePlacesAPI 68 | 69 | GooglePlacesAPI.provide(apiKey: "A VALID GOOGLE MAPS KEY") 70 | 71 | GooglePlacesAPI.placeAutocomplete(forInput: "Pub") { (response, error) -> Void in 72 | // Check Status Code 73 | guard response?.status == GooglePlaces.StatusCode.ok else { 74 | // Status Code is Not OK 75 | debugPrint(response?.errorMessage) 76 | return 77 | } 78 | 79 | // Use .predictions to access response details 80 | debugPrint("first matched result: \(response?.predictions.first?.description)") 81 | } 82 | 83 | ``` 84 | - Place Details 85 | ```swift 86 | import GooglePlacesAPI 87 | 88 | GooglePlacesAPI.provide(apiKey: "A VALID GOOGLE MAPS KEY") 89 | 90 | GooglePlacesAPI.placeDetails(forPlaceID: "ChIJb9sw59k0K4gRZZlYrnOomfc") { (response, error) -> Void in 91 | // Check Status Code 92 | guard response?.status == GooglePlaces.StatusCode.ok else { 93 | // Status Code is Not OK 94 | debugPrint(response?.errorMessage) 95 | return 96 | } 97 | 98 | // Use .result to access response details 99 | debugPrint("the formated address is: \(response?.result?.formattedAddress)") 100 | } 101 | ``` 102 | 103 | ## License 104 | 105 | The MIT License (MIT) 106 | 107 | Copyright (c) 2015 Honghao Zhang (张宏昊) 108 | 109 | Permission is hereby granted, free of charge, to any person obtaining a copy 110 | of this software and associated documentation files (the "Software"), to deal 111 | in the Software without restriction, including without limitation the rights 112 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 113 | copies of the Software, and to permit persons to whom the Software is 114 | furnished to do so, subject to the following conditions: 115 | 116 | The above copyright notice and this permission notice shall be included in all 117 | copies or substantial portions of the Software. 118 | 119 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 120 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 121 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 122 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 123 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 124 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 125 | SOFTWARE. 126 | -------------------------------------------------------------------------------- /Source/Core/Dictionary+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Dictionary+Extensions.swift 3 | // GoogleMapsDirections 4 | // 5 | // Created by Honghao Zhang on 2016-02-13. 6 | // Copyright © 2016 Honghao Zhang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | // MARK: - Plus Operator for Dictionary 12 | 13 | /** 14 | Combine two dictionaries 15 | 16 | - parameter left: left operand dictionary 17 | - parameter right: right operand dictionary 18 | 19 | - returns: Combined dictionary, existed keys in left dictionary will be overrided by right dictionary 20 | */ 21 | func + (left: [K : V], right: [K : V]?) -> [K : V] { 22 | guard let right = right else { return left } 23 | return left.reduce(right) { 24 | var new = $0 as [K : V] 25 | new.updateValue($1.1, forKey: $1.0) 26 | return new 27 | } 28 | } 29 | 30 | /** 31 | Combine two dictionaries 32 | 33 | - parameter left: left operand dictionary 34 | - parameter right: right operand dictionary 35 | */ 36 | func += (left: inout [K : V], right: [K : V]){ 37 | for (k, v) in right { 38 | left.updateValue(v, forKey: k) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Source/Core/GoogleMapsService.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GoogleMapsService.swift 3 | // GooglePlaces 4 | // 5 | // Created by Honghao Zhang on 2016-02-12. 6 | // Copyright © 2016 Honghao Zhang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | open class GoogleMapsService { 12 | enum GoogleMapsServiceError: Error { 13 | case apiKeyNotExisted 14 | } 15 | 16 | fileprivate static var _apiKey: String? 17 | 18 | /** 19 | Provide a Google Maps API key 20 | 21 | - parameter APIKey: Google Maps API key 22 | */ 23 | public class func provide(apiKey: String) { 24 | _apiKey = apiKey 25 | } 26 | 27 | /** 28 | Return a valid API key, or throw an exception 29 | 30 | - throws: API key error 31 | 32 | - returns: API Key string 33 | */ 34 | class func apiKey() throws -> String { 35 | guard let apiKey = _apiKey else { 36 | NSLog("Error: Please provide an API key") 37 | throw GoogleMapsServiceError.apiKeyNotExisted 38 | } 39 | return apiKey 40 | } 41 | 42 | /// Get a base request parameter dictionary, this will include API key 43 | class var baseRequestParameters: [String : String] { 44 | return try! ["key" : apiKey()] 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Source/Core/ObjectMapperTransformers/DateTransformInteger.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DateTransformInteger.swift 3 | // GoogleMapsDirections 4 | // 5 | // Created by Honghao Zhang on 2016-01-24. 6 | // Copyright © 2016 Honghao Zhang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ObjectMapper 11 | 12 | class DateTransformInteger: TransformType { 13 | typealias Object = Date 14 | typealias JSON = Int 15 | 16 | init() {} 17 | 18 | func transformFromJSON(_ value: Any?) -> Date? { 19 | if let timeInt = value as? Int { 20 | return Date(timeIntervalSince1970: TimeInterval(timeInt)) 21 | } 22 | 23 | if let timeStr = value as? String { 24 | return Date(timeIntervalSince1970: TimeInterval(atof(timeStr))) 25 | } 26 | 27 | return nil 28 | } 29 | 30 | func transformToJSON(_ value: Date?) -> Int? { 31 | if let date = value { 32 | return Int(date.timeIntervalSince1970) 33 | } 34 | return nil 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Source/Core/ObjectMapperTransformers/LocationCoordinate2DTransform.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LocationCoordinate2DTransform.swift 3 | // GoogleMapsDirections 4 | // 5 | // Created by Honghao Zhang on 2016-01-23. 6 | // Copyright © 2016 Honghao Zhang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ObjectMapper 11 | 12 | class LocationCoordinate2DTransform: TransformType { 13 | typealias LocationCoordinate2D = GoogleMapsService.LocationCoordinate2D 14 | typealias Object = LocationCoordinate2D 15 | typealias JSON = [String : Any] 16 | 17 | func transformFromJSON(_ value: Any?) -> Object? { 18 | if let value = value as? JSON { 19 | guard let latitude = value["lat"] as? Double, let longitude = value["lng"] as? Double else { 20 | NSLog("Error: lat/lng is not Double") 21 | return nil 22 | } 23 | 24 | return LocationCoordinate2D(latitude: latitude, longitude: longitude) 25 | } 26 | return nil 27 | } 28 | 29 | func transformToJSON(_ value: Object?) -> JSON? { 30 | if let value = value { 31 | return [ 32 | "lat" : "\(value.latitude)", 33 | "lng" : "\(value.longitude)" 34 | ] 35 | } 36 | return nil 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Source/Core/SharedTypes.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SharedTypes.swift 3 | // GoogleMapsDirections 4 | // 5 | // Created by Honghao Zhang on 2016-02-12. 6 | // Copyright © 2016 Honghao Zhang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ObjectMapper 11 | 12 | public extension GoogleMapsService { 13 | /// The status field within the Directions response object contains the status of the request, 14 | /// and may contain debugging information to help you track down why the Directions service failed. 15 | /// Reference: https://developers.google.com/maps/documentation/directions/intro#StatusCodes 16 | /// 17 | /// - ok: The response contains a valid result. 18 | /// - notFound: At least one of the locations specified in the request's origin, destination, or waypoints could not be geocoded. 19 | /// - zeroResults: No route could be found between the origin and destination. 20 | /// - maxWaypointsExceeded: Too many waypoints were provided in the request. 21 | /// - invalidRequest: The provided request was invalid. 22 | /// - overQueryLimit: The service has received too many requests from your application within the allowed time period. 23 | /// - requestDenied: The service denied use of the directions service by your application. 24 | /// - unknownError: Directions request could not be processed due to a server error. 25 | public enum StatusCode: String { 26 | case ok = "OK" 27 | case notFound = "NOT_FOUND" 28 | case zeroResults = "ZERO_RESULTS" 29 | case maxWaypointsExceeded = "MAX_WAYPOINTS_EXCEEDED" 30 | case invalidRequest = "INVALID_REQUEST" 31 | case overQueryLimit = "OVER_QUERY_LIMIT" 32 | case requestDenied = "REQUEST_DENIED" 33 | case unknownError = "UNKNOWN_ERROR" 34 | } 35 | } 36 | 37 | 38 | // MARK: - Place 39 | public extension GoogleMapsService { 40 | public typealias LocationDegrees = Double 41 | public struct LocationCoordinate2D { 42 | public var latitude: LocationDegrees 43 | public var longitude: LocationDegrees 44 | 45 | public init(latitude: LocationDegrees, longitude: LocationDegrees) { 46 | self.latitude = latitude 47 | self.longitude = longitude 48 | } 49 | } 50 | 51 | /// This struct represents a place/address/location, used in Google Map Directions API 52 | /// Reference: https://developers.google.com/maps/documentation/directions/intro#RequestParameters 53 | /// 54 | /// - stringDescription: Address as a string 55 | /// - coordinate: Coordinate 56 | /// - placeID: Place id from Google Map API 57 | public enum Place { 58 | case stringDescription(address: String) 59 | case coordinate(coordinate: LocationCoordinate2D) 60 | case placeID(id: String) 61 | 62 | public func toString() -> String { 63 | switch self { 64 | case .stringDescription(let address): 65 | return address 66 | case .coordinate(let coordinate): 67 | return "\(coordinate.latitude),\(coordinate.longitude)" 68 | case .placeID(let id): 69 | return "place_id:\(id)" 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Source/Google Maps Directions API/GoogleMapsDirections.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GoogleMapsDirections.swift 3 | // GoogleMapsDirections 4 | // 5 | // Created by Honghao Zhang on 2016-01-23. 6 | // Copyright © 2016 Honghao Zhang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Alamofire 11 | import ObjectMapper 12 | 13 | // Documentations: https://developers.google.com/maps/documentation/directions/ 14 | 15 | public class GoogleMapsDirections: GoogleMapsService { 16 | 17 | public static let baseURLString = "https://maps.googleapis.com/maps/api/directions/json" 18 | 19 | /** 20 | Request to Google Directions API 21 | Documentations: https://developers.google.com/maps/documentation/directions/intro#RequestParameters 22 | 23 | - parameter origin: The address, textual latitude/longitude value, or place ID from which you wish to calculate directions. 24 | - parameter destination: The address, textual latitude/longitude value, or place ID to which you wish to calculate directions. 25 | - parameter travelMode: Mode of transport to use when calculating directions. 26 | - parameter wayPoints: Specifies an array of waypoints. Waypoints alter a route by routing it through the specified location(s). 27 | - parameter alternatives: If set to true, specifies that the Directions service may provide more than one route alternative in the response. Note that providing route alternatives may increase the response time from the server. 28 | - parameter avoid: Indicates that the calculated route(s) should avoid the indicated features. 29 | - parameter language: Specifies the language in which to return results. See https://developers.google.com/maps/faq#languagesupport. 30 | - parameter units: Specifies the unit system to use when displaying results. 31 | - parameter region: Specifies the region code, specified as a ccTLD ("top-level domain") two-character value. 32 | - parameter arrivalTime: Specifies the desired time of arrival for transit directions 33 | - parameter departureTime: Specifies the desired time of departure. 34 | - parameter trafficModel: Specifies the assumptions to use when calculating time in traffic. (defaults to best_guess) 35 | - parameter transitMode: Specifies one or more preferred modes of transit. 36 | - parameter transitRoutingPreference: Specifies preferences for transit routes. 37 | - parameter completion: API responses completion block 38 | */ 39 | open class func direction(fromOrigin origin: Place, 40 | toDestination destination: Place, 41 | travelMode: TravelMode = .driving, 42 | wayPoints: [Place]? = nil, 43 | alternatives: Bool? = nil, 44 | avoid: [RouteRestriction]? = nil, 45 | language: String? = nil, 46 | units: Unit? = nil, 47 | region: String? = nil, 48 | arrivalTime: Date? = nil, 49 | departureTime: Date? = nil, 50 | trafficModel: TrafficMode? = nil, 51 | transitMode: TransitMode? = nil, 52 | transitRoutingPreference: TransitRoutingPreference? = nil, 53 | completion: ((_ response: Response?, _ error: NSError?) -> Void)? = nil) 54 | { 55 | var requestParameters: [String : Any] = baseRequestParameters + [ 56 | "origin" : origin.toString(), 57 | "destination" : destination.toString(), 58 | "mode" : travelMode.rawValue.lowercased() 59 | ] 60 | 61 | if let wayPoints = wayPoints { 62 | requestParameters["waypoints"] = wayPoints.map { $0.toString() }.joined(separator: "|") 63 | } 64 | 65 | if let alternatives = alternatives { 66 | requestParameters["alternatives"] = String(alternatives) 67 | } 68 | 69 | if let avoid = avoid { 70 | requestParameters["avoid"] = avoid.map { $0.rawValue }.joined(separator: "|") 71 | } 72 | 73 | if let language = language { 74 | requestParameters["language"] = language 75 | } 76 | 77 | if let units = units { 78 | requestParameters["units"] = units.rawValue 79 | } 80 | 81 | if let region = region { 82 | requestParameters["region"] = region 83 | } 84 | 85 | if arrivalTime != nil && departureTime != nil { 86 | NSLog("Warning: You can only specify one of arrivalTime or departureTime at most, requests may failed") 87 | } 88 | 89 | if let arrivalTime = arrivalTime, (travelMode == .transit || travelMode == .driving) { 90 | requestParameters["arrival_time"] = Int(arrivalTime.timeIntervalSince1970) 91 | } 92 | 93 | if let departureTime = departureTime, (travelMode == .transit || travelMode == .driving) { 94 | requestParameters["departure_time"] = Int(departureTime.timeIntervalSince1970) 95 | } 96 | 97 | if let trafficModel = trafficModel { 98 | requestParameters["traffic_model"] = trafficModel.rawValue 99 | } 100 | 101 | if let transitMode = transitMode { 102 | requestParameters["transit_mode"] = transitMode.rawValue 103 | } 104 | 105 | if let transitRoutingPreference = transitRoutingPreference { 106 | requestParameters["transit_routing_preference"] = transitRoutingPreference.rawValue 107 | } 108 | 109 | Alamofire.request(baseURLString, method: .get, parameters: requestParameters).responseJSON { response in 110 | if response.result.isFailure { 111 | NSLog("Error: GET failed") 112 | completion?(nil, NSError(domain: "GoogleMapsDirectionsError", code: -1, userInfo: nil)) 113 | return 114 | } 115 | 116 | // Nil 117 | if let _ = response.result.value as? NSNull { 118 | completion?(Response(), nil) 119 | return 120 | } 121 | 122 | // JSON 123 | guard let json = response.result.value as? [String : AnyObject] else { 124 | NSLog("Error: Parsing json failed") 125 | completion?(nil, NSError(domain: "GoogleMapsDirectionsError", code: -2, userInfo: nil)) 126 | return 127 | } 128 | 129 | guard let directionsResponse = Mapper().map(JSON: json) else { 130 | NSLog("Error: Mapping directions response failed") 131 | completion?(nil, NSError(domain: "GoogleMapsDirectionsError", code: -3, userInfo: nil)) 132 | return 133 | } 134 | 135 | var error: NSError? 136 | 137 | switch directionsResponse.status { 138 | case .none: 139 | let userInfo = [ 140 | NSLocalizedDescriptionKey : NSLocalizedString("StatusCodeError", value: "Status Code not found", comment: ""), 141 | NSLocalizedFailureReasonErrorKey : NSLocalizedString("StatusCodeError", value: "Status Code not found", comment: "") 142 | ] 143 | error = NSError(domain: "GoogleMapsDirectionsError", code: -4, userInfo: userInfo) 144 | case .some(let status): 145 | switch status { 146 | case .ok: 147 | break 148 | case .notFound: 149 | let userInfo = [ 150 | NSLocalizedDescriptionKey : NSLocalizedString("StatusCodeError", value: "At least one of the locations specified in the request's origin, destination, or waypoints could not be geocoded.", comment: ""), 151 | NSLocalizedFailureReasonErrorKey : NSLocalizedString("StatusCodeError", value: directionsResponse.errorMessage ?? "", comment: "") 152 | ] 153 | error = NSError(domain: "GoogleMapsDirectionsError", code: -5, userInfo: userInfo) 154 | case .zeroResults: 155 | let userInfo = [ 156 | NSLocalizedDescriptionKey : NSLocalizedString("StatusCodeError", value: "No route could be found between the origin and destination.", comment: ""), 157 | NSLocalizedFailureReasonErrorKey : NSLocalizedString("StatusCodeError", value: directionsResponse.errorMessage ?? "", comment: "") 158 | ] 159 | error = NSError(domain: "GoogleMapsDirectionsError", code: -6, userInfo: userInfo) 160 | case .maxWaypointsExceeded: 161 | let userInfo = [ 162 | NSLocalizedDescriptionKey : NSLocalizedString("StatusCodeError", value: "Too many waypoints were provided in the request. The maximum allowed number of waypoints is 23, plus the origin and destination. (If the request does not include an API key, the maximum allowed number of waypoints is 8.", comment: ""), 163 | NSLocalizedFailureReasonErrorKey : NSLocalizedString("StatusCodeError", value: directionsResponse.errorMessage ?? "", comment: "") 164 | ] 165 | error = NSError(domain: "GoogleMapsDirectionsError", code: -7, userInfo: userInfo) 166 | case .invalidRequest: 167 | let userInfo = [ 168 | NSLocalizedDescriptionKey : NSLocalizedString("StatusCodeError", value: "Provided request was invalid. Common causes of this status include an invalid parameter or parameter value.", comment: ""), 169 | NSLocalizedFailureReasonErrorKey : NSLocalizedString("StatusCodeError", value: directionsResponse.errorMessage ?? "", comment: "") 170 | ] 171 | error = NSError(domain: "GoogleMapsDirectionsError", code: -8, userInfo: userInfo) 172 | case .overQueryLimit: 173 | let userInfo = [ 174 | NSLocalizedDescriptionKey : NSLocalizedString("StatusCodeError", value: "Service has received too many requests from your application within the allowed time period.", comment: ""), 175 | NSLocalizedFailureReasonErrorKey : NSLocalizedString("StatusCodeError", value: directionsResponse.errorMessage ?? "", comment: "") 176 | ] 177 | error = NSError(domain: "GoogleMapsDirectionsError", code: -9, userInfo: userInfo) 178 | case .requestDenied: 179 | let userInfo = [ 180 | NSLocalizedDescriptionKey : NSLocalizedString("StatusCodeError", value: "Service denied use of the directions service by your application.", comment: ""), 181 | NSLocalizedFailureReasonErrorKey : NSLocalizedString("StatusCodeError", value: directionsResponse.errorMessage ?? "", comment: "") 182 | ] 183 | error = NSError(domain: "GoogleMapsDirectionsError", code: -10, userInfo: userInfo) 184 | case .unknownError: 185 | let userInfo = [ 186 | NSLocalizedDescriptionKey : NSLocalizedString("StatusCodeError", value: "A directions request could not be processed due to a server error. The request may succeed if you try again.", comment: ""), 187 | NSLocalizedFailureReasonErrorKey : NSLocalizedString("StatusCodeError", value: directionsResponse.errorMessage ?? "", comment: "") 188 | ] 189 | error = NSError(domain: "GoogleMapsDirectionsError", code: -11, userInfo: userInfo) 190 | } 191 | } 192 | 193 | completion?(directionsResponse, error) 194 | } 195 | } 196 | } 197 | 198 | extension GoogleMapsDirections { 199 | /** 200 | Request to Google Directions API, with address description strings 201 | Documentations: https://developers.google.com/maps/documentation/directions/intro#RequestParameters 202 | 203 | - parameter originAddress: The address description from which you wish to calculate directions. 204 | - parameter destinationAddress: The address description to which you wish to calculate directions. 205 | - parameter travelMode: Mode of transport to use when calculating directions. 206 | - parameter wayPoints: Specifies an array of waypoints. Waypoints alter a route by routing it through the specified location(s). 207 | - parameter alternatives: If set to true, specifies that the Directions service may provide more than one route alternative in the response. Note that providing route alternatives may increase the response time from the server. 208 | - parameter avoid: Indicates that the calculated route(s) should avoid the indicated features. 209 | - parameter language: Specifies the language in which to return results. See https://developers.google.com/maps/faq#languagesupport. 210 | - parameter units: Specifies the unit system to use when displaying results. 211 | - parameter region: Specifies the region code, specified as a ccTLD ("top-level domain") two-character value. 212 | - parameter arrivalTime: Specifies the desired time of arrival for transit directions 213 | - parameter departureTime: Specifies the desired time of departure. 214 | - parameter trafficModel: Specifies the assumptions to use when calculating time in traffic. (defaults to best_guess) 215 | - parameter transitMode: Specifies one or more preferred modes of transit. 216 | - parameter transitRoutingPreference: Specifies preferences for transit routes. 217 | - parameter completion: API responses completion block 218 | */ 219 | public class func direction(fromOriginAddress originAddress: String, 220 | toDestinationAddress destinationAddress: String, 221 | travelMode: TravelMode = .driving, 222 | wayPoints: [Place]? = nil, 223 | alternatives: Bool? = nil, 224 | avoid: [RouteRestriction]? = nil, 225 | language: String? = nil, 226 | units: Unit? = nil, 227 | region: String? = nil, 228 | arrivalTime: Date? = nil, 229 | departureTime: Date? = nil, 230 | trafficModel: TrafficMode? = nil, 231 | transitMode: TransitMode? = nil, 232 | transitRoutingPreference: TransitRoutingPreference? = nil, 233 | completion: ((_ response: Response?, _ error: NSError?) -> Void)? = nil) 234 | { 235 | direction(fromOrigin: Place.stringDescription(address: originAddress), 236 | toDestination: Place.stringDescription(address: destinationAddress), 237 | travelMode: travelMode, 238 | wayPoints: wayPoints, 239 | alternatives: alternatives, 240 | avoid: avoid, 241 | language: language, 242 | units: units, 243 | region: region, 244 | arrivalTime: arrivalTime, 245 | departureTime: departureTime, 246 | trafficModel: trafficModel, 247 | transitMode: transitMode, 248 | transitRoutingPreference: transitRoutingPreference, 249 | completion: completion) 250 | } 251 | 252 | /** 253 | Request to Google Directions API, with coordinate 254 | Documentations: https://developers.google.com/maps/documentation/directions/intro#RequestParameters 255 | 256 | - parameter originCoordinate: The coordinate from which you wish to calculate directions. 257 | - parameter destinationCoordinate: The coordinate to which you wish to calculate directions. 258 | - parameter travelMode: Mode of transport to use when calculating directions. 259 | - parameter wayPoints: Specifies an array of waypoints. Waypoints alter a route by routing it through the specified location(s). 260 | - parameter alternatives: If set to true, specifies that the Directions service may provide more than one route alternative in the response. Note that providing route alternatives may increase the response time from the server. 261 | - parameter avoid: Indicates that the calculated route(s) should avoid the indicated features. 262 | - parameter language: Specifies the language in which to return results. See https://developers.google.com/maps/faq#languagesupport. 263 | - parameter units: Specifies the unit system to use when displaying results. 264 | - parameter region: Specifies the region code, specified as a ccTLD ("top-level domain") two-character value. 265 | - parameter arrivalTime: Specifies the desired time of arrival for transit directions 266 | - parameter departureTime: Specifies the desired time of departure. 267 | - parameter trafficModel: Specifies the assumptions to use when calculating time in traffic. (defaults to best_guess) 268 | - parameter transitMode: Specifies one or more preferred modes of transit. 269 | - parameter transitRoutingPreference: Specifies preferences for transit routes. 270 | - parameter completion: API responses completion block 271 | */ 272 | public class func direction(fromOriginCoordinate originCoordinate: LocationCoordinate2D, 273 | toDestinationCoordinate destinationCoordinate: LocationCoordinate2D, 274 | travelMode: TravelMode = .driving, 275 | wayPoints: [Place]? = nil, 276 | alternatives: Bool? = nil, 277 | avoid: [RouteRestriction]? = nil, 278 | language: String? = nil, 279 | units: Unit? = nil, 280 | region: String? = nil, 281 | arrivalTime: Date? = nil, 282 | departureTime: Date? = nil, 283 | trafficModel: TrafficMode? = nil, 284 | transitMode: TransitMode? = nil, 285 | transitRoutingPreference: TransitRoutingPreference? = nil, 286 | completion: ((_ response: Response?, _ error: NSError?) -> Void)? = nil) 287 | { 288 | direction(fromOrigin: Place.coordinate(coordinate: originCoordinate), 289 | toDestination: Place.coordinate(coordinate: destinationCoordinate), 290 | travelMode: travelMode, 291 | wayPoints: wayPoints, 292 | alternatives: alternatives, 293 | avoid: avoid, 294 | language: language, 295 | units: units, 296 | region: region, 297 | arrivalTime: arrivalTime, 298 | departureTime: departureTime, 299 | trafficModel: trafficModel, 300 | transitMode: transitMode, 301 | transitRoutingPreference: transitRoutingPreference, 302 | completion: completion) 303 | } 304 | } 305 | -------------------------------------------------------------------------------- /Source/Google Maps Directions API/Response.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Response.swift 3 | // GoogleMapsDirections 4 | // 5 | // Created by Honghao Zhang on 2016-01-23. 6 | // Copyright © 2016 Honghao Zhang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ObjectMapper 11 | 12 | #if os(iOS) || os(watchOS) || os(tvOS) 13 | import UIKit 14 | public typealias Color = UIColor 15 | #elseif os(OSX) 16 | import Cocoa 17 | public typealias Color = NSColor 18 | #endif 19 | 20 | // Documentations: https://developers.google.com/maps/documentation/directions/intro#DirectionsResponseElements 21 | 22 | // MARK: - Response 23 | public extension GoogleMapsDirections { 24 | public struct Response: Mappable { 25 | public var status: StatusCode? 26 | public var errorMessage: String? 27 | 28 | public var geocodedWaypoints: [GeocodedWaypoint] = [] 29 | public var routes: [Route] = [] 30 | 31 | public init() {} 32 | public init?(map: Map) { } 33 | 34 | public mutating func mapping(map: Map) { 35 | status <- (map["status"], EnumTransform()) 36 | errorMessage <- map["error_message"] 37 | 38 | geocodedWaypoints <- map["geocoded_waypoints"] 39 | routes <- map["routes"] 40 | } 41 | 42 | /** 43 | * GeocodedWaypoint 44 | */ 45 | public struct GeocodedWaypoint: Mappable { 46 | public var geocoderStatus: GeocoderStatus? 47 | public var partialMatch: Bool = false 48 | public var placeID: String? 49 | public var types: [AddressType] = [] 50 | 51 | public init?(map: Map) { } 52 | 53 | public mutating func mapping(map: Map) { 54 | geocoderStatus <- (map["geocoder_status"], EnumTransform()) 55 | partialMatch <- map["geocoded_waypoints"] 56 | placeID <- map["place_id"] 57 | types <- (map["types"], EnumTransform()) 58 | } 59 | } 60 | 61 | /** 62 | * Route 63 | */ 64 | public struct Route: Mappable { 65 | public var summary: String? 66 | public var legs: [Leg] = [] 67 | public var waypointOrder: [Int] = [] 68 | public var overviewPolylinePoints: String? 69 | public var bounds: Bounds? 70 | public var copyrights: String? 71 | public var warnings: [String] = [] 72 | public var fare: Fare? 73 | 74 | public init?(map: Map) { } 75 | 76 | public mutating func mapping(map: Map) { 77 | summary <- map["summary"] 78 | legs <- map["legs"] 79 | waypointOrder <- map["waypointOrder"] 80 | overviewPolylinePoints <- map["overview_polyline.points"] 81 | bounds <- map["bounds"] 82 | copyrights <- map["copyrights"] 83 | warnings <- map["warnings"] 84 | fare <- map["fare"] 85 | } 86 | 87 | /** 88 | * Leg 89 | */ 90 | public struct Leg: Mappable { 91 | public var steps: [Step] = [] 92 | public var distance: Step.Distance? 93 | public var duration: Step.Duration? 94 | public var durationInTraffic: DurationInTraffic? 95 | public var arrivalTime: Time? 96 | public var departureTime: Time? 97 | public var startLocation: LocationCoordinate2D? 98 | public var endLocation: LocationCoordinate2D? 99 | public var startAddress: String? 100 | public var endAddress: String? 101 | 102 | public init?(map: Map) { } 103 | 104 | public mutating func mapping(map: Map) { 105 | steps <- map["steps"] 106 | distance <- map["distance"] 107 | duration <- map["duration"] 108 | durationInTraffic <- map["duration_in_traffic"] 109 | arrivalTime <- map["arrival_time"] 110 | departureTime <- map["departure_time"] 111 | startLocation <- (map["start_location"], LocationCoordinate2DTransform()) 112 | endLocation <- (map["end_location"], LocationCoordinate2DTransform()) 113 | startAddress <- map["start_address"] 114 | endAddress <- map["end_address"] 115 | } 116 | 117 | /** 118 | * Step 119 | */ 120 | public struct Step: Mappable { 121 | /// formatted instructions for this step, presented as an HTML text string. 122 | public var htmlInstructions: String? 123 | public var distance: Distance? 124 | public var duration: Duration? 125 | public var startLocation: LocationCoordinate2D? 126 | public var endLocation: LocationCoordinate2D? 127 | public var polylinePoints: String? 128 | public var steps: [Step] = [] 129 | public var travelMode: TravelMode? 130 | public var maneuver: String? 131 | public var transitDetails: TransitDetails? 132 | 133 | public init?(map: Map) { } 134 | 135 | public mutating func mapping(map: Map) { 136 | htmlInstructions <- map["html_instructions"] 137 | distance <- map["distance"] 138 | duration <- map["duration"] 139 | startLocation <- (map["start_location"], LocationCoordinate2DTransform()) 140 | endLocation <- (map["end_location"], LocationCoordinate2DTransform()) 141 | polylinePoints <- map["polyline.points"] 142 | steps <- map["steps"] 143 | travelMode <- map["travel_mode"] 144 | maneuver <- map["maneuver"] 145 | transitDetails <- map["transit_details"] 146 | } 147 | 148 | /** 149 | * Distance 150 | */ 151 | public struct Distance: Mappable { 152 | public var value: Int? // the distance in meters 153 | public var text: String? // human-readable representation of the distance 154 | 155 | public init?(map: Map) { } 156 | 157 | public mutating func mapping(map: Map) { 158 | value <- map["value"] 159 | text <- map["text"] 160 | } 161 | } 162 | 163 | /** 164 | * Duration 165 | */ 166 | public struct Duration: Mappable { 167 | public var value: Int? // the duration in seconds. 168 | public var text: String? // human-readable representation of the duration. 169 | 170 | public init?(map: Map) { } 171 | 172 | public mutating func mapping(map: Map) { 173 | value <- map["value"] 174 | text <- map["text"] 175 | } 176 | } 177 | 178 | /** 179 | * TransitDetails 180 | */ 181 | public struct TransitDetails: Mappable { 182 | public var arrivalStop: Stop? 183 | public var departureStop: Stop? 184 | public var arrivalTime: Time? 185 | public var departureTime: Time? 186 | public var headsign: String? 187 | public var headway: Int? 188 | public var numStops: Int? 189 | public var line: TransitLine? 190 | 191 | public init?(map: Map) { } 192 | 193 | public mutating func mapping(map: Map) { 194 | arrivalStop <- map["arrival_stop"] 195 | departureStop <- map["departure_stop"] 196 | arrivalTime <- map["arrival_time"] 197 | departureTime <- map["departure_time"] 198 | headsign <- map["headsign"] 199 | headway <- map["headway"] 200 | numStops <- map["num_stops"] 201 | line <- map["line"] 202 | } 203 | 204 | /** 205 | * Stop 206 | */ 207 | public struct Stop: Mappable { 208 | public var location: LocationCoordinate2D? 209 | public var name: String? 210 | 211 | public init?(map: Map) { } 212 | 213 | public mutating func mapping(map: Map) { 214 | location <- (map["location"], LocationCoordinate2DTransform()) 215 | name <- map["name"] 216 | } 217 | } 218 | 219 | /** 220 | * TransitLine 221 | */ 222 | public struct TransitLine: Mappable { 223 | public var name: String? 224 | public var shortName: String? 225 | public var color: Color? 226 | public var agencies: [TransitAgency] = [] 227 | public var url: URL? 228 | public var icon: URL? 229 | public var textColor: Color? 230 | public var vehicle: [TransitLineVehicle] = [] 231 | 232 | public init?(map: Map) { } 233 | 234 | public mutating func mapping(map: Map) { 235 | name <- map["name"] 236 | shortName <- map["short_name"] 237 | color <- (map["color"], colorTransform()) 238 | agencies <- map["agencies"] 239 | url <- (map["url"], URLTransform()) 240 | icon <- (map["icon"], URLTransform()) 241 | textColor <- (map["text_color"], colorTransform()) 242 | vehicle <- map["vehicle"] 243 | } 244 | 245 | fileprivate func colorTransform() -> TransformOf { 246 | return TransformOf(fromJSON: { (value: String?) -> Color? in 247 | if let value = value { 248 | return Color(hexString: value) 249 | } 250 | return nil 251 | }, toJSON: { (value: Color?) -> String? in 252 | if let value = value { 253 | return value.hexString 254 | } 255 | return nil 256 | }) 257 | } 258 | 259 | /** 260 | * TransitAgency 261 | */ 262 | public struct TransitAgency: Mappable { 263 | public var name: String? 264 | public var phone: String? 265 | public var url: URL? 266 | 267 | public init?(map: Map) { } 268 | 269 | public mutating func mapping(map: Map) { 270 | name <- map["name"] 271 | phone <- map["phone"] 272 | url <- (map["url"], URLTransform()) 273 | } 274 | } 275 | 276 | /** 277 | * TransitLineVehicle 278 | */ 279 | public struct TransitLineVehicle: Mappable { 280 | public var name: String? 281 | public var type: VehicleType? 282 | public var icon: URL? 283 | 284 | public init?(map: Map) { } 285 | 286 | public mutating func mapping(map: Map) { 287 | name <- map["name"] 288 | type <- (map["type"], EnumTransform()) 289 | icon <- (map["icon"], URLTransform()) 290 | } 291 | } 292 | } 293 | } 294 | } 295 | 296 | /** 297 | * DurationInTraffic 298 | */ 299 | public struct DurationInTraffic: Mappable { 300 | public var value: Int? // the duration in seconds. 301 | public var text: String? // human-readable representation of the duration. 302 | 303 | public init?(map: Map) { } 304 | 305 | public mutating func mapping(map: Map) { 306 | value <- map["value"] 307 | text <- map["text"] 308 | } 309 | } 310 | 311 | /** 312 | * Time 313 | */ 314 | public struct Time: Mappable { 315 | public var value: Date? // the time specified as a JavaScript Date object. 316 | public var text: String? // the time specified as a string. 317 | public var timeZone: TimeZone? // the time zone of this station. The value is the name of the time zone as defined in the IANA Time Zone Database, e.g. "America/New_York". 318 | 319 | public init?(map: Map) { } 320 | 321 | public mutating func mapping(map: Map) { 322 | value <- (map["value"], DateTransformInteger()) 323 | text <- map["text"] 324 | timeZone <- (map["time_zone"], timeZoneTransform()) 325 | } 326 | 327 | fileprivate func timeZoneTransform() -> TransformOf { 328 | return TransformOf(fromJSON: { (value: String?) -> TimeZone? in 329 | if let value = value { 330 | return TimeZone(identifier: value) 331 | } 332 | return nil 333 | }, toJSON: { (value: TimeZone?) -> String? in 334 | if let value = value { 335 | return value.identifier 336 | } 337 | return nil 338 | }) 339 | } 340 | } 341 | } 342 | 343 | /** 344 | * Bounds 345 | */ 346 | public struct Bounds: Mappable { 347 | public var northeast: LocationCoordinate2D? 348 | public var southwest: LocationCoordinate2D? 349 | 350 | public init?(map: Map) { } 351 | 352 | public mutating func mapping(map: Map) { 353 | northeast <- (map["northeast"], LocationCoordinate2DTransform()) 354 | southwest <- (map["southwest"], LocationCoordinate2DTransform()) 355 | } 356 | } 357 | 358 | /** 359 | * Fare 360 | */ 361 | public struct Fare: Mappable { 362 | public var currency: String? 363 | public var value: Float? 364 | public var text: String? 365 | 366 | public init?(map: Map) { } 367 | 368 | public mutating func mapping(map: Map) { 369 | currency <- map["currency"] 370 | value <- map["value"] 371 | text <- map["text"] 372 | } 373 | } 374 | } 375 | } 376 | } 377 | 378 | // MARK: - Hex Colors 379 | 380 | public extension Color { 381 | /** 382 | The rgba string representation of color with alpha of the form #RRGGBBAA/#RRGGBB. 383 | 384 | - parameter hexString: String value represents rgba values. 385 | */ 386 | public convenience init?(hexString: String) { 387 | assert(hexString.count == 6) 388 | 389 | guard hexString.hasPrefix("#") else { 390 | return nil 391 | } 392 | 393 | let hexString: String = String(hexString[String.Index.init(encodedOffset: 1)...]) 394 | var hexValue: UInt32 = 0 395 | 396 | guard Scanner(string: hexString).scanHexInt32(&hexValue) else { 397 | return nil 398 | } 399 | 400 | switch (hexString.count) { 401 | case 6: 402 | let divisor = CGFloat(255) 403 | let red = CGFloat((hexValue & 0xFF0000) >> 16) / divisor 404 | let green = CGFloat((hexValue & 0x00FF00) >> 8) / divisor 405 | let blue = CGFloat( hexValue & 0x0000FF ) / divisor 406 | self.init(red: red, green: green, blue: blue, alpha: 1) 407 | default: 408 | return nil 409 | } 410 | } 411 | 412 | /// Get Hex6 String, e.g. "#CC0000" 413 | var hexString: String { 414 | let colorRef = self.cgColor.components 415 | 416 | let r: CGFloat = colorRef![0] 417 | let g: CGFloat = colorRef![1] 418 | let b: CGFloat = colorRef![2] 419 | 420 | return String(format: "#%02X%02X%02X", Int(r * 255), Int(g * 255), Int(b * 255)) 421 | } 422 | } 423 | -------------------------------------------------------------------------------- /Source/Google Maps Directions API/Types.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Types.swift 3 | // GoogleMapsDirections 4 | // 5 | // Created by Honghao Zhang on 2016-01-23. 6 | // Copyright © 2016 Honghao Zhang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension GoogleMapsDirections { 12 | /** 13 | The status code resulting from the geocoding operation. 14 | 15 | - OK: No errors occurred; the address was successfully parsed and at least one geocode was returned. 16 | - ZeroResults: The geocode was successful but returned no results. This may occur if the geocoder was passed a non-existent address. 17 | */ 18 | public enum GeocoderStatus: String { 19 | case ok = "OK" 20 | case zeroResults = "ZERO_RESULTS" 21 | } 22 | 23 | /** 24 | Address type of the geocoding result used for calculating directions. 25 | 26 | - streetAddress: Precise street address 27 | - route: Named route (such as "US 101"). 28 | - intersection: Major intersection, usually of two major roads. 29 | - political: Political entity. Usually, this type indicates a polygon of some civil administration. 30 | - country: The national political entity, and is typically the highest order type returned by the Geocoder. 31 | - administrativeAreaLevel1: First-order civil entity below the country level. Within the United States, these administrative levels are states. Not all nations exhibit these administrative levels. 32 | - administrativeAreaLevel2: Second-order civil entity below the country level. Within the United States, these administrative levels are counties. Not all nations exhibit these administrative levels. 33 | - administrativeAreaLevel3: Third-order civil entity below the country level. This type indicates a minor civil division. Not all nations exhibit these administrative levels. 34 | - administrativeAreaLevel4: Fourth-order civil entity below the country level. This type indicates a minor civil division. Not all nations exhibit these administrative levels. 35 | - administrativeAreaLevel5: Fifth-order civil entity below the country level. This type indicates a minor civil division. Not all nations exhibit these administrative levels. 36 | - colloquialArea: Commonly-used alternative name for the entity. 37 | - locality: Incorporated city or town political entity. 38 | - ward: Specific type of Japanese locality, to facilitate distinction between multiple locality components within a Japanese address. 39 | - sublocality: First-order civil entity below a locality. 40 | - sublocalityLevel1: First-order civil entity below a locality. 41 | - sublocalityLevel2: Second-order civil entity below a locality. 42 | - sublocalityLevel3: Third-order civil entity below a locality. 43 | - sublocalityLevel4: Fourth-order civil entity below a locality. 44 | - sublocalityLevel5: Fifth-order civil entity below a locality. 45 | - neighborhood: Named neighborhood 46 | - premise: Named location, usually a building or collection of buildings with a common name 47 | - subpremise: First-order entity below a named location, usually a singular building within a collection of buildings with a common name 48 | - postalCode: Postal code as used to address postal mail within the country. 49 | - naturalFeature: Prominent natural feature. 50 | - airport: Airport. 51 | - park: Named park. 52 | - pointOfInterest: Named point of interest. Typically, these "POI"s are prominent local entities that don't easily fit in another category, such as "Empire State Building" or "Statue of Liberty." 53 | */ 54 | public enum AddressType: String { 55 | case streetAddress = "street_address" 56 | case route = "route" 57 | case intersection = "intersection" 58 | case political = "political" 59 | case country = "country" 60 | case administrativeAreaLevel1 = "administrative_area_level_1" 61 | case administrativeAreaLevel2 = "administrative_area_level_2" 62 | case administrativeAreaLevel3 = "administrative_area_level_3" 63 | case administrativeAreaLevel4 = "administrative_area_level_4" 64 | case administrativeAreaLevel5 = "administrative_area_level_5" 65 | case colloquialArea = "colloquial_area" 66 | case locality = "locality" 67 | case ward = "ward" 68 | case sublocality = "sublocality" 69 | case sublocalityLevel1 = "sublocality_level_1" 70 | case sublocalityLevel2 = "sublocality_level_2" 71 | case sublocalityLevel3 = "sublocality_level_3" 72 | case sublocalityLevel4 = "sublocality_level_4" 73 | case sublocalityLevel5 = "sublocality_level_5" 74 | case neighborhood = "neighborhood" 75 | case premise = "premise" 76 | case subpremise = "subpremise" 77 | case postalCode = "postal_code" 78 | case naturalFeature = "natural_feature" 79 | case airport = "airport" 80 | case park = "park" 81 | case pointOfInterest = "point_of_interest" 82 | } 83 | 84 | /** 85 | Transportation mode 86 | 87 | - driving: Driving directions using the road network. (default) 88 | - walking: Walking directions via pedestrian paths & sidewalks (where available). 89 | - bicycling: Bicycling directions via bicycle paths & preferred streets (where available). 90 | - transit: Public transit routes (where available). 91 | */ 92 | public enum TravelMode: String { 93 | case driving = "DRIVING" 94 | case walking = "WALKING" 95 | case bicycling = "BICYCLING" 96 | case transit = "TRANSIT" 97 | } 98 | 99 | /** 100 | Calculated route(s) should avoid the indicated features. 101 | 102 | - tolls: Avoid Toll roads/bridges 103 | - highways: Avoid Highways 104 | - ferries: Avoid Ferries 105 | - indoor: Avoid indoor steps for walking and transit directions. Only requests that include an API key or a Google Maps APIs Premium Plan client ID will receive indoor steps by default. 106 | */ 107 | public enum RouteRestriction: String { 108 | case tolls = "tolls" 109 | case highways = "highways" 110 | case ferries = "ferries" 111 | case indoor = "indoor" 112 | } 113 | 114 | /** 115 | Specifies the assumptions to use when calculating time in traffic. 116 | Discussion: This setting affects the value returned in the duration_in_traffic field in the response, which contains the predicted time in traffic based on historical averages. The traffic_model parameter may only be specified for driving directions where the request includes a departure_time, and only if the request includes an API key or a Google Maps APIs Premium Plan client ID. 117 | 118 | - bestGuess: (default) indicates that the returned duration_in_traffic should be the best estimate of travel time given what is known about both historical traffic conditions and live traffic. Live traffic becomes more important the closer the departure_time is to now. 119 | - pessimistic: indicates that the returned duration_in_traffic should be longer than the actual travel time on most days, though occasional days with particularly bad traffic conditions may exceed this value. 120 | - optimistic: indicates that the returned duration_in_traffic should be shorter than the actual travel time on most days, though occasional days with particularly good traffic conditions may be faster than this value. 121 | */ 122 | public enum TrafficMode: String { 123 | case bestGuess = "best_guess" 124 | case pessimistic = "pessimistic" 125 | case optimistic = "optimistic" 126 | } 127 | 128 | /** 129 | Specifies one or more preferred modes of transit. 130 | Discussion: This parameter may only be specified for transit directions, and only if the request includes an API key or a Google Maps APIs Premium Plan client ID. 131 | 132 | - bus: Calculated route should prefer travel by bus. 133 | - subway: Calculated route should prefer travel by subway. 134 | - train: Calculated route should prefer travel by train. 135 | - tram: Calculated route should prefer travel by tram and light rail. 136 | - rail: Calculated route should prefer travel by train, tram, light rail, and subway. This is equivalent to transit_mode=train|tram|subway. 137 | */ 138 | public enum TransitMode: String { 139 | case bus = "bus" 140 | case subway = "subway" 141 | case train = "train" 142 | case tram = "tram" 143 | case rail = "rail" 144 | } 145 | 146 | /** 147 | Specifies preferences for transit routes. 148 | Discussion: Using this parameter, you can bias the options returned, rather than accepting the default best route chosen by the API. This parameter may only be specified for transit directions, and only if the request includes an API key or a Google Maps APIs Premium Plan client ID. 149 | 150 | - lessWalking: Calculated route should prefer limited amounts of walking. 151 | - fewerTransfers: Calculated route should prefer a limited number of transfers. 152 | */ 153 | public enum TransitRoutingPreference: String { 154 | case lessWalking = "less_walking" 155 | case fewerTransfers = "fewer_transfers" 156 | } 157 | 158 | /** 159 | Unit system 160 | Discussion: Directions results contain text within distance fields that may be displayed to the user to indicate the distance of a particular "step" of the route. By default, this text uses the unit system of the origin's country or region. 161 | Note: this unit system setting only affects the text displayed within distance fields. The distance fields also contain values which are always expressed in meters. 162 | 163 | - metric: Metric system. Textual distances are returned using kilometers and meters. 164 | - imperial: Imperial (English) system. Textual distances are returned using miles and feet. 165 | */ 166 | public enum Unit: String { 167 | case metric = "metric" 168 | case imperial = "imperial" 169 | } 170 | 171 | /** 172 | Type of vehicle that runs on this line 173 | 174 | - rail: Rail 175 | - metroRail: Light rail transit. 176 | - subway: Underground light rail. 177 | - tram: Above ground light rail. 178 | - monorail: Monorail. 179 | - heavyRail: Heavy rail. 180 | - commuterRail: Commuter rail. 181 | - highSpeedTrain: High speed train. 182 | - bus: Bus. 183 | - intercityBus: Intercity bus. 184 | - trolleybus: Trolleybus. 185 | - shareTaxi: Share taxi is a kind of bus with the ability to drop off and pick up passengers anywhere on its route. 186 | - ferry: Ferry. 187 | - cableCar: A vehicle that operates on a cable, usually on the ground. Aerial cable cars may be of the type GONDOLA_LIFT. 188 | - gondolaLift: An aerial cable car. 189 | - funicular: A vehicle that is pulled up a steep incline by a cable. A Funicular typically consists of two cars, with each car acting as a counterweight for the other. 190 | - other: All other vehicles will return this type. 191 | */ 192 | public enum VehicleType: String { 193 | case rail = "RAIL" 194 | case metroRail = "METRO_RAIL" 195 | case subway = "SUBWAY" 196 | case tram = "TRAM" 197 | case monorail = "MONORAIL" 198 | case heavyRail = "HEAVY_RAIL" 199 | case commuterRail = "COMMUTER_TRAIN" 200 | case highSpeedTrain = "HIGH_SPEED_TRAIN" 201 | case bus = "BUS" 202 | case intercityBus = "INTERCITY_BUS" 203 | case trolleybus = "TROLLEYBUS" 204 | case shareTaxi = "SHARE_TAXI" 205 | case ferry = "FERRY" 206 | case cableCar = "CABLE_CAR" 207 | case gondolaLift = "GONDOLA_LIFT" 208 | case funicular = "FUNICULAR" 209 | case other = "OTHER" 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /Source/Google Places API/GooglePlaces.swift: -------------------------------------------------------------------------------- 1 | // 2 | // GooglePlaces.swift 3 | // GooglePlaces 4 | // 5 | // Created by Honghao Zhang on 2016-02-12. 6 | // Copyright © 2016 Honghao Zhang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import Alamofire 11 | import ObjectMapper 12 | 13 | public class GooglePlaces: GoogleMapsService { 14 | 15 | fileprivate static var pendingRequest: Alamofire.Request? 16 | 17 | public static let placeAutocompleteURLString = "https://maps.googleapis.com/maps/api/place/autocomplete/json" 18 | 19 | public class func placeAutocomplete(forInput input: String, 20 | offset: Int? = nil, 21 | locationCoordinate: LocationCoordinate2D? = nil, 22 | radius: Int? = nil, 23 | language: String? = nil, 24 | types: [PlaceType]? = nil, 25 | components: String? = nil, 26 | cancelPendingRequestsAutomatically: Bool = true, 27 | completion: ((PlaceAutocompleteResponse?, NSError?) -> Void)?) 28 | { 29 | var requestParameters: [String : Any] = baseRequestParameters + [ 30 | "input" : input 31 | ] 32 | 33 | if let offset = offset { 34 | requestParameters["offset"] = offset 35 | } 36 | 37 | if let locationCoordinate = locationCoordinate { 38 | requestParameters["location"] = "\(locationCoordinate.latitude),\(locationCoordinate.longitude)" 39 | } 40 | 41 | if let radius = radius { 42 | requestParameters["radius"] = radius 43 | } 44 | 45 | if let language = language { 46 | requestParameters["language"] = language 47 | } 48 | 49 | if let types = types { 50 | requestParameters["types"] = types.map { $0.rawValue }.joined(separator: "|") 51 | } 52 | 53 | if let components = components { 54 | requestParameters["components"] = components 55 | } 56 | 57 | if pendingRequest != nil && cancelPendingRequestsAutomatically { 58 | pendingRequest?.cancel() 59 | pendingRequest = nil 60 | } 61 | 62 | let request = Alamofire.request(placeAutocompleteURLString, method: .get, parameters: requestParameters).responseJSON { response in 63 | if response.result.error?._code == NSURLErrorCancelled { 64 | // nothing to do, another active request is coming 65 | return 66 | } 67 | 68 | if response.result.isFailure { 69 | NSLog("Error: GET failed") 70 | completion?(nil, NSError(domain: "GooglePlacesError", code: -1, userInfo: nil)) 71 | return 72 | } 73 | 74 | // Nil 75 | if let _ = response.result.value as? NSNull { 76 | completion?(PlaceAutocompleteResponse(), nil) 77 | return 78 | } 79 | 80 | // JSON 81 | guard let json = response.result.value as? [String : AnyObject] else { 82 | NSLog("Error: Parsing json failed") 83 | completion?(nil, NSError(domain: "GooglePlacesError", code: -2, userInfo: nil)) 84 | return 85 | } 86 | 87 | guard let response = Mapper().map(JSON: json) else { 88 | NSLog("Error: Mapping directions response failed") 89 | completion?(nil, NSError(domain: "GooglePlacesError", code: -3, userInfo: nil)) 90 | return 91 | } 92 | 93 | var error: NSError? 94 | 95 | switch response.status { 96 | case .none: 97 | let userInfo = [ 98 | NSLocalizedDescriptionKey : NSLocalizedString("StatusCodeError", value: "Status Code not found", comment: ""), 99 | NSLocalizedFailureReasonErrorKey : NSLocalizedString("StatusCodeError", value: "Status Code not found", comment: "") 100 | ] 101 | error = NSError(domain: "GooglePlacesError", code: -1, userInfo: userInfo) 102 | case .some(let status): 103 | switch status { 104 | case .ok: 105 | break 106 | default: 107 | let userInfo = [ 108 | NSLocalizedDescriptionKey : NSLocalizedString("StatusCodeError", value: status.rawValue, comment: ""), 109 | NSLocalizedFailureReasonErrorKey : NSLocalizedString("StatusCodeError", value: response.errorMessage ?? "", comment: "") 110 | ] 111 | error = NSError(domain: "GooglePlacesError", code: -1, userInfo: userInfo) 112 | } 113 | } 114 | 115 | pendingRequest = nil 116 | 117 | completion?(response, error) 118 | } 119 | 120 | pendingRequest = request 121 | } 122 | } 123 | 124 | 125 | 126 | // MARK: - Place Details 127 | public extension GooglePlaces { 128 | 129 | public static let placeDetailsURLString = "https://maps.googleapis.com/maps/api/place/details/json" 130 | 131 | public class func placeDetails(forPlaceID placeID: String, extensions: String? = nil, language: String? = nil, completion: ((_ response: PlaceDetailsResponse?, _ error: NSError?) -> Void)?) { 132 | var requestParameters = baseRequestParameters + [ 133 | "placeid" : placeID 134 | ] 135 | 136 | if let extensions = extensions { 137 | requestParameters["extensions"] = extensions 138 | } 139 | 140 | if let language = language { 141 | requestParameters["language"] = language 142 | } 143 | 144 | Alamofire.request(placeDetailsURLString, method: .get, parameters: requestParameters).responseJSON { response in 145 | if response.result.isFailure { 146 | NSLog("Error: GET failed") 147 | completion?(nil, NSError(domain: "GooglePlacesError", code: -1, userInfo: nil)) 148 | return 149 | } 150 | 151 | // Nil 152 | if let _ = response.result.value as? NSNull { 153 | completion?(PlaceDetailsResponse(), nil) 154 | return 155 | } 156 | 157 | // JSON 158 | guard let json = response.result.value as? [String : Any] else { 159 | NSLog("Error: Parsing json failed") 160 | completion?(nil, NSError(domain: "GooglePlacesError", code: -2, userInfo: nil)) 161 | return 162 | } 163 | 164 | guard let response = Mapper().map(JSON: json) else { 165 | NSLog("Error: Mapping directions response failed") 166 | completion?(nil, NSError(domain: "GooglePlacesError", code: -3, userInfo: nil)) 167 | return 168 | } 169 | 170 | var error: NSError? 171 | 172 | switch response.status { 173 | case .none: 174 | let userInfo = [ 175 | NSLocalizedDescriptionKey : NSLocalizedString("StatusCodeError", value: "Status Code not found", comment: ""), 176 | NSLocalizedFailureReasonErrorKey : NSLocalizedString("StatusCodeError", value: "Status Code not found", comment: "") 177 | ] 178 | error = NSError(domain: "GooglePlacesError", code: -1, userInfo: userInfo) 179 | case .some(let status): 180 | switch status { 181 | case .ok: 182 | break 183 | default: 184 | let userInfo = [ 185 | NSLocalizedDescriptionKey : NSLocalizedString("StatusCodeError", value: status.rawValue, comment: ""), 186 | NSLocalizedFailureReasonErrorKey : NSLocalizedString("StatusCodeError", value: response.errorMessage ?? "", comment: "") 187 | ] 188 | error = NSError(domain: "GooglePlacesError", code: -1, userInfo: userInfo) 189 | } 190 | } 191 | 192 | completion?(response, error) 193 | } 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /Source/Google Places API/PlaceAutocompleteResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PlaceAutocompleteResponse.swift 3 | // GooglePlaces 4 | // 5 | // Created by Honghao Zhang on 2016-02-13. 6 | // Copyright © 2016 Honghao Zhang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ObjectMapper 11 | 12 | // MARK: - PlaceAutocompleteResponse 13 | public extension GooglePlaces { 14 | public struct PlaceAutocompleteResponse: Mappable { 15 | public var status: StatusCode? 16 | public var errorMessage: String? 17 | 18 | public var predictions: [Prediction] = [] 19 | 20 | public init() {} 21 | public init?(map: Map) { } 22 | 23 | public mutating func mapping(map: Map) { 24 | status <- (map["status"], EnumTransform()) 25 | errorMessage <- map["error_message"] 26 | 27 | predictions <- map["predictions"] 28 | } 29 | 30 | /** 31 | * Prediction 32 | */ 33 | public struct Prediction: Mappable { 34 | public var description: String? 35 | public var place: Place? 36 | public var terms: [Term] = [] 37 | public var types: [String] = [] 38 | public var matchedSubstring: [MatchedSubstring] = [] 39 | 40 | public init() {} 41 | public init?(map: Map) { } 42 | 43 | public mutating func mapping(map: Map) { 44 | description <- map["description"] 45 | place <- (map["place_id"], TransformOf(fromJSON: { (json) -> Place? in 46 | if let placeId = json { 47 | return Place.placeID(id: placeId) 48 | } else { 49 | return nil 50 | } 51 | }, toJSON: { (place) -> String? in 52 | switch place { 53 | case .none: 54 | return nil 55 | case .some(let place): 56 | switch place { 57 | case .placeID(id: let id): 58 | return id 59 | default: 60 | return nil 61 | } 62 | } 63 | })) 64 | 65 | terms <- map["terms"] 66 | types <- map["types"] 67 | matchedSubstring <- map["matched_substrings"] 68 | } 69 | } 70 | 71 | /** 72 | * Term 73 | */ 74 | public struct Term: Mappable { 75 | public var offset: Int? 76 | public var value: String? 77 | 78 | public init() {} 79 | public init?(map: Map) { } 80 | 81 | public mutating func mapping(map: Map) { 82 | offset <- map["offset"] 83 | value <- map["value"] 84 | } 85 | } 86 | 87 | /** 88 | * MatchedSubstring 89 | */ 90 | public struct MatchedSubstring: Mappable { 91 | public var length: Int? 92 | public var offset: Int? 93 | 94 | public init() {} 95 | public init?(map: Map) { } 96 | 97 | public mutating func mapping(map: Map) { 98 | length <- map["length"] 99 | offset <- map["offset"] 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /Source/Google Places API/PlaceDetailsResponse.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PlaceDetailsResponse.swift 3 | // GooglePlaces 4 | // 5 | // Created by Honghao Zhang on 2016-02-20. 6 | // Copyright © 2016 Honghao Zhang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | import ObjectMapper 11 | 12 | // MARK: - PlaceAutocompleteResponse 13 | public extension GooglePlaces { 14 | public struct PlaceDetailsResponse: Mappable { 15 | public var status: StatusCode? 16 | public var errorMessage: String? 17 | 18 | public var result: Result? 19 | public var htmlAttributions: [String] = [] 20 | 21 | public init() {} 22 | public init?(map: Map) { } 23 | 24 | public mutating func mapping(map: Map) { 25 | status <- (map["status"], EnumTransform()) 26 | errorMessage <- map["error_message"] 27 | 28 | result <- map["result"] 29 | htmlAttributions <- map["html_attributions"] 30 | } 31 | 32 | public struct Result: Mappable { 33 | /// an array of separate address components used to compose a given address. For example, the address "111 8th Avenue, New York, NY" contains separate address components for "111" (the street number, "8th Avenue" (the route), "New York" (the city) and "NY" (the US state). 34 | public var addressComponents: [AddressComponent] = [] 35 | 36 | /// a string containing the human-readable address of this place. Often this address is equivalent to the "postal address," which sometimes differs from country to country. This address is generally composed of one or more address_component fields. 37 | public var formattedAddress: String? 38 | 39 | /// the place's phone number in its local format. For example, the formatted_phone_number for Google's Sydney, Australia office is (02) 9374 4000. 40 | public var formattedPhoneNumber: String? 41 | 42 | /// geometry.location the geocoded latitude,longitude value for this place. 43 | public var geometryLocation: LocationCoordinate2D? 44 | 45 | /// the URL of a suggested icon which may be displayed to the user when indicating this result on a map 46 | public var icon: URL? 47 | 48 | /// the place's phone number in international format. International format includes the country code, and is prefixed with the plus (+) sign. For example, the international_phone_number for Google's Sydney, Australia office is +61 2 9374 4000. 49 | public var internationalPhoneNumber: String? 50 | 51 | /// the human-readable name for the returned result. For establishment results, this is usually the canonicalized business name. 52 | public var name: String? 53 | 54 | /// Opening Hours 55 | public var openingHours: OpeningHours? 56 | 57 | /// a boolean flag indicating whether the place has permanently shut down (value true). If the place is not permanently closed, the flag is absent from the response. 58 | public var permanentlyClosed: Bool = false 59 | 60 | /// an array of photo objects, each containing a reference to an image. A Place Details request may return up to ten photos. More information about place photos and how you can use the images in your application can be found in the Place Photos documentation. 61 | public var photos: [Photo] = [] 62 | 63 | /// A textual identifier that uniquely identifies a place. To retrieve information about the place, pass this identifier in the placeId field of a Places API request. For more information about place IDs, see the place ID overview. 64 | public var placeID: String? 65 | 66 | /// Indicates the scope of the place_id. 67 | public var scope: Scope? 68 | 69 | /// An array of zero, one or more alternative place IDs for the place, with a scope related to each alternative ID. Note: This array may be empty or not present. 70 | public var alternativePlaceIDs: [PlaceIDScope] = [] 71 | 72 | /// The price level of the place, on a scale of 0 to 4. The exact amount indicated by a specific value will vary from region to region. 73 | public var priceLevel: PriceLevel? 74 | 75 | /// the place's rating, from 1.0 to 5.0, based on aggregated user reviews. 76 | public var rating: Float? 77 | 78 | /// a JSON array of up to five reviews. If a language parameter was specified in the Place Details request, the Places Service will bias the results to prefer reviews written in that language. 79 | public var reviews: [Review] = [] 80 | 81 | /// an array of feature types describing the given result. See the list of supported types for more information. 82 | public var types: [String] = [] 83 | 84 | /// the URL of the official Google page for this place. This will be the Google-owned page that contains the best available information about the place. Applications must link to or embed this page on any screen that shows detailed results about the place to the user. 85 | public var url: URL? 86 | 87 | /// the number of minutes this place’s current timezone is offset from UTC. For example, for places in Sydney, Australia during daylight saving time this would be 660 (+11 hours from UTC), and for places in California outside of daylight saving time this would be -480 (-8 hours from UTC). 88 | public var utcOffset: Int? 89 | 90 | /// a simplified address for the place, including the street name, street number, and locality, but not the province/state, postal code, or country. For example, Google's Sydney, Australia office has a vicinity value of 48 Pirrama Road, Pyrmont. 91 | public var vicinity: String? 92 | 93 | /// the authoritative website for this place, such as a business' homepage. 94 | public var website: String? 95 | 96 | public init() {} 97 | public init?(map: Map) { } 98 | 99 | public mutating func mapping(map: Map) { 100 | addressComponents <- map["address_components"] 101 | formattedAddress <- map["formatted_address"] 102 | formattedPhoneNumber <- map["formatted_phone_number"] 103 | geometryLocation <- (map["geometry.location"], LocationCoordinate2DTransform()) 104 | icon <- (map["icon"], URLTransform()) 105 | internationalPhoneNumber <- map["international_phone_number"] 106 | name <- map["name"] 107 | openingHours <- map["opening_hours"] 108 | permanentlyClosed <- map["permanently_closed"] 109 | photos <- map["photos"] 110 | placeID <- map["place_id"] 111 | scope <- (map["scope"], EnumTransform()) 112 | alternativePlaceIDs <- map["alt_ids"] 113 | priceLevel <- map["price_level"] 114 | rating <- map["rating"] 115 | reviews <- map["reviews"] 116 | types <- map["types"] 117 | url <- map["url"] 118 | utcOffset <- map["utc_offset"] 119 | vicinity <- map["vicinity"] 120 | website <- map["website"] 121 | } 122 | 123 | /** 124 | * AddressComponent 125 | address components used to compose a given address. For example, the address "111 8th Avenue, New York, NY" contains separate address components for "111" (the street number, "8th Avenue" (the route), "New York" (the city) and "NY" (the US state) 126 | */ 127 | public struct AddressComponent: Mappable { 128 | /// an array indicating the type of the address component. 129 | public var types: [String] = [] 130 | 131 | /// the full text description or name of the address component. 132 | public var longName: String? 133 | 134 | /// an abbreviated textual name for the address component, if available. For example, an address component for the state of Alaska may have a long_name of "Alaska" and a short_name of "AK" using the 2-letter postal abbreviation. 135 | public var shortName: String? 136 | 137 | public init() {} 138 | public init?(map: Map) { } 139 | 140 | public mutating func mapping(map: Map) { 141 | types <- map["types"] 142 | longName <- map["long_name"] 143 | shortName <- map["short_name"] 144 | } 145 | } 146 | 147 | public struct OpeningHours: Mappable { 148 | /// a boolean value indicating if the place is open at the current time. 149 | public var openNow: Bool = false 150 | 151 | /// an array of opening periods covering seven days, starting from Sunday, in chronological order. 152 | public var periods: [Period] = [] 153 | 154 | /// an array of seven strings representing the formatted opening hours for each day of the week. If a language parameter was specified in the Place Details request, the Places Service will format and localize the opening hours appropriately for that language. The ordering of the elements in this array depends on the language parameter. Some languages start the week on Monday while others start on Sunday. 155 | public var weekdayText: [String] = [] 156 | 157 | public init() {} 158 | public init?(map: Map) { } 159 | 160 | public mutating func mapping(map: Map) { 161 | openNow <- map["open_now"] 162 | periods <- map["periods"] 163 | weekdayText <- map["weekday_text"] 164 | } 165 | 166 | public struct Period: Mappable { 167 | /// a pair of day and time objects describing when the place opens 168 | public var open: DayTime? 169 | 170 | /// may contain a pair of day and time objects describing when the place closes. Note: If a place is always open, the close section will be missing from the response. Clients can rely on always-open being represented as an open period containing day with value 0 and time with value 0000, and no close. 171 | public var close: DayTime? 172 | 173 | public init() {} 174 | public init?(map: Map) { } 175 | 176 | public mutating func mapping(map: Map) { 177 | open <- map["open"] 178 | close <- map["close"] 179 | } 180 | 181 | public struct DayTime: Mappable { 182 | /// a number from 0–6, corresponding to the days of the week, starting on Sunday. For example, 2 means Tuesday. 183 | public var day: Int? 184 | 185 | /// contain a time of day in 24-hour hhmm format. Values are in the range 0000–2359. The time will be reported in the place’s time zone. 186 | public var time: Int? 187 | 188 | public init() {} 189 | public init?(map: Map) { } 190 | 191 | public mutating func mapping(map: Map) { 192 | day <- map["day"] 193 | time <- map["time"] 194 | } 195 | } 196 | } 197 | } 198 | 199 | public struct Photo: Mappable { 200 | /// a string used to identify the photo when you perform a Photo request. 201 | public var photoReference: String? 202 | 203 | /// the maximum height of the image. 204 | public var height: Float? 205 | 206 | /// the maximum width of the image. 207 | public var width: Float? 208 | 209 | /// contains any required attributions. This field will always be present, but may be empty. 210 | public var htmlAttributions: [String] = [] 211 | 212 | public init() {} 213 | public init?(map: Map) { } 214 | 215 | public mutating func mapping(map: Map) { 216 | photoReference <- map["photo_reference"] 217 | height <- map["height"] 218 | width <- map["width"] 219 | htmlAttributions <- map["html_attributions"] 220 | } 221 | } 222 | 223 | /// The scope of the place_id 224 | /// 225 | /// - app: The place ID is recognised by your application only. This is because your application added the place, and the place has not yet passed the moderation process. 226 | /// - google: The place ID is available to other applications and on Google Maps. 227 | public enum Scope: String { 228 | case app = "APP" 229 | case google = "GOOGLE" 230 | } 231 | 232 | public struct PlaceIDScope: Mappable { 233 | /// The most likely reason for a place to have an alternative place ID is if your application adds a place and receives an application-scoped place ID, then later receives a Google-scoped place ID after passing the moderation process. 234 | public var placeID: String? 235 | 236 | /// The scope of an alternative place ID will always be APP, indicating that the alternative place ID is recognised by your application only. 237 | public var scope: Scope? 238 | 239 | public init() {} 240 | public init?(map: Map) { } 241 | 242 | public mutating func mapping(map: Map) { 243 | placeID <- map["place_id"] 244 | scope <- (map["scope"], EnumTransform()) 245 | } 246 | } 247 | 248 | /** 249 | The price level of the place, on a scale of 0 to 4. The exact amount indicated by a specific value will vary from region to region. 250 | 251 | - free: Free 252 | - inexpensive: Inexpensive 253 | - moderate: Moderate 254 | - expensive: Expensive 255 | - veryExpensive: Very Expensive 256 | */ 257 | public enum PriceLevel: Int { 258 | case free = 0 259 | case inexpensive 260 | case moderate 261 | case expensive 262 | case veryExpensive 263 | } 264 | 265 | public struct Review: Mappable { 266 | /// a collection of AspectRating objects, each of which provides a rating of a single attribute of the establishment. The first object in the collection is considered the primary aspect. 267 | public var aspects: [AspectRating] = [] 268 | 269 | /// the name of the user who submitted the review. Anonymous reviews are attributed to "A Google user". 270 | public var authorName: String? 271 | 272 | /// the URL to the users Google+ profile, if available. 273 | public var authorURL: URL? 274 | 275 | /// an IETF language code indicating the language used in the user's review. This field contains the main language tag only, and not the secondary tag indicating country or region. For example, all the English reviews are tagged as 'en', and not 'en-AU' or 'en-UK' and so on. 276 | public var language: String? 277 | 278 | /// the user's overall rating for this place. This is a whole number, ranging from 1 to 5. 279 | public var rating: Float? 280 | 281 | /// the user's review. When reviewing a location with Google Places, text reviews are considered optional. Therefore, this field may by empty. Note that this field may include simple HTML markup. For example, the entity reference & may represent an ampersand character. 282 | public var text: String? 283 | 284 | /// the time that the review was submitted, measured in the number of seconds since since midnight, January 1, 1970 UTC. 285 | public var time: Date? 286 | 287 | /// a rich and concise review curated by Google's editorial staff. This field will be absent unless you pass the extensions=review_summary parameter in your details request. Note that this field may not be available in the requested language. 288 | public var reviewSummary: String? 289 | 290 | /// the place has been selected as a Zagat quality location. The Zagat label identifies places known for their consistently high quality or that have a special or unique character. 291 | public var zagatSelected: Bool = false 292 | 293 | public init() {} 294 | public init?(map: Map) { } 295 | 296 | public mutating func mapping(map: Map) { 297 | aspects <- map["aspects"] 298 | authorName <- map["author_name"] 299 | authorURL <- (map["author_url"], URLTransform()) 300 | language <- map["language"] 301 | rating <- map["rating"] 302 | text <- map["text"] 303 | time <- (map["time"], DateTransform()) 304 | 305 | reviewSummary <- map["review_summary"] 306 | zagatSelected <- map["zagat_selected"] 307 | } 308 | 309 | public struct AspectRating: Mappable { 310 | /// the name of the aspect that is being rated. 311 | public var type: Type? 312 | 313 | /// the user's rating for this particular aspect, from 0 to 3. 314 | public var rating: Float? 315 | 316 | public init() {} 317 | public init?(map: Map) { } 318 | 319 | public mutating func mapping(map: Map) { 320 | type <- map["type"] 321 | rating <- map["rating"] 322 | } 323 | 324 | /** 325 | the name of the aspect that is being rated. 326 | */ 327 | public enum `Type`: String { 328 | case appeal = "appeal" 329 | case atmosphere = "atmosphere" 330 | case decor = "decor" 331 | case facilities = "facilities" 332 | case food = "food" 333 | case overall = "overall" 334 | case quality = "quality" 335 | case service = "service" 336 | } 337 | } 338 | } 339 | } 340 | } 341 | } 342 | -------------------------------------------------------------------------------- /Source/Google Places API/Types.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Types.swift 3 | // GooglePlaces 4 | // 5 | // Created by Honghao Zhang on 2016-02-12. 6 | // Copyright © 2016 Honghao Zhang. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension GooglePlaces { 12 | public enum PlaceType: String { 13 | case geocode = "geocode" 14 | case address = "address" 15 | case establishment = "establishment" 16 | case regions = "(regions)" 17 | case cities = "(cities)" 18 | } 19 | } 20 | --------------------------------------------------------------------------------