本記事ではwatchOSアプリのライフサイクルについて解説します。
目次
アプリの状態
アプリの状態は下記の図のように状態遷移をします。
状態遷移図に出てくる各状態の説明は次の通りです。
- Not running
- アプリは動いていません。そもそもユーザがアプリを起動していないか、あるいはシステムがSuspended状態のアプリを開放した後の状態です。
- Inactive
- アプリはフォアグラウンドで動作していますが、操作やジェスチャーを受け付ける状態にはありません。しかし、他のコードは実行しているかもしれません。通常、新しく起動したアプリはしばらくこの状態にいて、その後にActive状態に遷移します。
- Active
- アプリはフォアグラウンドで動作しており、操作やジェスチャーを受け付ける状態にあります。アプリが画面上で動作している通常の状態です。
- background
- この状態でもアプリは実行されていますが、システムにより少しの時間しか実行時間を与えられていません。また、システムは、アプリがSuspended状態に入る前に、バックグラウンドセッション、バックグラウンドタスク、を実行する時間を与えます。
- システムはワーニングなしにアプリをSuspended状態のアプリを開放することができます。それはdelegateメソッドのapplicationDidEnterBackground()を使うことで、アプリの現在の状態を再構築するためのデータを保存できるからです。もし、追加のバックグラウンドの実行時間が欲しければ、ProcessInfoクラスのperformExpiringActivity(withReason:using:)メソッドを使うことで延長できます。
- Suspended
- アプリはメモリ上にはいますが何も実行しません。システムは、Background状態にあって、かつ、何も実行するべきタスクのないアプリをSuspended状態にします。システムはどんな時でも、他のアプリのためにSuspended状態のアプリを開放することがあります。システムは何の言わずアプリを開放します。その時アプリは、起動することはないですし、通知を受け取ることもありません。
- システムは、頻繁に使われるアプリはすぐに再開できるように、メモリ上にキープしようとします。特に、最も最近使われたアプリ、Dockにあるアプリ、現在画面のコンプリケーションに表示されている煽をキープします。もしこれらのアプリがメモリ制限により開放されるなら、システムはメモリに空き容量ができ次第、また再配置します。
この状態遷移図には出てきませんが、Frontmostという状態も並行して存在します。Frontmostについては後述します。
アプリの状態遷移におけるdelegate メソッド
上記の状態遷移のタイミングを、delgateメソッドによる通知で受け取ることができます。
図中の記号 | 遷移のタイミング | delegateメソッド |
---|---|---|
A | Not runningからInactive / Backgroundへの遷移 | applicationDidFinishLaunching() |
B | InactiveとActiveの間の遷移 | applicationDidBecomActive() applicationWillResignActive() |
C | BackgroundからInactiveへの遷移 | applicationWillEnterForeground() applicationDidEnterBackground() |
AのapplicationDidFinishLaunching()を除いて、システムはwatchOSアプリのメインインタフェースに表示された時だけ、これらのdelegateメソッドを呼びます。システムは他のどんな補足のインターフェースを表示した時でも、それらは呼び出しません。それは例えば、システムがコンプリケーションの更新やカスタム通知を表示した時です。通知には、通知のコントローラーのwillActivate()やdidDeactivate()を使ってください。
アプリの状態とインターフェースの状態
アプリの状態とインターフェースの状態の間に直接的な関連はありません。例えば、インターフェースはActiveでもアプリはInactiveかもしれません。下記の表は、最もよくある状況での、アプリとインターフェースの状態です。
状況 | アプリ | インターフェース |
---|---|---|
スクリーン上で実行中 | Active | Active |
Dockで実行中 | Inactive isApplicationRunningInDockがtrue | Active(Dock内) |
Frontmostとして実行中 | Inactive | Inactive |
Dynamic通知を表示中 | Inactive / Background | Active(通知) |
スナップショットバックグラウンドタスクを実行中 | Background | Active(スクリーンは非表示) |
その他のバックグラウンドタスクを実行中 | Background | Inactive |
バックグラウンドセッションを実行中 | Background | Inactive |
一般的な状態遷移の順番
アプリ起動時
これはアプリが起動した時、特にユーザが明示的に起動した時の順番です。例えば、ホームスクリーンでアプリのアイコンをタップした時です。
- アプリはWKApplicationState.inactiveに遷移します。システムはapplicationDidFinishLaunching()を呼びます。
- システムははじめのインターフェースコントローラーをインスタンス化し、そのawake(with Context:)を呼びます。
- アプリはWLApplicationState.activeに遷移します。システムはapplicationDidBecomeActive()を呼びます。
- システムはインターフェースコントローラーのwillAcive()を呼びます。
- アプリがスクリーンに表示されます。システムはインターフェースコントローラーのdidAppear()を呼びます。
アプリがBackgoundに遷移する時
これはアプリがBackgroundになる時の順番です。スクリーン上で実行されていたけど、腕を下ろした時、あるいは、スクリーンがオフになった時です。もし、ユーザが明確にアプリを閉じたとき(デジタルクラウンを押す、もしくはスクリーンを覆って隠した時)、アプリはFrontmostアプリではなくなり、Inactiveを経由せずに、すぐにBackgroundに遷移します。
- システムはapplicationWillResignActive()を呼びます。
- アプリはWKApplicationState.inactiveに遷移します。アプリはfrontmostアプリである限りこの状態を維持します(デフォルトで2分)
- アプリはWKApplicationState.backgroundに遷移します。システムはapplicationDidEnterbackground()を呼びます。
- システムは表示中のインターフェースコントローラーのdidDeactivate()を呼びます。
- システムはアプリをSuspended状態にします。
アプリが再開する時
これはアプリがBackgroundあるいはSuspendedであった時、ユーザがアプリをアクティベートした時です。例えば、コンプリケーションをタップした時です。
- Suspendedであれば、アプリはWKApplicationState.backgroundで再開します。
- システムはapplicationWillEnterForeground()を呼びます。
- アプリはWKApplicationState.activeに遷移します。システムはapplicationDidBecomeActive()を呼びます。
- システムははじめのインターフェースコントローラーのwillActivate()を呼びます。
Frontmostとは
もしアプリがFrontmostであれば、システムは、ユーザが腕を上げた時にそのアプリを表示します。実行中の時にスクリーンがオフになる、あるいは、ユーザーが腕を下ろした時、アプリはFrontmostとなります。アプリはInactiveに遷移しますが、Backgroundには遷移しません。
デフォルトでは、アプリは2分間はFrontmostのまま維持します。ユーザはこの動作を変更できます(Settings > General > Wake Screen)。また、isFrontmostTimeoutExtendedプロパティをtrueにすることでも延長することができます。
アプリがFrontmostである間、ユーザが腕をあげたら、システムは自動的にアプリをアクティベートしスクリーンに表示します。Frontmostがタイムアウトしたら、通常、アプリはBackgroundに遷移し、その後にSuspendedに遷移します。
もし、ユーザがいくつかの方法(例えば、クラウンを押す、スクリーンを覆って隠す)でアプリを閉じたなら、アプリはFrontmostではなくなります。すぐにInactiveからBackgroundに遷移します。
FrontmostのアプリがInactiveなら、スクリーンに表示はされないけど、フォアグラウンドで実行され続けます。これは下記の特徴を維持することを意味します。
- 触覚フィードバックを再生できます
- 通知を受信します
- URLSessionタスクやWatch Connectivityセッションからのバックグラウンド転送の完了に対し、すぐに反応することができます
例えば、Frontmostアプリが通知を受信したら、システムはuserNotificationCenter(_:willPresent:withCompletionhandler:)を呼びます。これは通知のアラートを表示するというよりは、触覚フィードバック、またはカスタム音声を再生し、ユーザーインターフェースを更新します。
ワークアウト、ロケーション、バックグラウンドオーディオ、オーディオレコーディングといったアプリは、Frontmostアプリに似た動作をします。しかし、これらのアプリは、ワークアウト・ロケーション・サウンドセッションの初めから終わりまで、ずっとBackgroundでの実行です。もし、ユーザがそのセッションの間にWatchを操作するなら、システムはWatch Faceの一番上に絵文字を表示します。ユーザがその絵文字をタップしたら、そのセッションのアプリはフォアグラウンドで再開します。
詳しい情報は、HKWorkoutSessionを参照してください。
バックグラウンドデータの受信
システムがバックグラウンドデータを受信した時、そのデータを処理するためにアプリはすぐに起動しないかもしれません。バッテリーに優しくするため、アプリにデータを届けるのを遅らせるかもしれません。
アプリが実行中であれば(Active、inactive、Frontmost、スクリーン表示中)、システムはそのデータをアプリにすぐに届けます。アプリがBackgoundであれば、システムは10分以内にアプリを起動し、データを届けます。