1

내 app이 백그라운드 처리되거나 일시 중단 될 때 호출되는 기본 func을 여기 구현하려고합니다.URLSession 및 배경 가져 오기 firebase를 사용하여 원격 알림과 함께 가져 오기

사실 우리는 하루에 약 5 일 보내려고합니다. 그래서 애플이 우리의 사용률을 낮춰서는 안됩니다.

저는 firebase와 userNotifications를 사용하는 다음을 작성했습니다. 지금은 내 응용 프로그램 대리인입니다. 앱이 포 그라운드에있을 때

는 :

  1. 내가

  2. "startDownload FUNC에서"로그를 얻을 나는 로그를 얻을 다음과 같이

    import Firebase 
    import FirebaseMessaging 
    import UserNotifications 
    
    @UIApplicationMain 
    class AppDelegate: UIResponder, UIApplicationDelegate { 
    
        var window: UIWindow? 
        var backgroundSessionCompletionHandler: (() -> Void)? 
    
    
        lazy var downloadsSession: Foundation.URLSession = { 
         let configuration = URLSessionConfiguration.background(withIdentifier: "bgSessionConfiguration") 
         configuration.timeoutIntervalForRequest = 30.0 
         let session = Foundation.URLSession(configuration: configuration, delegate: self, delegateQueue: nil) 
         return session 
        }() 
    
    
    
        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 
         // Override point for customization after application launch. 
         FIRApp.configure() 
         if #available(iOS 10.0, *) { 
          let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] 
          UNUserNotificationCenter.current().requestAuthorization(
           options: authOptions, 
           completionHandler: {_, _ in }) 
    
          // For iOS 10 display notification (sent via APNS) 
          UNUserNotificationCenter.current().delegate = self 
          // For iOS 10 data message (sent via FCM) 
          FIRMessaging.messaging().remoteMessageDelegate = self 
    
         } else { 
          let settings: UIUserNotificationSettings = 
           UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil) 
          application.registerUserNotificationSettings(settings) 
         } 
    
         application.registerForRemoteNotifications() 
         let token = FIRInstanceID.instanceID().token()! 
         print("token is \(token) < ") 
    
         return true 
        } 
    
    
    
        func application(_ application: UIApplication, handleEventsForBackgroundURLSession identifier: String, completionHandler: @escaping() -> Void){ 
          print("in handleEventsForBackgroundURLSession") 
          _ = self.downloadsSession 
          self.backgroundSessionCompletionHandler = completionHandler 
        } 
    
        //MARK: SyncFunc 
    
        func startDownload() { 
         NSLog("in startDownload func") 
    
         let todoEndpoint: String = "https://jsonplaceholder.typicode.com/todos/1" 
         guard let url = URL(string: todoEndpoint) else { 
          print("Error: cannot create URL") 
          return 
         } 
    
         // make the request 
         let task = downloadsSession.downloadTask(with: url) 
         task.resume() 
         NSLog(" ") 
         NSLog(" ") 
    
        } 
    
        func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession){ 
         DispatchQueue.main.async(execute: { 
          self.backgroundSessionCompletionHandler?() 
          self.backgroundSessionCompletionHandler = nil 
         }) 
        } 
    
        func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { 
    
         NSLog("in didReceiveRemoteNotification") 
         NSLog("%@", userInfo) 
         startDownload() 
    
         DispatchQueue.main.async { 
          completionHandler(UIBackgroundFetchResult.newData) 
         } 
        } 
    
    } 
    
    @available(iOS 10, *) 
    extension AppDelegate : UNUserNotificationCenterDelegate { 
    
        // Receive displayed notifications for iOS 10 devices. 
        /* 
        func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { 
         let userInfo = notification.request.content.userInfo 
         // Print message ID. 
         //print("Message ID: \(userInfo["gcm.message_id"]!)") 
    
         // Print full message. 
         print("%@", userInfo) 
         startDownload() 
    
          DispatchQueue.main.async { 
           completionHandler(UNNotificationPresentationOptions.alert) 
          }   
        } 
        */ 
    } 
    
    extension AppDelegate : FIRMessagingDelegate { 
        // Receive data message on iOS 10 devices. 
        func applicationReceivedRemoteMessage(_ remoteMessage: FIRMessagingRemoteMessage) { 
         print("%@", remoteMessage.appData) 
        } 
    } 
    
    extension AppDelegate: URLSessionDownloadDelegate { 
        func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL){ 
         NSLog("finished downloading") 
        } 
    } 
    

    결과

    은 "다운로드 완료".

앱이 배경에

:

  1. 나는

  2. 내가 "다운로드가 완료"로그를하지 않는다 "startDownload FUNC에서"로그를 얻을.

  3. 소음기가 작동하지 않습니다. 즉, 앱이 배경 화면으로 설정되어있을 때 트레이에서 알림을 받고 있습니다. 내가 요청을 보내는 우편 배달부를 사용하여 콘솔 오류 'FIRMessaging receiving notification in invalid state 2' 결과 다음과 같은 페이로드를 시도하고

