Makopy'5 La6

スマホアプリ開発とかその周辺のこととか関係ないこと。または恋は言ってみりゃボディー・ブロー

(Xamarin.Forms)アプリのライフサイクル

ライフサイクルの捕捉

ライフサイクルの捕捉は、スマホアプリ開発において非常に重要です。
機能要件や実装都合等の事情により、
ライフサイクルのタイミングに合わせて処理をする。
ということがしばしばあるからです。

ライフサイクルは大きく2つに分けられます。

  • アプリのライフサイクル
  • 画面のライフサイクル

今回は「アプリのライフサイクル」について書きます!

Xamarin.Formsにおけるアプリのライフサイクル

公式のDevelopersガイドに記載があります。
https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/app-lifecycle/

Applicationクラスには、以下の3つのライフサイクルメソッドが存在します。

  • OnStart
    • アプリケーションの起動時に呼び出される
  • OnSleep
    • アプリケーションがバックグラウンドに移動するたびに呼び出される
  • OnResume
    • アプリケーションがバックグラウンド遷移後、再開されたときに呼び出される

泣いても笑ってもこの3つしかありません。
以下ではこの3つのライフサイクルメソッドが呼び出されるタイミングを調査します。

呼び出されるタイミングについて調査

  • Appクラス
  • .DroidのMainActivity.cs
  • .iOSのAppDelegate.cs

のそれぞれのライフサイクルメソッドにログを張って、

  • 起動
  • バックグラウンド
  • フォアグラウンド

に関連しそうな操作をしてみました。

調査そのものに関係ないのですが…。
.iOSのAppDelegateのライフサイクルメソッド名がネイティブとだいぶイメージが違うなぁと思いましたw
iOSネイティブが大好物な人なので、違和感ありありですw

調査結果から見たポイント

調査ログを延々と記載する前に…。
先に結論というかポイントをまとめておきますw

OnResumeの注意点

OnResumeAndroidにおけるOnResumeと違って、起動時は呼ばれない

OnSleep/OnResumeの注意点

iOSでは、本来バックグラウンドと見なしたくない下記のタイミングで、OnSleep/OnResumeが呼ばれてしまう。

  • 通知センターの表示/非表示
  • コントロールセンターの表示/非表示

実際にはバックグラウンド/フォアグラウンドではなく、アクティブ/インアクティブに紐づいてしまっている。
従って、
OnSleepが呼ばれるタイミングは必ずしもバックグラウンドではない


ということで、以下調査ログの記録です。

iOS

起動時

  • AppのOnDestroyがAppDelegateのWillFinishLaunchingの直後に呼ばれる
AppDelegate.cs - WillFinishLaunching
AppDelegate.cs - FinishedLaunching
App.xaml.cs - .ctor
App.xaml.cs - OnStart
AppDelegate.cs - OnActivated

ホームボタン押下時

  • AppのOnDestroyがAppDelegateのOnResignActivationの直後に呼ばれる
AppDelegate.cs - OnResignActivation
App.xaml.cs - OnSleep
AppDelegate.cs - DidEnterBackground

ホームボタン押下後、マルチタスク画面から選択

  • AppのOnResumeがAppDelegateのOnActivatedの直後に呼ばれる
AppDelegate.cs - WillEnterForeground
AppDelegate.cs - OnActivated
App.xaml.cs - OnResume

ホームボタン押下後、アプリアイコンから起動

  • AppのOnResumeがAppDelegateのOnActivatedの直後に呼ばれる
AppDelegate.cs - WillEnterForeground
AppDelegate.cs - OnActivated
App.xaml.cs - OnResume

マルチタスク画面表示時

  • AppのOnSleepがAppDelegateのOnResignActivationの直後に呼ばれる
AppDelegate.cs - OnResignActivation
App.xaml.cs - OnSleep

マルチタスク画面から再選択

  • AppのOnSleepがAppDelegateのOnResignActivationの直後に呼ばれる
AppDelegate.cs - OnActivated
App.xaml.cs - OnResume

通知センター表示

  • AppのOnSleepがAppDelegateのOnResignActivationの直後に呼ばれる
AppDelegate.cs - OnResignActivation
App.xaml.cs - OnSleep

通知センター非表示

  • AppのOnResumeがAppDelegateのOnActivatedの直後に呼ばれる
