После реализации фоновых обновлений местоположения FCM сошел с ума и отправляется непрерывно без запрограммированного триггера. - PullRequest
0 голосов
/ 23 мая 2019

Я создаю простое приложение для чата с использованием 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 обновляется с текущим местоположением уведомление ,, триггер: >> уведомление ,, триггер: >>

и т. Д. *

1 Ответ

0 голосов
/ 29 мая 2019

Проблема полностью в облачных функциях Firebase и не имеет никакого отношения к службам CoreLocation

...