web-dev-qa-db-ja.com

iOSアクション拡張機能のバックグラウンドタスク

ユーザー向けにデータを準備し、MailCore2を使用してこの情報をSMTPサーバーに送信するアプリのアクション拡張機能に取り組んでいます。データの準備は非常に高速ですが、メールの送信には時間がかかる場合があります(サイズによって異なります)。そのため、送信アクティビティをバックグラウンドで処理する方法を探しています。しかし、これにより、さまざまなソリューションでいくつかの問題が発生します。

  1. URLSessionを使用します。これは、iOS拡張機能で大きなアップロードまたはダウンロードを処理するための最初の方法です。ただし、問題は、MailCore2がURLSessionsを使用してデータをメールサーバーに送信しないことです。したがって、これは使用できません。または、この呼び出しをURLSessionで「ラップ」することは可能ですか?

  2. UNUserNotificationCenterを使用して、データの準備後に拡張機能からローカル通知を送信します。この通知を受け取った後、メインアプリで送信タスクを開始するというアイデアです。問題:通知userNotificationCenter didReceiveメソッドは、ユーザーが通知をクリックしたときにのみ呼び出されます。単純なバッジ通知は、デリゲートメソッドを呼び出しません。

  3. Background Fetchを使用します。これはシミュレーターでは正常に機能していますが、iOSデバイスではSMTPサーバーに接続するときにエラーが発生します。 github.com/MailCore/mailcore2/issues/252 で説明されているのと同じHELOの問題に遭遇しました。この問題の場合、解決策はMCOSMTPSession.isUseHeloIPEnabled = trueですが、これはすべてのサーバーで機能するとは限りません。したがって、完璧な解決策でもありません。

何かアイデア、そのようなタスクを処理する方法は?または、上記の解決策の1つに対処する方法は?

編集:この質問にはまだ回答がないため、不明な点や必要な追加情報は何ですか?

15
mixable

多くのテストと失敗の後で、拡張機能のバックグラウンドで長時間実行されるタスクを実行するための次の解決策を見つけました。これは、拡張がすでに終了している場合でも、期待どおりに機能します。

_func performTask()
{
    // Perform the task in background.
    let processinfo = ProcessInfo()
    processinfo.performExpiringActivity(withReason: "Long task") { (expired) in
        if (!expired) {
            // Run task synchronously.
            self.performLongTask()
        }
        else {
            // Cancel task.
            self.cancelLongTask()
        }
    }
}
_

このコードは ProcessInfo.performExpiringActivity() を使用して別のスレッドでタスクを実行します。 performLongTask()のタスクが同期的に実行されることが重要です。ブロックの終わりに達すると、スレッドは終了し、タスクの実行を終了します。

同様のアプローチがメインアプリでも機能しています。 iOSのバックグラウンドタスク の簡単な要約で詳細に説明されています。

0
mixable

あなたは拡張機能からバックグラウンドで長時間実行されているタスクをスケジュールすることができないようです。参照- ここ(一部のAPIはアプリ拡張機能で使用できません)

あなたが提案した解決策の中で、私の提案はサイレントプッシュ通知を使用してみることです、あなたは準備でAPIを呼び出すことができますデータステージでは、サーバーからサイレントプッシュを送信し、サイレントプッシュが到着したときにバックグラウンドタスクを実行します。

4
Tibin Thomas

あなたの反応から判断すると、あなたの困難はあなたがバックグラウンド活動を許可する必要があるということです。 このようなチュートリアルに従う でそれを行うことができます。

2
Francois Nadeau

最も便利な解決策は、プッシュ通知を使用することです。自分のアプリケーションで使用したソリューション:

  1. 単純な要求を取得できる単純なサーバーを作成します。デバイストークンと、デバイスをウェイクアップする時刻です。
  2. アプリケーションがバックグラウンドモードになったら、サーバーにリクエストを送信して、後でデバイスをウェイクアップします。例えば。 5分/ 20分など。func applicationWillEnterForeground(_ application: UIApplication) { inside AppDelegate
  3. アプリケーションが可能な限りバックグラウンドで動作することを許可することを忘れないでください。

例えば、

   @UIApplicationMain
    class AppDelegate: UIResponder {
    var backgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskInvalid
    func application(_ application: UIApplication,
                         didReceiveRemoteNotification userInfo: [AnyHashable: Any],
                         fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
            if UIApplication.shared.applicationState != .active {
                doFetch(completionHandler: completionHandler)
            } else {
                // foreground here
                completionHandler(UIBackgroundFetchResult.noData)
            }
        }
    func application(_ application: UIApplication,
                         performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
            doFetch(completionHandler: completionHandler)
        }
    private func doFetch(completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    sendTheRequestToWakeApp()
    backgroundTask = UIApplication.shared.beginBackgroundTask { [weak self] in
                self?.endBackgroundTask()
            }
/// do work here
    completionHandler(UIBackgroundFetchResult.noData)
    }
    private func endBackgroundTask() {
            print("Background task ended.")
            UIApplication.shared.endBackgroundTask(backgroundTask)
            backgroundTask = UIBackgroundTaskInvalid
        }
    private func sendTheRequestToWakeApp() {
    /// Implement request using native library or Alamofire. etc.
    }
    }

サーバー側では、単純な時間またはループを使用します。

短所、

  1. インターネットが必要です
  2. それは完全には機能しません。バッテリー残量が少なくなると、バックグラウンドモードが制限されます。

プロジェクトを設定することを忘れないでください:

proejct screenshot

2
Vyacheslav