読者です 読者をやめる 読者になる 読者になる

しっぽを追いかけて

ぐるぐるしながら考えています

Unity と猫の話題が中心   掲載内容は個人の私見であり、所属組織の見解ではありません

Xamarin.Forms の App Lifecycle の呼び出され方を調べたい 【iOS編】

今回は Xamarin.iOS のアプリケーションライフサイクルの動作を確かめてみたいと思います

というわけで iOS のアプリケーション状態遷移のおさらい

f:id:matatabi_ux:20150308073914p:plain

Not Running、Inactive、Active、Background、Suspended の 4つの状態があり、Suspended に遷移してもメモリは解放されないので、再開時にデータを復帰させる対応はいらなそう

上記を踏まえて iOS の動作確認用のアプリを作ります

とりあえずブラウザを開く機能を追加

/// <summary>
/// Web ブラウザを開くサービス
/// </summary>
public class OpenBrowserService : IOpenBrowserService
{
    /// <summary>
    /// Web ブラウザを開く
    /// </summary>
    /// <param name="uri">Uri</param>
    public void OpenUri(string uri)
    {
        SimpleLogger.WriteLine(string.Format("open to {0}", uri));

        UIApplication.SharedApplication.OpenUrl(new NSUrl(uri));
    }
}

さくっとブラウザ呼び出しを追加するのみ!

次に AppDelegate.cs を変更

// The UIApplicationDelegate for the application. This class is responsible for launching the 
// User Interface of the application, as well as listening (and optionally responding) to 
// application events from iOS.
[Register("AppDelegate")]
public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
{
    /// <summary>
    /// WillFinishLanching イベントハンドラ
    /// 起動プロセスは実行されたが、その状態の復元がまだ発生していない状態
    /// </summary>
    /// <param name="uiApplication">アプリケーション</param>
    /// <param name="launchOptions">起動オプション</param>
    /// <returns>正常終了フラグ</returns>
    public override bool WillFinishLaunching(UIApplication uiApplication, NSDictionary launchOptions)
    {
        SimpleLogger.WriteLine(string.Format("WillFinishLaunching. AppState={0}", uiApplication.ApplicationState.ToString()));

        // ブラウザで開く機能を登録
        App.Container.RegisterType<IOpenBrowserService, OpenBrowserService>(new ContainerControlledLifetimeManager());

        return base.WillFinishLaunching(uiApplication, launchOptions);
    }

    /// <summary>
    /// FinishedLaunching イベントハンドラ
    /// 起動プロセスがほぼ終了した後、アプリの起動準備ができた状態
    /// </summary>
    /// <param name="uiApplication">アプリケーション</param>
    /// <param name="launchOptions">起動オプション</param>
    /// <returns>正常終了フラグ</returns>
    public override bool FinishedLaunching(UIApplication uiApplication, NSDictionary launchOptions)
    {
        SimpleLogger.WriteLine(string.Format("FinishedLaunching. AppState={0}", uiApplication.ApplicationState.ToString()));

        global::Xamarin.Forms.Forms.Init();
        LoadApplication(new App());

        return base.FinishedLaunching(uiApplication, launchOptions);
    }

    /// <summary>
    /// OnActivated イベントハンドラ
    /// アプリケーションがアクティブになった直後に呼び出されます
    /// </summary>
    /// <param name="uiApplication">アプリケーション</param>
    public override void OnActivated(UIApplication uiApplication)
    {
        SimpleLogger.WriteLine(string.Format("OnActivated. AppState={0}", uiApplication.ApplicationState.ToString()));

        base.OnActivated(uiApplication);
    }

    /// <summary>
    /// OnResignActivation イベントハンドラ
    /// アプリケーションが Inactive になる直前に呼び出されます
    /// </summary>
    /// <param name="uiApplication">アプリケーション</param>
    public override void OnResignActivation(UIApplication uiApplication)
    {
        SimpleLogger.WriteLine(string.Format("OnResignActivation. AppState={0}", uiApplication.ApplicationState.ToString()));

        base.OnResignActivation(uiApplication);
    }

    /// <summary>
    /// DidEnterBackground イベントハンドラ
    /// Backgrond 状態に遷移した状態
    /// </summary>
    /// <param name="uiApplication">アプリケーション</param>
    public override void DidEnterBackground(UIApplication uiApplication)
    {
        SimpleLogger.WriteLine(string.Format("DidEnterBackground. AppState={0}", uiApplication.ApplicationState.ToString()));

        base.DidEnterBackground(uiApplication);
    }

    /// <summary>
    /// WillEncodeRestorableState イベントハンドラ
    /// 任意のアプリデータ復帰が必要になった場合に呼び出されます
    /// </summary>
    /// <param name="uiApplication">アプリケーション</param>
    /// <param name="coder">シリアライズオブジェクト</param>
    public override void WillEncodeRestorableState(UIApplication uiApplication, NSCoder coder)
    {
        SimpleLogger.WriteLine(string.Format("WillEncodeRestorableState. AppState={0}", uiApplication.ApplicationState.ToString()));

        base.WillEncodeRestorableState(uiApplication, coder);
    }

    /// <summary>
    /// WillEnterForeground イベントハンドラ
    /// Foreground 状態に遷移した状態
    /// </summary>
    /// <param name="uiApplication">アプリケーション</param>
    public override void WillEnterForeground(UIApplication uiApplication)
    {
        SimpleLogger.WriteLine(string.Format("WillEnterForeground. AppState={0}", uiApplication.ApplicationState.ToString()));

        base.WillEnterForeground(uiApplication);
    }

    /// <summary>
    /// WillTerminate イベントハンドラ
    /// アプリが終了する直前に呼び出されます
    /// </summary>
    /// <param name="uiApplication">アプリケーション</param>
    public override void WillTerminate(UIApplication uiApplication)
    {
        SimpleLogger.WriteLine(string.Format("WillTerminate. AppState={0}", uiApplication.ApplicationState.ToString()));

        base.WillTerminate(uiApplication);
    }
}

