瀏覽代碼

Merge pull request #1216 from deltachat/registering_background_task

further hacks around 0xdead10cc
bjoern 4 年之前
父節點
當前提交
75f8f9e377
共有 2 個文件被更改,包括 58 次插入35 次删除
  1. 14 1
      deltachat-ios/AppDelegate.swift
  2. 44 34
      deltachat-ios/Helper/NotificationManager.swift

+ 14 - 1
deltachat-ios/AppDelegate.swift

@@ -371,6 +371,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         }
         }
         bgIoTimestamp = nowTimestamp
         bgIoTimestamp = nowTimestamp
 
 
+        // make sure to balance each call to `beginBackgroundTask` with `endBackgroundTask`
+        let backgroundTask = UIApplication.shared.beginBackgroundTask {
+            // TODO: currently, this should be okay, we are not using too much background time,
+            // so that handler should never be called.
+            // the plan is to listen to an event as DC_EVENT_ENTER_IDLE and stop fetch from there.
+            // if we have such an event, we could imprive this handler and fire the event.
+            logger.info("fetch background task will end soon")
+        }
+
         // we're in background, run IO for a little time
         // we're in background, run IO for a little time
         dcContext.maybeStartIo()
         dcContext.maybeStartIo()
         dcContext.maybeNetwork()
         dcContext.maybeNetwork()
@@ -388,9 +397,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
 
             // to avoid 0xdead10cc exceptions, scheduled jobs need to be done before we get suspended;
             // to avoid 0xdead10cc exceptions, scheduled jobs need to be done before we get suspended;
             // we increase the probabilty that this happens by waiting a moment before calling completionHandler()
             // we increase the probabilty that this happens by waiting a moment before calling completionHandler()
-            DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
+            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                 logger.info("⬅️ fetch done")
                 logger.info("⬅️ fetch done")
                 completionHandler(.newData)
                 completionHandler(.newData)
+
+                // this line should always be reached after a background task is started
+                // and balances the call to `beginBackgroundTask` above.
+                UIApplication.shared.endBackgroundTask(backgroundTask)
             }
             }
         }
         }
     }
     }

+ 44 - 34
deltachat-ios/Helper/NotificationManager.swift

