3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Class.getSimpleName()の罠

Posted at

学び

Android開発において、SimpleNameは使うべきではなさそう。

背景

SimpleNameを使った実装で予期せぬ動作を経験しました。

全く違うクラス名にも関わらず、同一のSimpleNameになっていたのです。
例えば、下記のコードが true になるのです。

if (MainFragment.simpleName == SubFragment.simpleName) {
    // "MainFragment" と "SubFragment" の比較になることを期待したので、
    // falseを期待しているのに、trueになる場合がある
}

ちなみに、私の環境ではdebugビルドでは false になるのに、
releaseビルドでは true になりました。

勘のいい人はわかったかもしれませんね。

何が起きたのか

難読化。ProGuardの仕業。
上記の例では、MainFragmentSubFragment が別のパッケージだった場合に、
難読化されて同一のクラス名に置き換わる可能性があります。

初期設定のProGuardの設定では、
パッケージ内のクラス名はアルファベット順に置き換わります。

例えば、下記の二つのクラスは、このように変換されます。
com.yoshinori.sandbox.main.MainFragmentb.b.a.a.a
com.yoshinori.sandbox.sub.SubFragmentb.b.a.b.a

このように変換された時の SimpleName は、両方とも a です。
元々のクラス名は全然違うのに、難読化後は同一のクラス名として処理されてしまうのです。
当たり前のようで、気付きにくいミスです。

どうやって対応すれば良いのか

SimpleName ではなくて Name を使用する。

name は、パッケージ名 + クラス名です。
難読化前なら com.yoshinori.sandbox.main.MainFragment となります。
これであれば、難読化後であっても、同一になることはありません。

if (MainFragment.name == SubFragment.name) {
    // 常にfalseになる
}

終わりに

もし SimpleName を使用している場合、本当に問題ないか確認してみてください。
基本的に普段の実装時にはProGuardは無効にしていると思います。

ですので、リリース直前で気づくことになったり、
最悪の場合は不具合に気付かずストアリリースされちゃいます。
怖いですね。

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?