DI コンテナに先ほどのサービスクラス実体を登録するのと、各種状態遷移のイベントハンドラをログ出力つきで追加しました・・・Windows Phone に比べると多い;

あとは実行、Windows Phone の時と同様に下記のような操作を順にやってみます

  • アプリ起動
  • 次画面に遷移
  • ブラウザで Xamarin ホームを開く
  • アプリに戻る
  • トップ画面に戻る
  • OS ホームに戻る
  • 再度アプリに戻る
  • アプリを終了
  • 再度起動

操作の様子はこんな感じ

f:id:matatabi_ux:20150308074836g:plain

出力されたログは・・・

AppDelegate.WillFinishLaunching WillFinishLaunching. AppState=Inactive
AppDelegate.FinishedLaunching FinishedLaunching. AppState=Inactive
App.OnStart started.
AppDelegate.OnActivated OnActivated. AppState=Active
TopPage.xaml.OnAppearingTopPage Appearing.
SecondPage.xaml.OnAppearingSecondPage Appearing.
AppDelegate.OnResignActivation OnResignActivation. AppState=Active
App.OnSleep sleeped.
AppDelegate.DidEnterBackground DidEnterBackground. AppState=Background
AppDelegate.WillEnterForeground WillEnterForeground. AppState=Background
AppDelegate.OnActivated OnActivated. AppState=Active
App.OnResume resumed.
TopPage.xaml.OnAppearingTopPage Appearing.
AppDelegate.OnResignActivation OnResignActivation. AppState=Active
App.OnSleep sleeped.
AppDelegate.DidEnterBackground DidEnterBackground. AppState=Background
AppDelegate.WillEnterForeground WillEnterForeground. AppState=Background
AppDelegate.OnActivated OnActivated. AppState=Active
App.OnResume resumed.
AppDelegate.OnResignActivation OnResignActivation. AppState=Active
App.OnSleep sleeped.
AppDelegate.DidEnterBackground DidEnterBackground. AppState=Background
AppDelegate.WillTerminate
(アプリ終了後、デバッカーも停止した)

やはり Windows Phone と同様にアプリ終了するまではアプリに戻ると OnResume が呼ばれるようです

操作が速すぎて Background から Suspended まで行くことがなかったのかとブラウザを開いたあとに 10 分待ってみましたが結果は変わらず

おそらくデバッグ起動だと Suspended にならないのかと思います

いずれにせよ iOS も OnResume を通ったときだけセッションデータを復帰させればよさそうです、ただアプリデータはメモリに残っているので何もしなくてよさそうですが