Я создаю простое приложение для чата с использованием Firebase. В моей базе данных есть узел для сообщений, и когда пользователь получает сообщение от другого пользователя, облачная функция отслеживает изменения и отправляет сообщение облачной базы Firebase на токен пользователя. UNUserNotificationCenterDelegate был правильно реализован в AppDelegate.
Все работало нормально, пока я не начал реализовывать фоновые обновления местоположения с помощью метода CoreLocation locationManager.startUpdatingLocation (). Я создаю экземпляр locationManager также в AppDelegate.
Мое приложение сохраняет текущее местоположение в UserDefaults (), затем обновляет местоположение, сравнивает его с сохраненным местоположением в UserDefaults и, если оно далеко от сохраненного местоположения или не было сохранено в базе данных в течение определенного периода времени, текущее местоположение сохраняется в базе данных Firebase и обновляется в UserDefaults ().
После запуска приложения я начал получать уведомления от Firebase (как на переднем, так и на заднем плане), которые являются последними 5-8 (затем до 58 за раз) сообщениями о том, что пользователь получил новое сообщение.
Я пытался понять, что вызывает эти FCM, но мог печатать только уведомление.description на консоль
Я пытался
func applicationDidBecomeActive (_ application: UIApplication) {
// Перезапускаем любые задачи, которые были приостановлены (или еще не запущены), когда приложение было неактивно. Если приложение ранее было в фоновом режиме, при необходимости обновите пользовательский интерфейс.
UNUserNotificationCenter.current (). RemoveAllPendingNotificationRequests ()
UNUserNotificationCenter.current (). RemoveAllDeliveredNotifications ()
}
но это не сработало
import UIKit
import Firebase
import UserNotifications
import GoogleMobileAds
import CoreLocation
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate {
var window: UIWindow?
lazy var locationManager: CLLocationManager = {
let locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.allowsBackgroundLocationUpdates = true
return locationManager
}()
var currentLocation: CLLocation?
var defaults = UserDefaults.standard
var geocoder = CLGeocoder()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
FirebaseApp.configure()
self.startLocationService()
locationManager.startUpdatingLocation()
self.registerForPushNotifications()
Messaging.messaging().delegate = self
return true
}
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
let dataDict:[String: String] = ["token": fcmToken]
NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict)
}
func applicationDidBecomeActive(_ application: UIApplication) {
UNUserNotificationCenter.current().removeAllPendingNotificationRequests( )
UNUserNotificationCenter.current().removeAllDeliveredNotifications()
}
func registerForPushNotifications() {
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.delegate = self
notificationCenter.requestAuthorization(options: [.alert, .sound, .badge]) {
(granted, error) in
guard granted else { return }
self.getNotificationSettings()
}
}
func getNotificationSettings() {
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
guard settings.authorizationStatus == .authorized else { return }
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let tokenParts = deviceToken.map { data -> String in
return String(format: "%02.2hhx", data)
}
print("Registered with device token \(tokenParts.joined())")
}
func application(_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Failed to register: \(error.localizedDescription)")
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
print("notification is \(notification.description)")
completionHandler([.sound])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
print("Received notification \(response.notification)")
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
if application.applicationState == .active {
application.applicationIconBadgeNumber = 0
} else {
let numberOfUnreadMessages = userInfo["count"] as! String
if let badgeNumber = Int(numberOfUnreadMessages) {
application.applicationIconBadgeNumber = badgeNumber
}
completionHandler(UIBackgroundFetchResult.newData)
}
}
}
extension AppDelegate: CLLocationManagerDelegate {
func startLocationService() {
print("Starting location services in AppDelegate")
if CLLocationManager.authorizationStatus() == .authorizedAlways || CLLocationManager.authorizationStatus() == .authorizedWhenInUse {
activateLocationServices()
} else {
locationManager.requestAlwaysAuthorization()
}
}
private func activateLocationServices() {
if UIApplication.shared.applicationState == .active {
locationManager.startUpdatingLocation()
} else {
locationManager.startMonitoringSignificantLocationChanges()
}
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedAlways || status == .authorizedWhenInUse {
activateLocationServices()
} else {
print("CLAuthorizationStatus is notDetermined")
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("error happened while getting current location: \(error.localizedDescription)")
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
currentLocation = locations.first
print("AppDelegate got location")
if defaults.value(forKey: "currentLatitude") == nil {
let currentLatitude = currentLocation?.coordinate.latitude
let currentLongtitude = currentLocation?.coordinate.longitude
let currentAltitude = currentLocation?.altitude
let timeStamp: Double = Double(Int(NSDate().timeIntervalSince1970))
defaults.set(currentLatitude, forKey: "currentLatitude")
defaults.set(currentLongtitude, forKey: "currentLongtitude")
defaults.set(currentAltitude, forKey: "currentAltitude")
defaults.set(timeStamp, forKey: "locationUpdated")
print("UserDefaults updated with current location")
}
saveLocationToDatabase()
}
func saveLocationToDatabase() {
var previousLocation: CLLocation?
var previuosTime: Double?
guard let currentLocation = currentLocation, let currentUserUid = defaults.string(forKey: "uid") else { return }
let previousLatitude = defaults.double(forKey: "currentLatitude")
let previousLongtitude = defaults.double(forKey: "currentLongtitude")
previuosTime = defaults.double(forKey: "locationUpdated")
previousLocation = CLLocation(latitude: previousLatitude, longitude: previousLongtitude)
let timeStamp: Double = Double(Int(NSDate().timeIntervalSince1970))
if previousLocation != nil && previuosTime != nil {
let distance = currentLocation.distance(from: previousLocation!)
let time = timeStamp - previuosTime!
if distance < 100 && time < 60 {
print("distance is \(distance), time is \(time)")
print("No need to save location")
return
} else {
self.saveChangesToDatabase()
}
} else {
self.saveChangesToDatabase()
}
}
func saveChangesToDatabase() {
guard let currentLocation = currentLocation, let currentUserUid = defaults.string(forKey: "uid") else { return }
let usersRef = Database.database().reference().child("users").child(currentUserUid)
usersRef.child("location").child("latitude").setValue(currentLocation.coordinate.latitude)
usersRef.child("location").child("longtitude").setValue(currentLocation.coordinate.longitude)
usersRef.child("location").child("altitude").setValue(currentLocation.altitude)
let timeToSet: NSNumber = NSNumber(value: Int(NSDate().timeIntervalSince1970))
usersRef.child("location").child("updated").setValue(timeToSet)
print("Location saved to database")
defaults.set(currentLocation.coordinate.latitude, forKey: "currentLatitude")
defaults.set(currentLocation.coordinate.longitude, forKey: "currentLongtitude")
defaults.set(currentLocation.altitude, forKey: "currentAltitude")
defaults.set(timeToSet, forKey: "locationUpdated")
print("UserDefaults updated with current location")
self.geocoder.reverseGeocodeLocation(currentLocation) { (placemarks, error) in
if let error = error {
print(error.localizedDescription)
return
}
guard let placemark = placemarks?.first else { return }
if let city = placemark.locality, let state = placemark.administrativeArea {
let currentPlace = "\(city), \(state)"
usersRef.child("location").child("currentPlace").setValue(currentPlace)
}
}
}
}
Моя консоль:
AppDelegate получил местоположение
расстояние 0.00017503746557926585, время 58.0
Нет необходимости сохранять местоположение
AppDelegate получил местоположение
Местоположение сохранено в базе данных
UserDefaults обновляется с текущим местоположением
уведомление ,, триггер: >>
уведомление ,, триггер: >>
и т. Д. *