うな(。・ε・。)

Android, iOS, AppEngine まわりのめもめも

Background Fetch が起きたあと、アプリを起動しても didFinishLaunching を通らない

Background Fetch を使うと、アプリのライクサイクルイベントが少し変わってくるのでメモ書きをします。

通常のアプリ起動時のライフサイクルイベント

  1. - application:didFinishLaunchingWithOptions:
  2. - applicationDidBecomeActive:

こののち、「アプリを閉じて再度開く」「写真へのアクセス許可など OS ダイアログが閉じられる」などが起こると、-applicationDidBecomeActive: のみが呼ばれます。

メモリが不足するなどしてプロセスがキルされない限り、- application:didFinishLaunchingWithOptions: は二度と呼ばれないことに注意してください。

Background Fetch が起こり、その後アプリを起動した場合

f:id:liedderoptik:20151208201652p:plain

  1. - application:didFinishLaunchingWithOptions: (Background Fetch が起こったとき)
  2. - application:performFetchWithCompletionHandler:
  3. - applicationDidBecomeActive: (アイコンをタッチして、アプリを起動したとき)

Background Fetch が起きたときは、ユーザがアプリを開くなどしなくても - application:didFinishLaunchingWithOptions: が呼ばれることに注意してください。なお、この際 launchOptions には nil が渡されます。

取り扱いに注意すべきこと

didFinishLaunchingperformFetch での KeyChain の取り扱いに注意

KeyChain は applicationState によって値が取り出せずエラーになることがあります。(設定次第です)

performFetch では気をつけていても、didFinishLaunching でユーザIDをトラッキング用に取得するなどして意図せず値が取り出せない状況が起こり得ます。 例外は起きませんが、適切にエラーハンドリングをする必要があります。

たとえば、「値が取り出せない場合は新しく割り当てる」といった処理をしている場合は、Background Fetch が起きるたびに値が変わってしまいます。 対策としては、KeyChain の accessibility として kSecAttrAccessibleAfterFirstUnlock を使うか、値を取得するときに起こりうるエラーを適切にハンドリングします。

Gilt: iOS7でbackground fetchを利用するとログアウトしてしまうバグへの対応 - ワザノバ | wazanova

ユーザがアプリを明示的に起動しなくても didFinishLaunching が呼ばれることに注意

Background Fetch をつかうと、ユーザが明示的にアイコンをタップしてアプリを起動しなくても、- application:didFinishLaunchingWithOptions: が呼ばれてしまいます。

このとき、メソッド内で「アプリ起動イベント」などを計測していると、誤ったデータが取得されてしまいます。

- applicationDidBecomeActive: を「アプリ起動イベント」として数えるほうが正確です。この場合、「アプリを閉じてすぐ再度アプリを開く」「写真へのアクセス許可など OS ダイアログが閉じられる」といった状況でも「アプリ起動イベント」として計測されてしまうことに注意します。