AppDelegate.cs - OnActivated
App.xaml.cs - OnResume

コントロールセンター表示

  • AppのOnSleepがAppDelegateのOnResignActivationの直後に呼ばれる
AppDelegate.cs - OnResignActivation
App.xaml.cs - OnSleep

コントロールセンター非表示

  • AppのOnResumeがAppDelegateのOnActivatedの直後に呼ばれる
AppDelegate.cs - OnActivated
App.xaml.cs - OnResume

マルチタスク画面からアプリKill

  • AppDelegateのDidEnterBackgroundWillTerminateが呼ばれる
  • Appのライフサイクルメソッドは呼ばれない
AppDelegate.cs - DidEnterBackground
AppDelegate.cs - WillTerminate

Android

アプリ起動時

  • AppのOnStartがActivityのOnStartの直後に呼ばれる
  • ActivityのOnResumeは呼ばれるが、AppのOnResumeは呼ばれない
MainActivity.cs - OnCreate
App.xaml.cs - .ctor
MainActivity.cs - OnStart
App.xaml.cs - OnStart
MainActivity.cs - OnPostCreate
MainActivity.cs - OnResume
MainActivity.cs - OnPostResume

ホームボタン押下時

  • AppのOnSleepがActivityのOnStopの直後に呼ばれる
MainActivity.cs - OnUserLeaveHint
MainActivity.cs - OnPause
MainActivity.cs - OnSaveInstanceState
MainActivity.cs - OnStop
App.xaml.cs - OnSleep

ホームボタン押下後、アプリ一覧から選択

  • AppのOnResumeがActivityのOnRestartの直後に呼ばれる
MainActivity.cs - OnRestart
App.xaml.cs - OnResume
MainActivity.cs - OnStart
MainActivity.cs - OnResume
MainActivity.cs - OnPostResume

ホームボタン押下後、アプリアイコンから起動

  • AppのOnStartがActivityのOnStartの直後に呼ばれる
  • ActivityのOnResumeは呼ばれるが、AppのOnResumeは呼ばれない
MainActivity.cs - OnCreate
App.xaml.cs - .ctor
MainActivity.cs - OnStart
App.xaml.cs - OnStart
MainActivity.cs - OnPostCreate
MainActivity.cs - OnResume
MainActivity.cs - OnPostResume

マルチタスクボタン押下時

  • AppのOnSleepがActivityのOnStopの直後に呼ばれる
MainActivity.cs - OnUserLeaveHint
MainActivity.cs - OnPause
MainActivity.cs - OnSaveInstanceState
MainActivity.cs - OnStop
App.xaml.cs - OnSleep

マルチタスクボタン押下後、アプリ一覧から再選択

  • AppのOnResumeがActivityのOnRestartの直後に呼ばれる
MainActivity.cs - OnRestart
App.xaml.cs - OnResume
MainActivity.cs - OnStart
MainActivity.cs - OnResume
MainActivity.cs - OnPostResume

通知バー表示

  • 何も呼ばれない

アプリ一覧からアプリKill

  • ActivityのOnDestroyが呼ばれる
  • Appのライフサイクルメソッドは呼ばれない
MainActivity.cs - OnDestroy

(Xamarin.Forms)ログにメソッド名を出力する

ログにメソッド名を出力したい!

そう思うことはちょいちょいあります。
iOSネイティブだと、

  • Objective-Cなら__PRETTY_FUNCTION__
  • Swiftなら#function

で、手軽にできるんですが。

Xamarin.Formsではどうやるんでしょうか?
ということで、調べて見ました。

MethodBase.GetCurrentMethod

パッと調べてみた感じ、
MethodBase.GetCurrentMethod
を使えばよさそう!

GetCurrentMethod - Xamarin

と思いましたが、
Xamarin.Forms(PCL)ではちょっと無理っぽい…。

MethodBase does not contain GetCurrentMethod in Portable Class Library (VS 2015)

Caller Info属性

