SwiftLocation 5.1.0

SwiftLocation 5.1.0

测试已测试
Lang语言 SwiftSwift
许可 NOASSERTION
发布上次发布2021年2月
SPM支持SPM

Daniele Margutti维护。



SwiftLocation

位置管理变得简单

SwiftLocation是一个轻量级的Swift库,它提供了一个简单的方式来处理与位置相关的功能。不再需要处理委托或回调,而是一个简单基于请求的架构,拥有多个订阅和自动调整核心位置管理器的设置。

特性 描述
🛰 通过GPS定位 通过完全可配置的API监视单个、连续或重要的位置更新。
👩‍💻 通过IP定位 在未获得用户授权的情况下估算位置数据。
IPApiIPDataIPGeolocationIPInfoIPifyIPStack.
🛴 围栏功能 支持圆形区域和自定义多边形的监视。
🌍 Geo编码器
反向Geo编码器
从坐标获取地址或相反。
AppleGoogleHereMapBoxOpenStreet.
🏠 自动完成 地址、地点或POI的建议与详情。
AppleGoogleHere.
📍 信标 信标测距、监视。
📡 信标广播器 从应用中广播信标(仅在前台)
🏞 访问 重要访问位置监视。

🤾立即播放!

SwiftLocation附带了一个playground应用程序,您可以使用它来了解如何使用此库或只是与每个支持的功能互动!

drawing

❤️您的支持

嘿,亲爱的开发者!
你知道,维护和开发工具需要资源和时间。虽然我享受制作它们,但您的支持对我的持续发展至关重要

如果您使用SwiftLocation或我的其他创造,请考虑以下选项:

简介

使用方法简单;所有的功能都可通过SwiftLocation对象访问。

每个功能都会向池管理器添加一个新的请求(符合RequestProtocol协议)对象,您可以使用该对象来获取结果或微调其配置。

结果是Result<Data, LocationError>对象(其中Data是一个结构体/类,它依赖于请求)。
您可以按需管理,但SwiftLocation还公开了两个可选属性。

  • .error用于获取生成的错误(LocationError?)。
  • .data用于获取生成的结果(<RequestInstance>.ProducedData)。

所有请求都会自动保留,因此您不需要将它们保持活动状态,直到它们运行。

您可以添加一个或多个订阅,通过在请求上调用then()运算符来获取生成的数据(您可以指定返回结果的DispatchQueue,默认为.main)。

要取消/停止正在运行的请求(例如,持续的位置更新),请调用其上的cancelRequest():它将从队列中删除请求并根据剩余请求调整核心位置设置(如果需要)。

要暂时停止请求(同时仍在队列中),请使用.isEnabled属性。

发现特性

通过GPS获取用户位置

只需一行代码

SwiftLocation.gpsLocation().then {
    print("Location is \($0.location)")
}

记住:在您使用SwiftLocation之前,应在您的Info.plist文件中设置适当的键(NSLocationAlwaysAndWhenInUseUsageDescriptionNSLocationWhenInUseUsageDescriptionNSLocationTemporaryUsageDescriptionDictionary,如果您在使用iOS 14+中的减少位置)。

如果您需要更多的自定义,您可以通过配置每个可用的参数来微调您的请求。这是一个更复杂的示例

SwiftLocation.gpsLocationWith {
    // configure everything about your request
    $0.subscription = .continous // continous updated until you stop it
    $0.accuracy = .house 
    $0.minDistance = 300 // updated every 300mts or more
    $0.minInterval = 30 // updated each 30 seconds or more
    $0.activityType = .automotiveNavigation
    $0.timeout = .delayed(5) // 5 seconds of timeout after auth granted
}.then { result in // you can attach one or more subscriptions via `then`.
    switch result {
    case .success(let newData):
        print("New location: \(newData)")
    case .failure(let error):
        print("An error has occurred: \(error.localizedDescription)")
    }
}

.significant 订阅需要始终授权,即使在后台也能正常工作。

如果应用没有运行,它被系统恢复,SwiftLocation将为您恢复GPS请求,这样您就可以绑定自己的订阅了。

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // The best place to resume your requests is the app launch.
    SwiftLocation.onRestoreGPS = { requests in
        for request in requests {
            request.then {
                // do anything or bind to your own classes
            }
        }
    }
    ...
}

获取最后一个已知位置

