iOS应用被杀时进入监控区域触发本地通知实现咨询
iOS 地理围栏本地通知实现(支持应用被杀状态触发)
需求说明
- 用户到达本地存储的附近目的地时,发送iOS本地通知
- 在
CLLocationManager代理的didEnterRegion方法中触发通知 - 应用被杀死状态下仍能触发通知
- 应用被杀时,监控用户最后位置附近的20个区域
- 用户进入监控区域时自动触发本地通知
核心实现代码
首先定义必要的属性与初始化配置:
import CoreLocation import UserNotifications class LocationMonitor: NSObject, CLLocationManagerDelegate, UNUserNotificationCenterDelegate { private let locationManager = CLLocationManager() private var regions: [CLCircularRegion] = [] private var monitoredRegions: Set<CLCircularRegion> = [] private var lastLocation: CLLocation? override init() { super.init() setupLocationManager() setupNotificationPermission() } private func setupLocationManager() { locationManager.delegate = self // 申请Always权限,后台/被杀状态监控必须用该权限 locationManager.requestAlwaysAuthorization() locationManager.allowsBackgroundLocationUpdates = true locationManager.pausesLocationUpdatesAutomatically = false } private func setupNotificationPermission() { UNUserNotificationCenter.current().delegate = self UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { granted, error in if let error = error { print("通知权限申请失败:\(error.localizedDescription)") } } }
生成用户当前位置周边的随机区域:
func generateSurroundingRegions(currentLocation: CLLocation) { regions.removeAll() for i in 1...100 { // 生成随机角度(0-360度)和距离(20-1020米) let angle = Double(arc4random_uniform(360)) * Double.pi / 180 let distance = Double(arc4random_uniform(1000) + 20) // 计算区域中心坐标 let newLatitude = currentLocation.coordinate.latitude + (distance / 111000) * cos(angle) let newLongitude = currentLocation.coordinate.longitude + (distance / (111000 * cos(currentLocation.coordinate.latitude * Double.pi / 180))) * sin(angle) let region = CLCircularRegion(center: CLLocationCoordinate2D(latitude: newLatitude, longitude: newLongitude), radius: 50, identifier: "Region\(i)") regions.append(region) } }
更新监控区域(保留最近的20个,符合iOS系统限制):
func updateMonitoredRegions(currentLocation: CLLocation) { // 按距离当前位置由近到远排序 let sortedRegions = regions.sorted { let location1 = CLLocation(latitude: $0.center.latitude, longitude: $0.center.longitude) let location2 = CLLocation(latitude: $1.center.latitude, longitude: $1.center.longitude) return currentLocation.distance(from: location1) < currentLocation.distance(from: location2) } let closestRegions = Array(sortedRegions.prefix(20)) let newMonitoredRegions = Set(closestRegions) // 停止监控不需要的区域 for region in monitoredRegions.subtracting(newMonitoredRegions) { locationManager.stopMonitoring(for: region) } // 启动新区域的监控 for region in newMonitoredRegions.subtracting(monitoredRegions) { region.notifyOnEntry = true region.notifyOnExit = false // 仅监听进入事件,可按需调整 locationManager.startMonitoring(for: region) } monitoredRegions = newMonitoredRegions }
位置更新时同步监控区域:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { guard let currentLocation = locations.last else { return } lastLocation = currentLocation generateSurroundingRegions(currentLocation: currentLocation) updateMonitoredRegions(currentLocation: currentLocation) }
进入区域时触发通知:
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) { sendLocalNotification(regionID: region.identifier) print("进入区域:\(region.identifier)") } private func sendLocalNotification(regionID: String) { let content = UNMutableNotificationContent() content.title = "到达目标区域" content.body = "你已进入区域:\(regionID)" content.sound = .default let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: nil) UNUserNotificationCenter.current().add(request) { error in if let error = error { print("通知发送失败:\(error.localizedDescription)") } } } }
关键注意事项
- 权限配置:必须申请
Always位置权限,WhenInUse权限无法支持应用被杀状态的监控。需在Info.plist中添加NSLocationAlwaysAndWhenInUseUsageDescription和NSLocationWhenInUseUsageDescription字段说明权限用途。 - 后台模式:在Xcode项目的
Signing & Capabilities中开启Background Modes,勾选Location updates选项。 - 系统限制:iOS单应用最多支持20个地理围栏监控,代码中取最近20个区域符合该限制。
- 被杀状态触发逻辑:应用被杀后,系统会接管地理围栏监控,用户进入区域时系统会唤醒应用(后台状态)并调用
didEnterRegion方法,从而触发通知。 - 坐标精度:代码中使用的坐标转换为近似计算,若需更高精度可借助
CoreLocation的专业坐标计算API。
内容的提问来源于stack exchange,提问作者Jay Pratap singh
相关产品推荐
相关产品推荐

