経緯
先日、とあるゲームアプリでユーザー情報が消えているというバグ報告をユーザーから受けました。
ユーザー情報自体はKeychainに保存して、Keychainに特定の情報が無ければ初期化処理をしていました。
これらの処理に問題は無さそうだったので迷宮入りしかけましたが、
報告を受けた症状と残っていた僅かなログを元に原因を推測し、
アプリ起動時にKeychainの読み込みに失敗している可能性に辿り着きました。
そこで再現する条件や対処方法をいろいろと実験したので、ここにメモ書きを残します。
症状
- (特に)iOS9でアプリ起動時にKeychainから情報を取得しようとすると、極めて稀に
-34018=errSecMissingEntitlement
のエラーコードが返ってくる - 起動から数秒おいて取得する処理に変えても改善せず
- 成功するまでリトライ処理に変えたら、無限ループ
症状としては上記のような感じです。
再現しないんじゃないかってぐらい再現しないので、実装やKeychainの使い方に問題は無さそうです。
しかしながら簡単に再現しないとデバッグに困るので、何とか再現しやすい状態を探しました・・・
お手軽再現方法
- アプリで起動時にKeychainから取得する前に、600MBほどメモリを確保するような処理を仕込む
- 再現率に影響したり、アプリごと落ちたりするので、環境によって調整して下さい
- Safariで適当にブラウジング(重要)
- アプリを開くと、数回〜10回に1回ぐらいの頻度で再現
Safariでブラウジングがどういう影響を及ぼしているかはわからないですが、
するのとしないとでは再現率が圧倒的に違うので、多少面倒でもした方がいいです。
対処法
-
errSecItemNotFound
以外の想定しないエラーが返ってきたら、アプリ再起動を強制する - Keychainじゃない場所にバックアップし、矛盾がないかチェックする
症状に書いてあるように、リトライとかは効果ありませんでした。
なので考えうる対処法はこれぐらいじゃないでしょうか?
以前からKeychain周りで信頼性に関してや、バグがいろいろと報告されていたようで、Apple側も認識していると思います。
もし何かしらの詳しい情報をお持ちの方がいらっしゃいましたら、ぜひコメントなどで教えて下さい。
注意:Keychainの挙動は謎も多く、かなり手探りで調査したので、上記の情報に間違いや不備があるかもしれないことをご容赦下さい。