SwiftLocation 库会自动存储最后一个已知位置,即使在应用程序重启之间

let location = SwiftLocation.lastKnownGPSLocation

地理编码器 & 反向地理编码器

地理编码是将地址(如街道地址)转换为地理坐标的过程,您可以使用这些坐标将标记放置在地图上,或定位地图。
反向地理编码是将点位置反向编码为可读地址或地名的过程。

让我展示如何使用 Apple 服务获取一个著名地点的坐标

let service = Geocoder.Apple(address: "1 infinite loop cupertino")
SwiftLocation.geocodeWith(service).then { result in
    // You will get an array of suggested [GeoLocation] objects with data and coordinates
    print(result.data)
}

反向地理编码依然简单。这是一个使用 google 的例子

let service = Geocoder.Google(lat: 37.331656, lng: -122.0301426, APIKey: "<your api key>")
SwiftLocation.geocodeWith(service).then { result in
    // Different services, same expected output [GeoLocation]
    print(result.data)
}

如你所见,预期输出没有区别;所有服务都返回相同的输出,即一个包含获取数据的 [GeoLocation] 对象数组的输出 (请参阅文档以获取更多详情)

正如你所看到的,一些服务需要 API 密钥;每次请求都传递密钥真的很无聊吗?
如果您计划为某一系列的 所有服务使用相同的密钥,请考虑使用共享凭据存储

SwiftLocation.credentials[.google] = "<google api key>" // setup the key

// you can now omit the APIKey parameter in your google requests!
// SwiftLocation will automatically read the shared credentials value!
let service = Geocoder.Google(address: "Via Roma 1, Milano")
SwiftLocation.geocodeWith(service).then { result in
    // ...
}

每个服务都有自己的独特设置,您可以进行配置(请参阅完整的文档,这里)。
一旦创建了服务对象,您就可以在将其发送到请求池之前配置其自身设置

let service = Geocoder.MapBox(address: "Trafalgar Square")
// MapBox service has lots of configuration available to get better results
service.locale = "en"
service.limit = 1
service.boundingBox = Geocoder.MapBox.BoundingBox(minLat: 40.7661, minLon: -73.9876,
                                                  maxLat: 40.8002, maxLon: -73.9397)
service.resultTypes = [.place]
SwiftLocation.geocodeWith(service).then { result in
    print(result.data) // different services, same expected output [GeoLocation]
}

它支持以下服务 (其中一些需要 API 密钥),均在 Geocoder 下(请参阅文档获取更多信息)。

通过 IP 地址获取位置

有时您不需要精确的位置,也不想麻烦用户授权应用程序获取它。
在这些情况下,您可以使用六个可用的服务之一,仅通过使用 IP 位置服务即可获取近似位置(和一些其他位置数据)。

以下示例演示了如何获取包含从当前设备 IP 地址检索的所有信息的 IPLocation.Data 对象 (您也可以在服务的初始化中指定其他 IP 地址)

SwiftLocation.ipLocationWith(IPLocation.IPData()).then { result in
    print(result.location.coordinates)
    // get the city and other data from .info dictionary
    print(result.location.info[.city])
    print(result.location.info[.countryCode])
}

它支持以下服务 (其中一些需要 API 密钥)。请查看单个类以读取自定义配置

自动完成地址

您可以使用自动完成功能,为您的应用提供类似地图应用搜索字段的前瞻性搜索行为。自动完成服务可以匹配完整单词和子字符串,解析地点名称、地址和加码(1)。因此,应用可以在用户输入时发送查询,提供即时地点预测。

您还可以获取预测的详细信息,即当用户点击其中的一个建议并需要获取坐标和其他数据(2)时。

