はじめに
先日リリース前に地雷を踏みかけ、そういえば以前にも似たような地雷を踏んだのを思い出したので書きました。
事例
ケース1
発生した事象
単一Activity上で複数Fragment(それぞれA,B,C,Dとする)を切り替えるアプリを作っていた際に、BottomNavigationで切り替えるもReleaseビルドでのみDのFragmentに切り替えようとしているにも関わらずBのフラグメントが表示されてしまった。
原因
FragmentのtagにそのFragmentのClass.simpleNameを利用していたこと。
debugビルドではProguardが無効なので問題なくユニークな文字列として機能してくれたが、releaseビルドにおいて難読化された結果下記のようなマッピングとなっていた。
- A -> a.a
- B -> b.b
- C -> c.c
- D -> d.b
ここでnameで参照していればBとDは別のものだと認識できたもの、のsimpleNameを参照するとそれぞれbとしか見做されず、Fragment切り替えの際にfindByTagするとbとしてしか参照できずにBとDが同一視されてしまっていた。
対応策
- リリース前だったことと、次の事例とは異なりFragmentの識別だけ出来ればいいのでsimpleNameではなくnameを参照するようにコードを変更したところReleaseビルドでも問題なく動くようになった
ケース2
発生した事象
アプリをアップデートすると1つ前のバージョンで設定したアプリ内の設定項目が変更されてしまう。
原因
SharedPreferencesのkeyに利用する文字列をベタ書きにせずClass.nameで生成していたこと。
simpleNameではなくnameなのでユニークなkeyにはなるものの、アップデートによるクラス数の増減があったことによってmappingが変わってしまい保存時のkeyで参照できなくなってしまっていた。
例) アップデートに伴いパッケージbにMというクラスが追加された。
Ver 1.0.0
- a/A -> a.a
- b/N -> b.a
Ver 1.0.1
- a/A -> a.a
- b/M -> b.a
- b/N -> b.b
対応策
- それ以降はSharedPreferencesのkeyはベタ書きで定義、利用することになった
- なお、このときはアプリはリリース済みだったため既存ユーザが保存した設定のkeyは難読化されたクラス名のままであった
- 力技でSharedPreferencesのwrapperクラスに自前で新旧の難読化されたクラス名のmapping処理を書いて変換していた記憶(当時この件は先輩が対応してくださっていてうろ覚えです
)
- 力技でSharedPreferencesのwrapperクラスに自前で新旧の難読化されたクラス名のmapping処理を書いて変換していた記憶(当時この件は先輩が対応してくださっていてうろ覚えです
おわりに
simpleName, nameはデバッグLogCatでの利用くらいに留めておいたほうが無難そうです。
まぁAndroidStudio先生にも怒られるのでTimber使えばsimpleNameを参照する必要もないのですが。
もし使う場合はProguardがかかっても問題ない内容かどうかを判断してから使うようにしないと危険なので気をつけましょう(自戒)
simpleName, nameに関する別の事例をお持ちの方はぜひ教えてくださいませ。