経緯
APIからJSONを受け取って、Gsonを使用しDataクラスにパースしてもらっていました。
開発中は問題なく動いていましたが、いざ完了したらなぜかパースしたDataクラスを使用している機能が急に動かなくなりました。うまくAPIから引けなかった時と同じ挙動でした。困った。
Gsonとは
Googleさんが提供している、JSONとオブジェクトを相互変換できるライブラリです。
細かい部分は省略しますが、toJson()、fromJson()なんかを使用してサクッと変換してくれるので大変重宝しています。
本題(原因)
タイトルにも書いたので結論から。
ProGuardが有効になったため、クラス名やフィールド名がなんの意味もないてきとうな文字列に変換(難読化)され、
パースしようにもJSONのキー名と一致しなくなり失敗、みたいです。
無知のため調査は難航し、
・API側が変わったのか確認してみたり、
・気づかないうちにフィールド名を変更してしまっていないか必死に差分確認したり、
・このご時世なのでネットワークの問題か?VPNか?
など見当違いも甚だしい確認をひたすらにしていました・・・。
実装
data class SampleData(
val id: String,
val name: String,
val hoge: String
)
こんなクラスがあったとして、JSONはこんな感じ
{"id":"111","name":"test","hoge":"hoge"}
val hogefuga = Gson().fromJson(jsonStr, SampleData::class.java)
みたいにするとhogefugaはjsonStrからSampleDataにパースされたものが入ります。
解決方法
難読化された場合、
上記SampleDataで言うと、idがa、nameがb、hogeがc みたいに(実際はどうなるのかわかりませんが)変わってしまうので
JSONのキーと合うものがないじゃん、ということでうまくいかなかった、と。
解決方法その1
SerializedNameを付与してあげればGson側に認識させることができます。
data class SampleData(
@SerializedName("id")
val id: String,
@SerializedName("name")
val name: String,
@SerializedName("hoge")
val hoge: String
)
SerializedNameを付与しておけば変数名はなんでも大丈夫になってしまうので注意。
解決方法その2
難読化の対象外とする
-keep class hoge.fuga.〇〇
みたいにすれば名称を見失うことはないですね。
-keepnames class hoge.fuga.〇〇
みたいなのもあるそうです。
ProGuardはよくわからないのですが、いくつかオプションパターンがあるようです。
終わりに
冷静に考えてみればうまくいかない原因を絞り込むことはできたように思います。
難読化は全く頭にありませんでしたが、今後は真っ先に疑えるようそのあたりの知識もつけていきたいです。
ProGuardも勉強しなくては。