服务在《自动完成》的伞形下提供并支持。
您可以创建两种自动完成的类型

  • (1) 查找完整单词和子字符串(.init(partialMatches: ...
  • (2) 位置详情(.init(detailsFor: ...)
let australia = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: -33.269290, longitude: 150.479955), latitudinalMeters: 20000, longitudinalMeters: 20000)

let service = Autocomplete.Apple(partialMatches: "Mart", region: australia)
SwiftLocation.autocompleteWith(service).then { result in
    // You get an array of `PartialAddressMatch`
    // From this array you can obtain infos with (2).
    //
    // Martial Arts Search Nearby, 
    // Mart Search Nearby, Martinsville,
    // NSW, Australia
    // ...
    let partialMatches = result.data.map { $0.partialAddress }
}

现在假设您想从第一个结果Martial Arts Search Nearby获取更多信息。
只需调用该服务即可

let detailService = Autocomplete.Apple(detailsFor: partialMatches.first)
SwiftLocation.autocompleteWith(detailService).then { result in
    // Extract the array of found `GeoLocation` places
    let places = result.data?.map({ $0.place })
    let firstResult: GeoLocation = places?.first
    print(firstResult.coordinates) // coordinates
    // .info contains additional fetched information depending from used service
    print(firstResult.info[.formattedAddress])
    print(firstResult.info[.subAdministrativeArea]) 
    // ...
}

如果您使用Autocomplete.Google(partialMatches: "..."),预期结果类型没有区别,但“info”字典可能包含更多或更少的数据。
当然,不同的服务暴露了不同的设置

let service = Autocomplete.Google(partialMatches: "Mart")
// See the doc for all settings each service exposes!
service.placeTypes = [.cities, .address]
service.radius = 500
service.strictBounds = true
SwiftLocation.autocompleteWith(detailService).then { ... }

它支持以下在《自动完成》的伞形下可用的地理围栏服务(有关更多信息,请参阅文档)

地理围栏区域

地理围栏是现实世界地理区域的虚拟边界。
地理围栏用例的一个例子是,基于位置的服务(LBS)用户的位置感知设备进入或退出地理围栏。

使用SwiftLocation,您可以监控以下内容

  • 圆形区域
  • 自定义多边形区域 (实际上它工作不正确,因此请避免使用)
let options = GeofencingOptions(circleWithCenter: CLLocationCoordinate2D(latitude: 3, longitude: 2), radius: 100)
SwiftLocation.geofenceWith(options).then { result in
    guard let event = result.data else { return }

    switch event {
    case .didEnteredRegion(let r):
        print("Triggered region entering! \(r)")
    case .didExitedRegion(let r):
        print("Triggered region exiting! \(r)")
    default:
        break
    }
}

要监控自定义多边形,只需创建适当的

GeofencingOptions,将

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // The best place to resume your requests when app is killed
    SwiftLocation.onRestoreGeofences = { requests in // do anything you want }
}

let options GeofencingOptions(polygon: <MKPolygon>)传递。

有时您可能只需要在用户的移动值得关注时监控更新。访问服务是收集位置数据最节能的方式。
每次更新都包括位置和在该位置停留的时间。此服务不适用于导航或其他实时活动(
了解更多)。

// You can also specify an activity To help the system determine how to manage the battery use.
SwiftLocation.visits(activityType: .fitness).then { result in
    print("A new visits to \(result.data)")
}

即使应用被杀死,该功能也将在后台工作,您可以在需要触发某些事件时在应用启动时恢复它。

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // The best place to resume your requests when app is killed
    SwiftLocation.onRestoreVisits = { requests in // do anything you want }
}

信标监控

信标是一种发出蓝牙信号并可由您的设备检测到的设备。您可以根据邻近信标的距离来决定采取哪些行动(了解更多)。

let beacon = BeaconRequest.Beacon(uuid: <UUID>, minor: <MinorID>, major: <MajorID>)
SwiftLocation.beacon(beacon).then { result in
    guard let event = result.data else { return }
    switch event {
    case .rangingBeacons(let b):
        print("Ranged beacon: \(b)")
    case .didEnterRegion(let r):
        print("Did enter in region: \(r)")
    case .didExitRegion(let r):
        print("Did exit in \(r)")
    }
}

当然,您可以监控一个或多个信标或一个家庭UUID。

SwiftLocation.beacon(BeaconRequest(UUIDs: [<UUID_Family1>,<UUID_Family2>])).then { ... }

信标广播

有时您可能需要将您的应用作为信标进行广播。SwiftLocation 允许您这样做(然而,由于iOS的限制,它只能在应用打开的前台工作)。

let beaconToSimulate = BroadcastedBeacon(UUID: <UUID>, 
                                        majorID: <MajorID>, minorID: <MinorID>, 
                                        identifier: <Identifier>)
SwiftLocation.broadcastAsBeacon(beaconToSimulate)

使用 SwiftLocation.stopBroadcasting() 可让您停止广播,而使用 SwiftLocation.isBeaconBroadcastActive 可让您检查是否正在传播。

用户授权请求

通常,您不需要手动管理授权,因为 SwiftLocation 会根据您添加到池管理器和您的 Info.plist 配置的请求来处理它(您可以通过设置 SwiftLocation.preferredAuthorizationMode = <AuthorizationMode> 强制首选授权模式;默认为 .plist)。

但是,如果您需要手动请求授权,您仍然可以使用

SwiftLocation.requestAuthorization(.onlyInUse) { newStatus in
    print("New status \(newStatus.description)")
}

要获取当前的授权状态,请使用
let currentStatus = SwiftLocation.authorizationStatus

后台位置更新

为了在后台获取位置连续更新,您需要在Xcode项目的“签名与能力”中指定适当的后台能力 > 位置更新。
此外,您还应该将 SwiftLocation.allowsBackgroundLocationUpdates = true 设置为true。

可选地,您也可以设置 SwiftLocation.pausesLocationUpdatesAutomatically = true,允许位置管理器暂停更新以提高目标设备的电池寿命,同时不牺牲位置数据。当此属性设置为true时,位置管理器会在位置数据不太可能变化时暂停更新(并关闭相应的硬件)。例如,如果用户在使用导航应用时停下来吃东西,位置管理器可能会暂停一段时间的更新。您可以通过分配一个值给activityType属性来帮助确定何时暂停位置更新。

最后,如果您的应用已停止,所有请求将自动保存,可以在应用启动的早期阶段恢复,如下面的示例所示。

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // The best place to resume your requests is the app launch.
    SwiftLocation.onRestoreGPS = { requests in ... }
    SwiftLocation.onRestoreVisits = { requests in ... }
    SwiftLocation.onRestoreGeofences = { requests in ... }
    ...
}

