【Swift】バックグラウンドで処理を続ける方法!beginBackgroundTask

【Swift】バックグラウンドで処理を続ける方法!beginBackgroundTask

この記事からわかること

  • Swiftバックグラウンド処理続けるには?
  • UIApplicationクラスbeginBackgroundTaskメソッド使い方
  • Background Task 2 ("Called by MyApp, from $XXX"), was created over 30 seconds ago. In applications running in the background, this creates a risk of termination. Remember to call UIApplication.endBackgroundTask(_:) for your task in a timely manner to avoid this.とは?

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

環境

バックグラウンドでも処理を継続する方法

Swiftではバックグラウンド(ここではアプリが停止している状態)でも処理を継続させる方法がいくつか存在するようです。そもそもバックグラウンドでもアプリを実行させることが不毛なバッテリー消費を引き起こすことになるためiOSアプリではバックグラウンド操作の制限が厳しいようです。

今回はその中でもUIApplicationクラスのbeginBackgroundTaskメソッドを使用した方法をまとめていきます。

beginBackgroundTaskメソッド

公式リファレンス:beginBackgroundTaskメソッド

func beginBackgroundTask(expirationHandler handler: (() -> Void)? = nil) -> UIBackgroundTaskIdentifier

beginBackgroundTaskアプリがバックグラウンドに入った場合に続行したいタスクをマークするためのメソッドです。返り値としてバックグラウンドタスクを一意に識別するUIBackgroundTaskIdentifier型のIDを返します。このIDは明示的にバックグラウンドタスクが完了したことをマークするendBackgroundTaskメソッドの引数として利用します。

引数expirationHandler動作可能なバックグラウンド動作時間が0になる直前に呼び出されるハンドラーです。この方法ではバックグラウンドで処理を継続できる秒数が制限されているので、制限時間を超えないような処理を渡すように注意する必要があります。具体的な秒数を検証してみましたが、シミュレーターでは30秒程度、実機では10分以上動作することを確認できました。

使用方法

使用方法はバックグラウンドで実行したい処理の前で呼び出すだけです。バックグラウンドでの動作が不要になるタイミングでendBackgroundTaskメソッドを呼び出します。

private func backgroundCount() {
    self.backgroundTaskID = UIApplication.shared.beginBackgroundTask {
        UIApplication.shared.endBackgroundTask(backgroundTaskID)
    }
    timerPublisher = Timer.publish(every: 1, on: .current, in: .common)
        .autoconnect()
        .receive(on: DispatchQueue(label: "subthread", qos: .background))
        .sink { _ in
            print("発火!\(count)")
            count += 1
            if count == 1000 {
                UIApplication.shared.endBackgroundTask(backgroundTaskID)
            }
        }
}

Swift UIで動作確認するためのコードは以下の通りになります。

import SwiftUI
import Combine

struct ContentView: View {
  
    @State  private var count: Int = 0
    @State  var timerPublisher: AnyCancellable?
    @State  private var backgroundTaskID = UIBackgroundTaskIdentifier(rawValue: 0)
    
    private func backgroundCount() {
        self.backgroundTaskID = UIApplication.shared.beginBackgroundTask {
            UIApplication.shared.endBackgroundTask(backgroundTaskID)
        }
        timerPublisher = Timer.publish(every: 1, on: .current, in: .common)
            .autoconnect()
            .receive(on: DispatchQueue(label: "subthread", qos: .background))
            .sink { _ in
                print("発火!\(count)")
                count += 1
                if count == 1000 {
                    UIApplication.shared.endBackgroundTask(backgroundTaskID)
                }
            }
    }
    
    @Environment(\.scenePhase) private var scenePhase
    
    var body: some View {
        VStack {
            Text("\(count)")
                .onAppear {
                    backgroundCount()
                }.onChange(of: scenePhase) { phase in
                    switch phase {
                    case .active:
                        print("フォアグラウンド")
                    case .inactive:
                        print("フォアグラウンド(作業を一時停止する必要)")
                    case .background:
                        print("バックグラウンド")
                    @unknown    default:
                        print("不明")
                    }
                }
        }
    }
}

Background Task 2 ("Called by MyApp, from $XXX"), was created over 30 seconds ago. In applications running in the background, this creates a risk of termination. Remember to call UIApplication.endBackgroundTask(_:) for your task in a timely manner to avoid this.

beginBackgroundTaskメソッドを利用していると以下のようなログが出力されることがあります。これは適切にendBackgroundTaskメソッドを呼び出していないことが原因です。

Background Task 2 ("Called by MyApp, from $XXX"), was created over 30 seconds ago. In applications running in the background, this creates a risk of termination. Remember to call UIApplication.endBackgroundTask(_:) for your task in a timely manner to avoid this.

適切にタスクを終了させない場合、アプリがOSによって終了させられることもあるので注意してください。

Bluetoothではもっと簡単にバックグラウンド処理を実装できます

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index