RxLocationManager 2.0.0

RxLocationManager 2.0.0

测试已测试
语言语言 SwiftSwift
许可证 MIT
发布最新发布2016年11月
SwiftSwift 版本3.0
SPM支持 SPM

RxLocationManager 维护。



  • 作者:
  • Yonny Hao

Swift 下的 Reactivity LocationManager

介绍

如果你采用 RP(RxSwift) 模式进行应用程序开发,可能觉得 CLLocationManager 使用起来不方便。RxLocationManager 旨在为 CLLocationManager 创建一个“reactive”界面,这样就无需担心像使视图控制器符合 CLLocationManagerDelegate,这有时感觉不太自然,或者放置 CLLocationManager 实例(例如 AppDelegate)以便轻松引用等问题。所有这些都在 RxLocationManager 类及其静态方法和变量中完成。内部 RxLocationManager 有多个共享的 CLLocationManagerDelegate 实例,并在内存使用和电池寿命方面有效地管理它们。RxLocationManager 并不像 CLLocationManager 那样提供“一站式”类,而是根据它们的相对性将属性和方法分为几个组,例如将位置相关 API 放入 StandardLocationService 类,将航向更新相关 API 放入 HeadingUpdateService 类,将区域监控相关 API 放入 RegionMonitoringService 类(它还包括测距信标功能),并将访问监控相关 API 放入 MonitoringVisitsService,因此使用起来更清晰。