如果您想禁用自动请求的保存,可以设置 SwiftLocation.automaticRequestSave = false

在iOS 14+中精确和降低位置

位置数据非常敏感;自iOS 14以来,苹果为Core Location Manager增加了另一层隐私保护:用户可以选择是否提供精确或近似位置访问
从5.0.1以来,SwiftLocation支持此选项,并且对旧iOS版本是透明的。

您可以在创建新请求时使用GPSLocationOptions对象的.precise属性指定您可以使用的精确选项。如果您没有指定它,您将获得用户在第一次授权请求时设置的位置精度。
如果您在某个时刻需要获取精确位置,您可以显式请求一次性权限设置.precise = .fullAccuracy
当用户设置了降低精度时,SwiftLocation需要请求进一步的授权;您不需要做任何事情!

SwiftLocation.gpsLocationWith {
  $0.precise = .fullAccuracy
  // set any other filter options
}.then { result in
  print("Location found is \(result.location) and it's \(SwiftLocation.preciseAccuracy.description)")
}

您可以使用SwiftLocation.preciseAccuracy来获取当前精确授权状态,并根据您的业务逻辑采取行动。

此选项自iOS14+开始提供。旧版本始终使用fullAccuracy,参数将被忽略。

安装

SwiftLocation与Swift 5.x+兼容,在iOS (11+)和macOS平台上。

您可以通过CocoaPods安装它

use_frameworks!
pod 'SwiftLocation/Core'
pod 'SwiftLocation/BeaconBroadcaster' ## If you want to use Beacon Broadcaster

或在您的Package.swift中使用SPM

import PackageDescription

  let package = Package(name: "YourPackage",
    dependencies: [
      .Package(url: "https://github.com/malcommac/SwiftLocation.git", majorVersion: 0),
    ]
  )

然后,您必须使用import SwiftLocation来使用核心功能。
要使用蓝牙服务,您可以导入import SwiftLocationBeaconBroadcaster

考虑 ❤️ 支持这个库的开发

贡献

  • 如果您需要帮助或者想要提问,请打开一个问题。
  • 如果您发现了一个错误,请打开一个问题。
  • 如果您有一个功能请求,请打开一个问题。
  • 如果您想要贡献,请提交一个拉取请求。

版权 & 致谢

SwiftLocation 目前由 Daniele Margutti 拥有和维护。
您可以在 Twitter 上关注我 @danielemargutti
我的网站是 https://www.danielemargutti.com

本软件遵照 MIT 许可证 许可。

关注我在