もうちょっと調べてみたら、
Caller Info属性
というのがあるらしい(C# 5.0〜)

C# 5.0 の新機能 - C# によるプログラミング入門 | ++C++; // 未確認飛行 C

こいつならXamarin.Formsでもいけそう! ということで、 Caller Infoを使ったサンプル実装してみました!

とは言っても、
ほとんど上記のページの通りの実装に、 自分が欲しい形を追加しただけなんですが…。

Traceクラスを実装してみた

ログ出力周りについては、
実戦の開発で使うならいろいろ考慮せねばなりませんが…。
ここではベーシックにやり方を押さえるサンプルとして。

おまけ

iOS(Objective-C)の場合

iOS(Swift)の場合

Android(Java)の場合

スマホアプリ開発の学習で真っ先に押さえるべきポイント

スマホアプリ開発の学習

5年?6年?くらいはスマホアプリ開発に携わってきました。
他記事でも書いていることですが…。
iOSネイティブを中心に、色んなプラットフォームでの開発に携わってきました。
どれもこれも突然(FIELD OF VIEW)な話で、
そういう状況下では、そこまでの経験をベースにして、

  • 大事なことから優先的に取り組む
  • 実戦の中でのトライアンドエラーで補完
  • 並行して個人的な取り組みで補完

という動きにならざるを得ません。
基本的に上記のようなスタンスで日々悪戦苦闘しています。

真っ先に押さえるべきポイント

画面遷移とライフサイクル

なるはやで開発の戦力になることを目標に置くならば。
まず画面遷移とライフサイクル周りのことを押さえておくべきだと考えます。

  • ベーシックかつ頻出の画面遷移
    • Navigation
    • Modal
    • Tab
  • 画面やアプリのライフサイクル
    • どのようなライフサイクルをフックできるか
    • 画面遷移ごとの特性

これらを学習のエントリポイントにすると、簡単なサンプル実装でも色んなことでつまずくと思います。
Xamarin.Formsで言えば。
どうしても画面関連にはXAMLの存在はつきまとうし、 MVVMのお話とか。
そういうのは副産物的に学習やトライアンドエラーが稼げる点で、うれしい誤算と思うことにしています。

リスト形式のUI

UIの中ではリスト形式のUIを使えるようになることが先決です。
TableViewとかListViewと呼んでるやつです。

色んな場面で静的にも動的にも使用する頻出のUIです。
静的な例では設定画面。
動的な例ではSNSやチャットのタイムライン表示とか商品リストなどの何かしらの一覧など。

ここにも副産物があります。
リスト形式UIに対しては、DataSourceがつきまといます。
そうなると必然的にコレクションを扱うことになります。
コレクションにModelをぶち込んでぶん回す。
こういったことを理屈ではなく、具体的に言語レベルで押さえることになります。

実験用ベースプロジェクトを作っています(まだ途中)

Xamarin.Formsで。
上記のポイントを盛り込んだプロジェクトを作成しようと思っています。
そのプロジェクトをベースとして学習やトライアンドエラーを積み重ねていこうかと。
そもそも、
覚書的にアウトプット
というのが本ブログの目的だったりするわけですが。
そのアウトプット先をまずは限定してみようかなと。
結果的にGitHubやGistも充実していったらいいなと思ったりするわけです。

ということで、作ってみました。
まだ途中です…。

github.com

Xamarinでもなんとかなるぞ!

以下、個人的な見解に基づいて…。

Xamarinはいいぞ!

「Xamarinはいいぞ!」
Xamarinに関わっている人/興味がある人は、
そんなようなセリフを見聞きしたことがあると思います。
確かに自分もそう思います。
様々な点で魅力に溢れていると思います。
それはもはや筆者がここで語るまでもありません。

Xamarinでもなんとかなるぞ!

個人的なXamarinの出発点は、技術的な興味からでした。
ちょっとやってみようとゆるーく始めた取り組み。

それからあまり時を置かずして、
「来月からXamarinのプロジェクトやってもらうから」
という話が。
その時点での「来月」は「来週」とイコールでしたけどw

とにかく、
「Xamarinを使って開発せざるをえない」
状況に追い込まれたわけです…。
まぁ、こういうの慣れてますけどねw

実情として、
「Xamarinの知識や経験が豊富な人が望んでXamarinの案件にアサインされる」
というケースはあまりないのではないかと思います。

といった、
部分的にXamarinの技術要素にマッチする人がアサインされるケースの方が多いと思います。
少なくとも筆者が現在やっているプロジェクトのメンバーはiOS/Androidのどちらか or 両方な人だけです。
C#XAMLに至っては実務経験がある人はほとんどいませんw
でも、自分含めて苦労しながらもなんとかなっています。

うん…、
「Xamarinでもなんとかなるぞ!」

とっかかりやすさ

以前の話ですが。
似たような流れでハイブリッドアプリ開発に携わることになりました。
その時は不安が結構大きかった記憶があります。
それまでのiOS/Androidのネイティブの経験が活かしづらく感じたからだと思います。
プラグイン部分は各ネイティブのコードを書きますが、基本はWebView上の世界です。

ハイブリッドの時と比べて、Xamarinの場合はどうかというと。
Xamarinの場合はその辺りの不安は感じなくて、
「Xamarinでもなんとかなりそう!」
くらいの感触はまず持てました。
なんとかなりそうという感触は実戦経験から、
「Xamarinでもなんとかなるぞ!」
という確信めいたものに変わりました。
(実戦経験せいぜい3ヶ月くらいですけど…)

あくまでネイティブアプリのエンジニア視点ですが、
「とっかかりやすさ 」
みたいなものがあるのではないかと思います。

Xamarinで開発するかどうかの判断基準

メリットや魅力に溢れるXamarin。
「Xamarinはいいぞ!」
とは言いつつも、
プロジェクトの性質によっては、Xamarinの向き/不向きもあると思います。
何でもかんでもXamarinでというのはハッピーな結果を生まないと思います。

これは何か標準的な指標みたいなものがあるといいなと思います。
チェックシートみたくして、点数が多かったらXamarinで検討/提案してみようとか。

(iOS/Android)WebViewのInspect(Mac OS)

WebViewを巡るあれこれ

ハイブリッドアプリは、それ自体がWebViewの世界の話なので言わずもがなですが…。
ネイティブアプリ開発においても、実戦では結構WebViewを使う頻度は多いです。
何かしらのログイン画面を表示したり、URLロードをフックして云々とか、JavaScriptと連携したりとか。
Webのページ遷移の中にネイティブの画面遷移を絡めて…というのも実際にありました。

WebViewを使ったテクニカルトピックは別の機会に書くとして。
今回はとりあえずWebインスペクタの設定方法を覚書しておきます。

WebViewが絡む開発ではWebインスペクタの存在は重要です。

@ハイブリッドアプリ開発

Webインスペクタは手放せない!!

今回記事では設定方法等扱いませんが、OSやブラウザに依存しないweinreというツールもあります。
weinre - Home

ハイブリッドアプリではインスペクタの使用頻度が必然的に高くなるため、weinreを使う方が楽かもしれません。
(設定はちょっとばかり面倒です)

@ネイティブアプリ開発

WebViewを使った開発時にWebインスペクタがあると便利!

Webインスペクタの設定/起動方法

今回はiOSAndroidでそれぞれの方法を示します。

iOS

Safariを利用します。

  • Safariの設定
    • 設定
      • 詳細
        • 「メニューバーに"開発"メニューを表示」にチェック f:id:makopy_inside:20170222223633p:plain
  • 開発メニューからInspectする対象を選択 f:id:makopy_inside:20170222223718p:plainf:id:makopy_inside:20170222223745p:plain

Android

前提条件として、Chromeが必要です。

Xamarin.Formsの基礎の基礎

Xamarin.Formsとは何者か?

Xamarin.Formsとはどういうものか?
どのような思想で成り立っているのか?

既にXamarin.Formsで開発をしている人はもちろん、Xamarin.Formsに興味を持っている人や始めてみようと思っている人なら、何となくご存知だと思います。
Xamarinの公式サイトを見ればそのようなことは大体書いてあります。

よく見る図

Xamarin.Formsの記事では、 ↓ような図をよく見ると思います。

f:id:makopy_inside:20170221231229p:plain

上述の
Mobile Application Development to Build Apps in C# - Xamarin
にも、同じような図があると思います。

同じような図があるというか、模倣して作りました…。
作っておけば他に使うこともあろうかと思いまして。
そのままもらってきて貼り付けるのも気がひけるし。

「よく見る図」の重要性

図中でいう、
「Shared C#…」
の部分を実装することもあれば、
DependencyServiceやCustom Rendererといった、
「Platform-specific C# の部分を実装することもあります。

特にXamarin.Formsに携わって日が浅い場合。
そうこうしている内に迷子になることも結構あります。
そんなときに立ち返るべきは「よく見る図」なのではないかと思います。