MRが楽しい

MRやVRについて学習したことを書き残す

HoloLensアプリでサスペンド状態への移行と復旧を検知する

本日は HoloLens の調査枠です。
HoloLens アプリがサスペンド状態に移行するタイミングとそこから実行状態に戻るタイミングを検出します。

3Dアプリでのサスペンド

HoloLens で3Dアプリを終了する場合、ブルームジェスチャーでアプリを終了することができます。
f:id:bluebirdofoz:20190424093443j:plain

しかし、実際にはこのとき、3Dアプリはサスペンド状態に移行しており、完全に終了していません。
メモリの開放などが行われておらず、再びアプリを起動すると前回の状態から続けて起動するような形になります。
f:id:bluebirdofoz:20190424093451j:plain

アプリを完全に終了するには対象アプリのパネルを閉じる必要があります。

UWPアプリの状態遷移

UWPアプリのライフサイクルは以下のページに参考資料があります。
docs.microsoft.com
docs.microsoft.com

サスペンドの検出

このためアプリ側から見ると、終了通知が受け取れないままアプリが完全終了させられたり、突如、実行環境が変化するケースが発生します。
これらの状態遷移を3Dアプリ側で検出するには OnApplicationFocus(bool) または OnApplicationPause(bool) 関数が利用できます。
docs.unity3d.com
docs.unity3d.com

サスペンド移行時には OnApplicationFocus が False、OnApplicationPause が True を返します。
サスペンドからの復旧時には OnApplicationFocus が True、OnApplicationPause が False を返します。

実機での動作を確認する

実際に HoloLens での動作を確認してみます。
以下の記事を元にHoloLens(WindowsMR)プロジェクトを作成します。
bluebirdofoz.hatenablog.com

2019/4/24現在、MRTK 2017 の最新バージョンは 2017.4.3.0 です。
f:id:bluebirdofoz:20190424093504j:plain

サンプルコード

OnApplicationFocus(bool) と OnApplicationPause(bool) 関数の結果を表示する以下のスクリプトを作成します。
・AppChecker.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AppChecker : MonoBehaviour
{
    /// <summary>
    /// 出力用テキストフィールド
    /// </summary>
    private UnityEngine.UI.Text p_text;

    /// <summary>
    /// 起動時処理
    /// </summary>
    private void Start()
    {
        // Textコンポーネントを取得
        p_text = GetComponent<UnityEngine.UI.Text>();
        if (p_text != null) p_text.text = "";

        string text = "Start";
        message(text);
    }

    /// <summary>
    /// フォーカスの検出
    /// </summary>
    /// <param name="focus"></param>
    private void OnApplicationFocus(bool focus)
    {
        string text = "OnApplicationFocus:" + focus;
        message(text);
    }

    /// <summary>
    /// 一時停止の検出
    /// </summary>
    /// <param name="pause"></param>
    private void OnApplicationPause(bool pause)
    {
        string text = "OnApplicationPause:" + pause;
        message(text);
    }

    /// <summary>
    /// メッセージ出力
    /// </summary>
    /// <param name="text"></param>
    private void message(string text)
    {
        if (p_text != null)
        {
            // 発生時刻と共にテキストフィールドに文字を出力
            p_text.text += text;
            p_text.text += System.DateTime.Now.ToString(" hh:mm:ss");
            p_text.text += System.Environment.NewLine;
        }
    }
}

作成したスクリプトを Text オブジェクトにアタッチします。
f:id:bluebirdofoz:20190424093511j:plain

後は HoloLens 向けにプロジェクトをビルドしてインストールします。
UnityプロジェクトのビルドとHoloLensへのインストール手順については以下を参照してください。
bluebirdofoz.hatenablog.com

HoloLensでの動作確認

HoloLens 上で動作確認を行います。
f:id:bluebirdofoz:20190424093520j:plain

アプリ起動後に一度ブルーム操作でアプリを閉じ、30秒ほど待って再びパネルからアプリを呼び出してみました。
f:id:bluebirdofoz:20190424093527j:plain
サスペンドへの移行のタイミングと、復旧のタイミングでそれぞれの関数が呼ばれています。

参考ページ

blog.xin9le.net
qiita.com

2019/09/16追記

OnApplicationPause(bool) と OnApplicationFocus(bool) の使い分けについてです。
この2つの関数はアプリでバックグラウンド処理が走っていた場合、異なる動きをします。
例えば、以下のようなサスペンド時にアプリを完全終了するスクリプトを準備します。
・AppCondition.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AppCondition : MonoBehaviour
{
    /// <summary>
    /// 起動時処理
    /// </summary>
    void Start()
    {
    }

    /// <summary>
    /// 一時停止の検出
    /// </summary>
    /// <param name="pause"></param>
    private void OnApplicationPause(bool pause)
    {
        Debug.Log("OnApplicationPause:" + pause);
        // 一時停止された場合はアプリを完全終了する
        if(pause)
        {
#if WINDOWS_UWP
            Windows.ApplicationModel.Core.CoreApplication.Exit();
#else
            Application.Quit();
#endif
        }
    }

    /// <summary>
    /// フォーカスの検出
    /// </summary>
    /// <param name="focus"></param>
    private void OnApplicationFocus(bool focus)
    {
        Debug.Log("OnApplicationFocus:" + focus);
        // フォーカスが失われた場合はアプリを完全終了する
        if(focus == false)
        {
#if WINDOWS_UWP
            Windows.ApplicationModel.Core.CoreApplication.Exit();
#else
            Application.Quit();
#endif
        }
    }
}

通常、アプリ起動中にHoloLensのブルーム操作を行うと、OnApplicationPause 側の処理でアプリが強制終了します。
一方で、UNETでのネット接続のようなバックグラウンド処理が走っていた場合、OnApplicationFocus 側の処理でアプリが強制終了します。
これはバックグラウンド処理が走っていた場合、ブルーム操作を行ってもアプリが一時停止せず、OnApplicationPause が実行されないためです。