watchOSアプリのライフサイクル【Apple Watch】

本記事では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メソッド
ANot runningからInactive / Backgroundへの遷移applicationDidFinishLaunching()
BInactiveとActiveの間の遷移applicationDidBecomActive()
applicationWillResignActive()
CBackgroundからInactiveへの遷移applicationWillEnterForeground()
applicationDidEnterBackground()

AのapplicationDidFinishLaunching()を除いて、システムはwatchOSアプリのメインインタフェースに表示された時だけ、これらのdelegateメソッドを呼びます。システムは他のどんな補足のインターフェースを表示した時でも、それらは呼び出しません。それは例えば、システムがコンプリケーションの更新やカスタム通知を表示した時です。通知には、通知のコントローラーのwillActivate()やdidDeactivate()を使ってください。

アプリの状態とインターフェースの状態

アプリの状態とインターフェースの状態の間に直接的な関連はありません。例えば、インターフェースはActiveでもアプリはInactiveかもしれません。下記の表は、最もよくある状況での、アプリとインターフェースの状態です。

状況アプリインターフェース
スクリーン上で実行中ActiveActive
Dockで実行中Inactive
isApplicationRunningInDockがtrue
Active(Dock内)
Frontmostとして実行中InactiveInactive
Dynamic通知を表示中Inactive / BackgroundActive(通知)
スナップショットバックグラウンドタスクを実行中BackgroundActive(スクリーンは非表示)
その他のバックグラウンドタスクを実行中BackgroundInactive
バックグラウンドセッションを実行中BackgroundInactive

一般的な状態遷移の順番

アプリ起動時

これはアプリが起動した時、特にユーザが明示的に起動した時の順番です。例えば、ホームスクリーンでアプリのアイコンをタップした時です。

  1. アプリはWKApplicationState.inactiveに遷移します。システムはapplicationDidFinishLaunching()を呼びます。
  2. システムははじめのインターフェースコントローラーをインスタンス化し、そのawake(with Context:)を呼びます。
  3. アプリはWLApplicationState.activeに遷移します。システムはapplicationDidBecomeActive()を呼びます。
  4. システムはインターフェースコントローラーのwillAcive()を呼びます。
  5. アプリがスクリーンに表示されます。システムはインターフェースコントローラーのdidAppear()を呼びます。

アプリがBackgoundに遷移する時

これはアプリがBackgroundになる時の順番です。スクリーン上で実行されていたけど、腕を下ろした時、あるいは、スクリーンがオフになった時です。もし、ユーザが明確にアプリを閉じたとき(デジタルクラウンを押す、もしくはスクリーンを覆って隠した時)、アプリはFrontmostアプリではなくなり、Inactiveを経由せずに、すぐにBackgroundに遷移します。

  1. システムはapplicationWillResignActive()を呼びます。
  2. アプリはWKApplicationState.inactiveに遷移します。アプリはfrontmostアプリである限りこの状態を維持します(デフォルトで2分)
  3. アプリはWKApplicationState.backgroundに遷移します。システムはapplicationDidEnterbackground()を呼びます。
  4. システムは表示中のインターフェースコントローラーのdidDeactivate()を呼びます。
  5. システムはアプリをSuspended状態にします。

アプリが再開する時

これはアプリがBackgroundあるいはSuspendedであった時、ユーザがアプリをアクティベートした時です。例えば、コンプリケーションをタップした時です。

  1. Suspendedであれば、アプリはWKApplicationState.backgroundで再開します。
  2. システムはapplicationWillEnterForeground()を呼びます。
  3. アプリはWKApplicationState.activeに遷移します。システムはapplicationDidBecomeActive()を呼びます。
  4. システムははじめのインターフェースコントローラーの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分以内にアプリを起動し、データを届けます。

参考URL

Working with the watchOS App Life Cycle