:

{ 
    "to" : "Server_Key", 
    "content_available" : true, 
    "notification": { 
    "body": "Firebase Cloud Message29- BG CA1" 
    } 
} 

나는 배경에 대해 설정 한 기능 가져 오기 및 원격 통지를합니다. 응용 프로그램은 빠른 3 작성 및 최신 중포 기지

편집 사용합니다 : 코멘트에 따라

+0

당신의 코드가 있습니다 말이되지 않는다. 백그라운드 다운로드를 구성하고 있는데,'application (_ : handleEventsForBackgroundURLSession 식별자 : completionHandler :)'및'urlSessionDidFinishEvents (forBackgroundURLSession :)'의 구현은 어디에 있습니까? 앱 위임 코드의 절반을 버렸습니까? 아니면 가장 중요한 부분을 작성하는 것을 잊었습니까? :) – matt

+0

@matt 가장 중요한 부분을 버렸습니다! : 0 didFinishDownloadingTo은 완료시 호출되는 메소드이고 거기에있는 코드는 완료 핸들러가 될 것이라고 생각했습니다. 내 앱 대리인의 확장 프로그램에 이러한 기능을 넣을 수 있습니까 : URLSessionDownloadDelegate? 나는 이것을 함께 조각하는 방법에 대해 약간 혼란 스럽다. 또한이 완성 처리기가 위의 코드에서 "완료된 다운로드"인쇄물을 볼 것으로 예상되는 코드를 실행 한 후입니까? – user2363025

+0

@matt 처음에는 작업 정의의 일부로 완료 핸들러를 가지고 있었지만 이것을 실행하면 completionHandlers가 백그라운드 모드에서 허용되지 않고 대신 델리게이트를 사용할 수 없다는 오류가 콘솔에 나타났습니다 – user2363025

답변

2

몇 가지 관찰을 funcs를 포함 AppDelegate에 업데이트를 :

앱이 handleEventsForBackgroundURLSessionIdentifier에 의해 다시 시작
  1. , 당신 완료 핸들러를 저장해야 할뿐만 아니라 실제로 세션을 시작해야합니다. 당신은 전자를하는 것처럼 보이지만 전자는하지 않는 것처럼 보입니다.

    또한 urlSessionDidFinishEvents(forBackgroundURLSession:)을 구현하고 저장된 완성 처리기를 호출하고 참조를 삭제해야합니다.

  2. 데이터 작업을 수행하는 것처럼 보입니다. 하지만 백그라운드 작업을 원한다면 작업을 다운로드하거나 업로드해야합니다. [편집 한 질문을 다운로드 작업으로 만들었습니다.]

  3. userNotificationCenter(_:willPresent:completionHandler:)에서이 메서드에 전달 된 완료 처리기를 호출하지 마십시오. 따라서 30 초 (또는 무엇이든간에)가 만료되었으므로 호출하지 않았기 때문에 앱이 일시적으로 종료되고 모든 백그라운드 요청이 취소됩니다.

    따라서 willPresent은 요청 시작과 동시에 완료 핸들러를 호출해야합니다. 이 완료 핸들러 (알림 처리 완료)와 나중에 제공되는 별도 완료 핸들러 (백그라운드 URLSession 이벤트 처리 완료)를 urlSessionDidFinishEvents과 혼동하지 마십시오.

  4. 저장 한 백그라운드 세션 완료 핸들러가 올바르지 않습니다. 당신이 그것을 저장할 때

    var backgroundSessionCompletionHandler: (() -> Void)? 
    

    , 그것이 : 나는 좋을 것

    backgroundSessionCompletionHandler = completionHandler // note, no() 
    

    그리고 당신은 urlSessionDidFinishEvents에서 그것을 호출 할 때, 그것은이다

    DispatchQueue.main.async { 
        self.backgroundSessionCompletionHandler?() 
        self.backgroundSessionCompletionHandler = nil 
    } 
    
+0

응답 해 주셔서 감사합니다! 실수를 수정하고 다운로드 할 데이터를 변경했으며, 완성 처리자라고도 부르는 것으로 추가했습니다. 편집 된 질문보기, 세션을 시작하는 방법은 확실하지 않습니까? startDownload func에 task.resume()이 포함되었습니다. – user2363025

+0

urlSessionDidFinishEvents에 추가 한 다음 완료 처리기를 다시 호출하려고했는데 여기 및 UserNotificationCenter에서 호출해야합니까? – user2363025

+0

설명해 주셔서 감사 합니다만, 아직 사용자 시작 완료 핸들러에 무엇이 있어야하는지 잘 모르겠습니다. 실제로 startDownload func 이후에 호출해야하는지 확실하지 않습니다. – user2363025