title: iOS swift notficiation after download finishes using URLSession
body: <p>I am downloading a long file using URLSession and after the download is finished i am trying to show a notification to the user to let him know that the download is completed. </p>
  
  <p>Notification works perfectly when the app is running. But not working when the app goes background. When the app comes to foreground again then the notification code starts running. </p>
  
  <p><strong>My codes:</strong></p>
  
  <pre><code>import Foundation
  import Zip
  import UserNotifications
  
  class DownloadManager : NSObject, URLSessionDelegate, URLSessionDownloadDelegate {
  
      static var shared = DownloadManager()
      var selectedBook: Book!
  
      typealias ProgressHandler = (Float, Float, Float) -&gt; ()
  
      var onProgress : ProgressHandler? {
          didSet {
              if onProgress != nil {
                  let _ = activate()
              }
          }
      }
  
      override private init() {
          super.init()
      }
  
      func activate() -&gt; URLSession {
          let config = URLSessionConfiguration.background(withIdentifier: "\(Bundle.main.bundleIdentifier!).background")
  
          // Warning: If an URLSession still exists from a previous download, it doesn't create a new URLSession object but returns the existing one with the old delegate object attached!
          return URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue())
      }
  
      private func calculateProgress(session : URLSession, completionHandler : @escaping (Float, Float, Float) -&gt; ()) {
          session.getTasksWithCompletionHandler { (tasks, uploads, downloads) in
              let progress = downloads.map({ (task) -&gt; Float in
                  if task.countOfBytesExpectedToReceive &gt; 0 {
                      return Float(task.countOfBytesReceived) / Float(task.countOfBytesExpectedToReceive)
                  } else {
                      return 0.0
                  }
              })
              let countOfBytesReceived = downloads.map({ (task) -&gt; Float in
                  return Float(task.countOfBytesReceived)
              })
              let countOfBytesExpectedToReceive = downloads.map({ (task) -&gt; Float in
                  return Float(task.countOfBytesExpectedToReceive)
              })
              if progress.reduce(0.0, +) == 1.0 {
                  self.postNotification()
              }
              completionHandler(progress.reduce(0.0, +), countOfBytesReceived.reduce(0.0, +), countOfBytesExpectedToReceive.reduce(0.0, +))
          }
      }
  
      func postUnzipProgress(progress: Double) {
          NotificationCenter.default.post(name: .UnzipProgress, object: progress)
      }
  
      func postNotification() {
          let center = UNUserNotificationCenter.current()
          center.requestAuthorization(options: [.alert, .sound]) { (granted, error) in
              // Enable or disable features based on authorization.
          }
  
          let content = UNMutableNotificationContent()
          content.title = NSString.localizedUserNotificationString(forKey: "Download Completed", arguments: nil)
          content.body = NSString.localizedUserNotificationString(forKey: "Quran Touch app is ready to use", arguments: nil)
          content.sound = UNNotificationSound.default()
          content.categoryIdentifier = "com.qurantouch.qurantouch"
          // Deliver the notification in 60 seconds.
          let trigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 2.0, repeats: false)
          let request = UNNotificationRequest.init(identifier: "downloadCompleted", content: content, trigger: trigger)
  
          // Schedule the notification.
          center.add(request)
      }
  
      func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
  
          if totalBytesExpectedToWrite &gt; 0 {
              if let onProgress = onProgress {
                  calculateProgress(session: session, completionHandler: onProgress)
              }
              let progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)
              debugPrint("Progress \(downloadTask) \(progress)")
  
          }
      }
  
      func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
          debugPrint("Download finished: \(location)")
  
          let folder = URL.createFolder(folderName: selectedBook.folder)
          let fileURL = folder!.appendingPathComponent("ClipsAndTacksF1ForModeler.zip")
  
          if let url = URL.getFolderUrl(folderName: selectedBook.folder) {
              do {
                  try FileManager.default.moveItem(at: location, to: fileURL)
                  try Zip.unzipFile((fileURL), destination: url, overwrite: true, password: nil, progress: { (progress) -&gt; () in
                      self.postUnzipProgress(progress: progress)
                      if progress == 1 {
  //                        self.postNotification()
                          UserDefaults.standard.set("selected", forKey: self.selectedBook.fileKey)
                          URL.removeFile(file: fileURL)
                      }
                  }, fileOutputHandler: {(outputUrl) -&gt; () in
                  })
              } catch {
                  print(error)
              }
          }
      }
  
      func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
          debugPrint("Task completed: \(task), error: \(error)")
      }
  
  }
  </code></pre>
  
  <p><strong>And started the download here</strong></p>
  
  <pre><code>func downloadBookWithUrl(url: String) {
          DownloadManager.shared.selectedBook = selectedBook
          let url = URL(string: url)!
          let task = DownloadManager.shared.activate().downloadTask(with: url)
          task.resume()        
      }
  </code></pre>
  
  <p>I got an example from apple that is written in Objective C. But couldn't get through it as i don't know Objective C.
  Here is the example: <a href="https://developer.apple.com/library/archive/samplecode/SimpleBackgroundTransfer/Introduction/Intro.html#//apple_ref/doc/uid/DTS40013416" rel="nofollow noreferrer">https://developer.apple.com/library/archive/samplecode/SimpleBackgroundTransfer/Introduction/Intro.html#//apple_ref/doc/uid/DTS40013416</a></p>