Отправка писем с помощью SMTP Mailcore2 в фоновом режиме, пока приложение работает - PullRequest
0 голосов
/ 15 мая 2019

Я пишу приложение для iOS, которое должно отправлять регулярные обновления в фоновом режиме после того, как пользователь добавляет новые данные (Barcoder Scanner, scancodes). Я не могу найти способы отправки почты в фоновом режиме через SMTP и mailcore2 без проблем и ограничений.

Я уже пробовал это с:

  1. Пробовал с фоновой выборкой https://developer.apple.com/documentation/uikit/core_app/managing_your_app_s_life_cycle/preparing_your_app_to_run_in_the_background/updating_your_app_with_background_app_refresh Но это очень нерегулярно, и требуется некоторое время, чтобы сработало.

  2. В AppDelegate.swift:

func applicationDidEnterBackground(_ application: UIApplication) {
        BackgroundTask.run(application: application) { [...] }
}

Но тогда данные отправляются только в том случае, если я закрываю / минимизирую приложение и если BackgroundTask не завершается, приложение зависает, и я получаю эту ошибку: соединение XPC прервано Я также сталкиваюсь с проблемами, потому что мне нужно дождаться возвращения sendOperation, но, поскольку это асинхронный режим, я создаю обходной путь, чтобы поддерживать работу потока и впоследствии обрабатывать мое «если все еще будет ...». Подробнее в полном коде:

typealias CompletionHandler = (Error?) -> Void

/// Provides syncronous access to results returned by
/// asynchronous processes with completion handlers
class SyncMaker {
    var result: Error? = nil

    /// Generates a synchronous-compliant completion handler
    func completion() -> CompletionHandler{
        return {
            (error: Error?) in

            // Store result, return control
            self.result = error
            CFRunLoopStop(CFRunLoopGetCurrent())
        }
    }

    // Perform task (that must use custom completion handler) and wait
    func run(_ task: @escaping () -> Void) -> Error? {
        task()
        CFRunLoopRun()
        return result
    }
}

func applicationDidEnterBackground(_ application: UIApplication) {
        BackgroundTask.run(application: application) { backgroundTask in
            if (scanManager.hasDataToSend()) {
                let smtpSession = MCOSMTPSession()
                let settings: Settings = scanManager.getSettings()
                smtpSession.hostname = settings.credMailServer
                smtpSession.username = settings.credMailSource
                print(settings.credMailSource)
                smtpSession.password = settings.credMailPassword
                smtpSession.port = UInt32(settings.credMailPort)
                […] Setting auth and connection typ
                smtpSession.isCheckCertificateEnabled = false
                smtpSession.timeout = 100
                smtpSession.connectionLogger = {(connectionID, type, data) in
                    if data != nil {
                        if let string = NSString(data: data!, encoding: String.Encoding.utf8.rawValue){
                            NSLog("Connectionlogger: \(string)")
                        }
                    }
                }

                let builder = MCOMessageBuilder()
                builder.header.to = [MCOAddress(displayName: settings.credMailDest, mailbox: settings.credMailDest)!]
                builder.header.from = MCOAddress(displayName: settings.credMailSource, mailbox: settings.credMailSource)
                builder.header.subject = "ScanLMS"
                builder.htmlBody = ""

                guard let attachment = MCOAttachment(data: scanManager.getSendData().data(using: .ascii), filename: "scans.txt") else {
                    print("Cant init attachment!")
                    backgroundTask.end()
                    return
                }
                attachment.mimeType =  "text/plain"
                builder.addAttachment(attachment)

                let rfc822Data = builder.data()
                let sendOperation = smtpSession.sendOperation(with: rfc822Data!)
                var sendingError: Bool = true

                print("Trying to send mail...")
                if (sendOperation != nil) {
                    print("Starting sendOperation...")
                    let syncMaker = SyncMaker() //full class on top of code
                    let result = syncMaker.run {
                        sendOperation?.start(
                            syncMaker.completion())
                    }
                    if (result != nil) {
                        print("Error sending email: \(result!)")
                    } else {
                        sendingError = false
                        print("Successfully sent email!")
                    }
                } else {
                    print("Cant init sendOperation")
                    sendingError = true
                }
                if (sendingError) {
                    print("Error, returning")
                } else {
                    print("Send done")
                    print("Updating scanManager with send data...")
                    scanManager.updateSendData()
                    print("Done, returning")
                }
            } else {
                print("No new send data")
            }
            backgroundTask.end()
        }
    }

1 Ответ

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

Я уменьшил smtpSession.timeout = 100 до 3 (секунд), и теперь он больше не блокирует пользовательский интерфейс. Больше взломать, чем решение, но оно работает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...