要求

  • iOS 8.0+ | macOS 10.10+ | tvOS 9.0+ | watchOS 2.0+
  • Xcode 8.1+
  • Swift 3.0+(对于 Swift 2 支持请查看分支 Swift-2.X
  • RxSwift 3.0+

安装

Git 子模块

  • 运行以下命令将 RxLocationManager 作为子模块添加
$ git submodule add [email protected]:popduke/RxLocationManager.git
  • RxLocationManager.xcodeproj 拖动到 Project Navigator
  • 转到 项目 > 目标 > 编译阶段 > 链接二进制库,点击 + 并选择 RxLocationManager [平台] 目标

用法

📌始终参考 CLLocationManager 的官方文档,了解如何配置它以在不同模式下工作📌

在导入 RxLocationManager 模块时添加以下行

import RxLocationManager

观察位置服务启用/禁用状态变化

RxLocationManager.enable
.map{
   //$0 is Boolean
   return $0 ? "enabled" : "disabled"
}
.subscribe(onNext:{
   print("Location Service is \($0)")
})
.addDisposableTo(disposeBag)

观察应用的授权状态变化

RxLocationManager.authorizationStatus
.subscribe(onNext:{
   //$0 is CLAuthorizationStatus
   print("Current authorization status is \($0)")
})
.addDisposableTo(disposeBag)

请求应用的授权

//ask for WhenInUse authorization
RxLocationManager.requestWhenInUseAuthorization()
//ask for Always authorization
RxLocationManager.requestAlwaysAuthorization()

确定服务可用性

#if os(iOS) || os(OSX)
RxLocationManager.significantLocationChangeMonitoringAvailable
RxLocationManager.isMonitoringAvailableForClass(regionClass: AnyClass) -> Bool
#endif

#if os(iOS)
RxLocationManager.deferredLocationUpdatesAvailable 
RxLocationManager.headingAvailable 
RxLocationManager.isRangingAvailable
#endif

标准位置服务

StandardLocationService 包含两个主要 ObservableLocatedLocatingLocated 在每次订阅和完成时只报告一个 CLLocation 对象,代表设备的当前确定的地理位置;Locating 在观察时报告一系列的 CLLocation 对象,代表设备的不断变化的位置。多个订阅共享单个底层的 CLLocationManager 对象,RxLocationManager 在第一次订阅时开始位置更新,并在最后一个订阅被丢弃后停止。

确定设备的当前位置

// RxLocationManager.Standard is a shared standard location service instance
#if os(iOS) || os(watchOS) || os(tvOS)
RxLocationManager.Standard.located.subscribe(
    onNext:{
        // the event will only be triggered once to report current determined location of device
        print("Current Location is \($0)")
    },
    onError:{
        // in case some error occurred during determining device location, e.g. LocationUnknown
    },
    onCompleted:{
        // completed event will get triggered after location is reported successfully
        print("Subscription is Completed")    
    })
    .addDisposableTo(disposeBag)
#endif

监控设备的定位更新

#if os(iOS) || os(OSX) || os(watchOS)
//available in watchOS 3.0
RxLocationManager.Standard.locating.subscribe(
    onNext:{
        // series of events will be delivered during subscription
        print("Current Location is \($0)")        
    },
    onError:{
        // LocationUnknown error will be ignored, and other errors reported    
    },
    onCompleted:{
        // no complete event    
    })
    .addDisposableTo(disposeBag)
#endif

配置

在开始订阅 locatedlocating 之前,您也可以通过以下链式风格的 API 配置标准位置服务实例

RxLocationManager.Standard.distanceFilter(distance: CLLocationDistance) -> StandardLocationService
RxLocationManager.Standard.desiredAccuracy(desiredAccuracy: CLLocationAccuracy) -> StandardLocationService

#if os(iOS)
RxLocationManager.Standard.allowsBackgroundLocationUpdates(allow : Bool) -> StandardLocationService
RxLocationManager.Standard.activityType(type: CLActivityType) -> StandardLocationService
#endif

为位置交付启用自动暂停模式,并观察暂停状态变化的通知

#if os(iOS)
RxLocationManager.Standard.pausesLocationUpdatesAutomatically(true)

RxLocationManager.Standard.isPaused
.map{
    //$0 is Boolean
    return $0 ? "Paused" : "Resumed"
}
.subscribe(
    onNext:{
        print("Location Updating is \($0)")
    }
)
.addDisposableTo(disposeBag)
#endif

设置/删除延迟位置更新条件,并在条件满足或出现错误时进行观察

#if os(iOS)
//Setup deferred location update condition
RxLocationManager.Standard.allowDeferredLocationUpdates(untilTraveled:100, timeout: 120)

//Remove current deferred update condition
RxLocationManager.Standard.disallowDeferredLocationUpdates()

//Observe the event when condition is satisfied or finished with error
RxLocationManager.Standard.deferredUpdateFinished
.map{
    //$0 is NSError?
    return $0 == nil ? "Finished" : "Finished with error code \($0.code) in \($0.domain)"
}
.subscribe(
    onNext:{
        error in
        print("Location Updating is \($0)")
    }
)
.addDisposableTo(disposeBag)
#endif

多个标准位置服务

在某些情况下,您的应用可能需要多个配置不同的标准位置服务,您可以通过从共享实例克隆来创建一个新的实例

var anotherStandardLocationService = RxLocationManager.Standard.clone()
anotherStandardLocationService.distanceFilter(100).desiredAccuracy(50)

显著位置更新服务

SignificantLocationUpdateService 只包含一个 Observablelocating,在观察时会报告一系列的 CLLocation 对象,代表设备执行显著的地理位置变化。多个订阅共享单个底层的 CLLocationManager 对象,RxLocationManager 在第一次订阅时开始监视显著的位置变化,并在最后一个订阅被丢弃后停止。

#if os(iOS) || os(OSX)
// RxLocationManager.SignificantLocation is the shared significant location update service instance
RxLocationManager.SignificantLocation.locating.subscribe(
    onNext:{
        print("Current Location is \($0)")
    },
    onError:{        
        // in case errors
    },
    onCompleted:{
        // no complete event        
    }
)
.addDisposableTo(disposeBag)
#endif

航向更新服务

HeadingUpdateService 只包含一个 Observableheading,在观察时会报告一系列的 CLHeading 对象,代表设备的航向变化。多个订阅共享单个底层的 CLLocationManager 对象,RxLocationManager 在第一次订阅时开始监视设备航向的变化,并在最后一个订阅被丢弃后停止。

观察设备航向变化

#if os(iOS)
// RxLocationManager.HeadingUpdate is the shared heading update service instance
RxLocationManager.HeadingUpdate.heading.subscribe(
    onNext:{
        // series of events will be delivered during subscription
        print("Current heading is \($0)")
    },
    onCompleted:{
        // no complete event
    },
    onError:{
        // in case errors    
    }
)
.addDisposableTo(disposeBag)
#endif

配置

在开始订阅航向之前,您还可以通过以下链式风格API配置航向更新服务实例

#if os(iOS)
RxLocationManager.HeadingUpdate.headingFilter(degrees:CLLocationDegrees) -> HeadingUpdateService
RxLocationManager.HeadingUpdate.headingOrientation(degrees:CLDeviceOrientation) -> HeadingUpdateService
RxLocationManager.HeadingUpdate.displayHeadingCalibration(should:Bool) -> HeadingUpdateService

//Use following to methods to start/stop location updating, so that true heading value will be reported
RxLocationManager.HeadingUpdate.startTrueHeading(withParams:(distanceFilter:CLLocationDistance, desiredAccuracy:CLLocationAccuracy))
RxLocationManager.HeadingUpdate.stopTrueHeading()
#endif

如果存在,则关闭航向校准显示

#if os(iOS)
RxLocationManager.HeadingUpdate.dismissHeadingCalibrationDisplay() 
#endif

多个航向更新服务

在某些情况下,您需要您的应用中不止一个航向更新服务,并且它们的配置不同,您可以通过从共享进行克隆来创建一个新的服务

var anotherHeadingUpdateService = RxLocationManager.HeadingUpdate.clone()
anotherHeadingUpdateService.distanceFilter(100).desiredAccuracy(50)

区域监控服务

观察当前监控区域集合的变化

#if os(iOS) || os(OSX)
// methods to start|stop monitoring regions
RxLocationManager.RegionMonitoring.startMonitoringForRegions(regions: [CLRegion]) -> RegionMonitoringService
RxLocationManager.RegionMonitoring.stopMonitoringForRegions(regions: [CLRegion]) -> RegionMonitoringService
RxLocationManager.RegionMonitoring.stopMonitoringForAllRegions() -> RegionMonitoringService

RxLocationManager.RegionMonitoring.monitoredRegions.subscribe(
    onNext:{
        //happens no matter when new region is added or existing one gets removed from the monitored regions set
        regions in
        print("Current monitoring \(regions.count) regions")
    }
)
.addDisposableTo(disposeBag)
#endif

观察区域进入/退出事件

#if os(iOS) || os(OSX)
RxLocationManager.RegionMonitoring.entering.subscribe(
    onNext:{
        region in
        print("Device is entering the region: \(region.identifier)")
    }
)    
.addDisposableTo(disposeBag)

RxLocationManager.RegionMonitoring.exiting.subscribe(
    onNext:{
        region in
        print("Device is leaving the region: \(region.identifier)")
    }
)   
.addDisposableTo(disposeBag)
#endif

请求监控区域的状态

RxLocationManager.RegionMonitoring.requestRegionsState(regions:[CLRegion]) -> RegionMonitoringService
RxLocationManager.RegionMonitoring.determinedRegionState.subscribe(
    onNext:{
        region, state in
        print("the region: \(region.identifier) is in state: \(state.rawValue)")
    }
)
.addDisposableTo(disposeBag)

启动/停止范围内测距信标

#if os(iOS)
RxLocationManager.RegionMonitoring.startRangingBeaconsInRegion(region: CLBeaconRegion)
RxLocationManager.RegionMonitoring.stopRangingBeaconsInRegion(region: CLBeaconRegion)
#endif

观察测距信标

#if os(iOS)
RxLocationManager.RegionMonitoring.ranging.subscribe(
    onNext:{
        beacons, inRegion in
        print("\(beacons.count) beacons ranged in range:\(inRange.identifier)")
    }
)    
.addDisposableTo(disposeBag)
#endif

访问监控服务

启动/停止访问监控

#if os(iOS)
RxLocationManager.VisitMonitoring.startMonitoringVisits()
RxLocationManager.VisitMonitoring.stopMonitoringVisits()
#endif

观察访问事件

#if os(iOS)
RxLocationManager.VisitMonitoring.visiting.subscribe(
    onNext:{
        visit in
        print("coordinate: \(visit.coordinate.longitude),\(visit.coordinate.latitude)")
    }
)    
.addDisposableTo(disposeBag)
#endif

MIT许可证