@@ -8,6 +8,7 @@ public class NotificationManager {
     var incomingMsgObserver: NSObjectProtocol?
     var incomingMsgObserver: NSObjectProtocol?
     var msgsNoticedObserver: NSObjectProtocol?
     var msgsNoticedObserver: NSObjectProtocol?
 
 
+
     init() {
     init() {
         initIncomingMsgsObserver()
         initIncomingMsgsObserver()
         initMsgsNoticedObserver()
         initMsgsNoticedObserver()
@@ -43,6 +44,13 @@ public class NotificationManager {
             forName: dcNotificationIncoming,
             forName: dcNotificationIncoming,
             object: nil, queue: OperationQueue.main
             object: nil, queue: OperationQueue.main
         ) { notification in
         ) { notification in
+            // make sure to balance each call to `beginBackgroundTask` with `endBackgroundTask`
+            let backgroundTask = UIApplication.shared.beginBackgroundTask {
+                // we cannot easily stop the task,
+                // however, this handler should not be called as adding the notification should not take 30 seconds.
+                logger.info("notification background task will end soon")
+            }
+
             DispatchQueue.global(qos: .background).async {
             DispatchQueue.global(qos: .background).async {
                 if let ui = notification.userInfo,
                 if let ui = notification.userInfo,
                    let chatId = ui["chat_id"] as? Int,
                    let chatId = ui["chat_id"] as? Int,
@@ -52,45 +60,47 @@ public class NotificationManager {
                     NotificationManager.updateApplicationIconBadge(reset: false)
                     NotificationManager.updateApplicationIconBadge(reset: false)
 
 
                     let chat = DcContext.shared.getChat(chatId: chatId)
                     let chat = DcContext.shared.getChat(chatId: chatId)
-                    if chat.isMuted {
-                        return
-                    }
+                    if !chat.isMuted {
+                        let content = UNMutableNotificationContent()
+                        let msg = DcMsg(id: messageId)
+                        content.title = chat.isGroup ? chat.name : msg.getSenderName(msg.fromContact)
+                        content.body =  msg.summary(chars: 80) ?? ""
+                        content.subtitle = chat.isGroup ?  msg.getSenderName(msg.fromContact) : ""
+                        content.userInfo = ui
+                        content.sound = .default
 
 
-                    let content = UNMutableNotificationContent()
-                    let msg = DcMsg(id: messageId)
-                    content.title = chat.isGroup ? chat.name : msg.getSenderName(msg.fromContact)
-                    content.body =  msg.summary(chars: 80) ?? ""
-                    content.subtitle = chat.isGroup ?  msg.getSenderName(msg.fromContact) : ""
-                    content.userInfo = ui
-                    content.sound = .default
-
-                    if msg.type == DC_MSG_IMAGE || msg.type == DC_MSG_GIF,
-                       let url = msg.fileURL {
-                        do {
-                            // make a copy of the file first since UNNotificationAttachment will move attached files into the attachment data store
-                            // so that they can be accessed by all of the appropriate processes
-                            let tempUrl = url.deletingLastPathComponent()
-                                .appendingPathComponent("notification_tmp")
-                                .appendingPathExtension(url.pathExtension)
-                            try FileManager.default.copyItem(at: url, to: tempUrl)
-                            if let attachment = try? UNNotificationAttachment(identifier: Constants.notificationIdentifier, url: tempUrl, options: nil) {
-                                content.attachments = [attachment]
+                        if msg.type == DC_MSG_IMAGE || msg.type == DC_MSG_GIF,
+                           let url = msg.fileURL {
+                            do {
+                                // make a copy of the file first since UNNotificationAttachment will move attached files into the attachment data store
+                                // so that they can be accessed by all of the appropriate processes
+                                let tempUrl = url.deletingLastPathComponent()
+                                    .appendingPathComponent("notification_tmp")
+                                    .appendingPathExtension(url.pathExtension)
+                                try FileManager.default.copyItem(at: url, to: tempUrl)
+                                if let attachment = try? UNNotificationAttachment(identifier: Constants.notificationIdentifier, url: tempUrl, options: nil) {
+                                    content.attachments = [attachment]
+                                }
+                            } catch let error {
+                                logger.error("Failed to copy file \(url) for notification preview generation: \(error)")
                             }
                             }
-                        } catch let error {
-                            logger.error("Failed to copy file \(url) for notification preview generation: \(error)")
                         }
                         }
+                        let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.1, repeats: false)
+                        let accountEmail = DcContact(id: Int(DC_CONTACT_ID_SELF)).email
+                        if #available(iOS 12.0, *) {
+                            content.threadIdentifier = "\(accountEmail)\(chatId)"
+                        }
+                        let request = UNNotificationRequest(identifier: "\(Constants.notificationIdentifier).\(accountEmail).\(chatId).\(msg.messageId)",
+                                                            content: content,
+                                                            trigger: trigger)
+                        UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
+                        logger.info("notifications: added \(content.title) \(content.body) \(content.userInfo)")
                     }
                     }
-                    let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.1, repeats: false)
-                    let accountEmail = DcContact(id: Int(DC_CONTACT_ID_SELF)).email
-                    if #available(iOS 12.0, *) {
-                        content.threadIdentifier = "\(accountEmail)\(chatId)"
-                    }
-                    let request = UNNotificationRequest(identifier: "\(Constants.notificationIdentifier).\(accountEmail).\(chatId).\(msg.messageId)",
-                                                        content: content,
-                                                        trigger: trigger)
-                    UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
-                    logger.info("notifications: added \(content.title) \(content.body) \(content.userInfo)")
                 }
                 }
+
+                // this line should always be reached
+                // and balances the call to `beginBackgroundTask` above.
+                UIApplication.shared.endBackgroundTask(backgroundTask)
             }
             }
         }
         }
     }
     }