天天看點

proguard如何會導緻json解析失效?1. 楔子2. 一開始3. 後來,他們開啟了proguard4. 問題所在5. 解決一些連結

1. 楔子

json資料的解析是這個星球上99%的Android程式猿都會遇到的問題,而其中的大部分,都會使用

Gson

,故事就是從這裡發生……

2. 一開始

通常json資料是從服務端取的,典型的一段json字元串如下:

{ "name": "老張","age": }
           

一般程式猿們會在本地寫一個實體類與之對應,比如資料類

Person

:

public class Person { 
    private String name;
    private int age;
    //……省略中間get/set
    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + '}';
    }
}
           

然後就可以愉快地使用Gson來進行解析啦,像這樣:

Person someone = new Gson().fromJson(jsonString, Person.class);
Log.d("TAG", "someone: " + someone.toString());
           

一切順利,程式猿們得到輸出:

Person{ name=’老張’,age=18}

然後他們就愉快地下班去玩耍了。

3. 後來,他們開啟了proguard

意外就是從這裡開始的,開啟了proguard之後,debug運作的程式一切如常,但是proguard之後輸入的apk包,在安裝之後的輸出變成了這樣:

Person{ name=’null’,age=0}

——解析出錯了。

(算了,我編不下去了,從現在開始使用第一人稱……)

4. 問題所在

經過反複排查,發現問題就是由proguard引起的。

我們知道,proguard的過程會執行壓縮、混淆、去除無用代碼等操作。而其中的混淆、去除無用代碼的過程,對于使用了

反射

技術的代碼來說,都是有可能受到影響的。

不幸的是:Gson.fromJson()就是基于反射來實作的。

通過反編譯apk包,發現我們寫的Person類,在沒有被保護的情況下,會被proguard成類似這個樣子的:

proguard如何會導緻json解析失效?1. 楔子2. 一開始3. 後來,他們開啟了proguard4. 問題所在5. 解決一些連結

可以看到,類名、字段名都改成了a/b這樣的名字。

這樣在使用Gson的時候,它嘗試去序列化的字段就會變成了a/b,而不是之前的name/age了。

——那還反射個毛啊!

5. 解決

知道問題了,自然也就很好解決了。

方案是在proguard規則中,把Person類給保護起來。

5.1 proguard檔案編輯

proguard-rules.pro

檔案中添加規則(也可能是其他檔案,具體見gradle檔案中的定義),把資料類保護起來即可。

具體來說,可以直接保護目前類:

-keep class com.xxx.beans.Person {*;}

也可以保護整個包:

-keep class com.xxx.beans.* {*;}

還可以給Person添加一個對

Serializable

的實作,然後保護所有的

Serializable

-keep class * implements java.io.Serializable {*; }

5.2 @Keep注解

另外,項目如果引用了

注解支援庫

,那麼給Person類加上

@Keep

的注解也可以防止它被混淆。

@Keep
public class Person {/*省略*/}
           

OK,加上保護之後,重新打包。

反編譯這時的apk,可以看到,字段Person類沒有再被混淆了:

proguard如何會導緻json解析失效?1. 楔子2. 一開始3. 後來,他們開啟了proguard4. 問題所在5. 解決一些連結

然後安裝、運作,果然一切正常了。

Person{ name=’老張’,age=18}

完美。

一些連結

工具:https://github.com/google/android-classyshark

壓縮代碼和資源:https://developer.android.com/studio/build/shrink-code.html

proguard相關問題排查:https://stuff.mit.edu/afs/sipb/project/android/sdk/android-sdk-linux/tools/proguard/docs/index.html#manual/troubleshooting.html

關于作者:https://github.com/barryhappy