学び
Android開発において、SimpleNameは使うべきではなさそう。
背景
SimpleNameを使った実装で予期せぬ動作を経験しました。
全く違うクラス名にも関わらず、同一のSimpleNameになっていたのです。
例えば、下記のコードが true
になるのです。
if (MainFragment.simpleName == SubFragment.simpleName) {
// "MainFragment" と "SubFragment" の比較になることを期待したので、
// falseを期待しているのに、trueになる場合がある
}
ちなみに、私の環境ではdebugビルドでは false
になるのに、
releaseビルドでは true
になりました。
勘のいい人はわかったかもしれませんね。
何が起きたのか
難読化。ProGuardの仕業。
上記の例では、MainFragment
と SubFragment
が別のパッケージだった場合に、
難読化されて同一のクラス名に置き換わる可能性があります。
初期設定のProGuardの設定では、
パッケージ内のクラス名はアルファベット順に置き換わります。
例えば、下記の二つのクラスは、このように変換されます。
com.yoshinori.sandbox.main.MainFragment
→ b.b.a.a.a
com.yoshinori.sandbox.sub.SubFragment
→ b.b.a.b.a
このように変換された時の SimpleName
は、両方とも a
です。
元々のクラス名は全然違うのに、難読化後は同一のクラス名として処理されてしまうのです。
当たり前のようで、気付きにくいミスです。
どうやって対応すれば良いのか
SimpleName
ではなくて Name
を使用する。
name
は、パッケージ名 + クラス名です。
難読化前なら com.yoshinori.sandbox.main.MainFragment
となります。
これであれば、難読化後であっても、同一になることはありません。
if (MainFragment.name == SubFragment.name) {
// 常にfalseになる
}
終わりに
もし SimpleName
を使用している場合、本当に問題ないか確認してみてください。
基本的に普段の実装時にはProGuardは無効にしていると思います。
ですので、リリース直前で気づくことになったり、
最悪の場合は不具合に気付かずストアリリースされちゃいます。
怖いですね。