google gson 使用proguard混淆程式碼注意事項
阿新 • • 發佈:2019-01-23
這裡不介紹怎樣開啟程式碼混淆功能。具體方法可以參照:
http://developer.android.com/tools/help/proguard.html
http://proguard.sourceforge.net/#manual/usage.html
主要介紹混淆使用 google gson的程式碼的時候需要注意的問題和解決方法。
在使用Android Studio 自帶的Proguard去混淆程式碼的時候。程式碼混淆可以通過,但是執行的時候出現下面錯誤:
07-13 14:25:41.549 22817-22817/? E/AndroidRuntime﹕ FATAL EXCEPTION: main Process: com.project.mocha_patient, PID: 22817 java.lang.NullPointerException: Attempt to invoke virtual method 'boolean java.lang.String.equals(java.lang.Object)' on a null object reference at com.project.mocha_patient.login.c.a(Unknown Source) at com.project.mocha_patient.network.p.a(Unknown Source) at com.project.mocha_patient.network.p.onPostExecute(Unknown Source) at android.os.AsyncTask.finish(AsyncTask.java:636) at android.os.AsyncTask.access$500(AsyncTask.java:177) at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:653) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:135) at android.app.ActivityThread.main(ActivityThread.java:5254) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
最後定位程式碼位置在於:
除錯程式碼可以顯示obj為非null。但是內部成員都為 nullpublic void ServerResponse(HttpTaskResult ret) { SignResponseData obj = JsonUtils.objectFromJson (ret.getResponesMsg(), SignResponseData.class); if (obj == null){ Toast.makeText(LoginActivity.this, "Server replied the wrong data, please check.", Toast.LENGTH_SHORT).show(); return ; } if (!obj.getStatus().equals(MCSConstants.POST_SUCCESSFUL)){ //異常位置 Toast.makeText(LoginActivity.this, "Server Error: " + obj.getMessage(), Toast.LENGTH_SHORT).show(); return; } .... }
SignResponseData.javapublic final class JsonUtils { private static Gson sGson = new Gson(); public static String jsonStringFromObject(Object object) { return sGson.toJson(object); } public static <T> T objectFromJson(String json, Class<T> clz) { try { return sGson.fromJson(json, clz); }catch (Exception e){ e.printStackTrace(); } return null; } public static<T> T objectFromJson(InputStream in, Class<T> clz) { try { JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8")); T object = sGson.fromJson(reader, clz); reader.close(); return object; } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } }
public final class SignResponseData {
private String regType;
private String token;
private String message;
private String status;
...
}
分析原因:
由於gson使用對映的方法找到SignResponseData.class中對應的成員變數名稱,將json格式的的欄位對應的值賦值給SignResponseData類中對應的成員變數。
但是由於經過proguard後 SignResponseData內部的成員變數名稱發生了變化。已經無法找到json欄位中對應的類成員變數。所以導致所有生成的SignResponseData成員變數值都為null 。
解決方法 1:
在proguard-rules.pro中加入下面規則。 對SignResponseData.java的所有private 物件不進行obfuscation。
##---------------Begin: proguard configuration for Gson ----------
-keep public class com.google.gson.**
-keep public class com.google.gson.** {public private protected *;}
-keepattributes Signature
-keepattributes *Annotation*
-keep public class com.project.mocha_patient.login.SignResponseData { private *; }
##---------------End: proguard configuration for Gson ----------
解決方法2:
在SignResponseData.java中,將所有被gson使用的變數都加下面宣告,這樣gson就可以識別對應的變數。
@SerializedName("name")
public final class SignResponseData {
@SerializedName("regType")
private String regType;
@SerializedName("token")
private String token;
@SerializedName("message")
private String message;
@SerializedName("status")
private String status;
...
}
如果要保留的類是內部類。可以使用下面宣告:
-keep class com.project.mocha_patient.login.FindForgotInfoActivity$ForgetResponse {*;}
-keep class com.project.mocha_patient.account_setting.ChangePasswordActivity$ChangePasswordResponse {*;}