如何修复SharedPreferences中Gson解析ProGuard混淆后的变量名错乱问题
解决Gson解析混淆旧数据的问题
核心原因
之前开启ProGuard时未保护WaterModel的字段,导致序列化到SharedPreferences的JSON用了混淆后的a/b/c/d作为键;现在加了keep规则后,Gson解析时会用原始字段名id/date/waterMl/waterPercent匹配,自然对应不上,抛出解析异常。
解决方案
1. 给POJO字段添加多别名兼容
用Gson的@SerializedName注解,给每个字段同时标注原始名称和混淆后的别名,让Gson能识别两种键名:
import com.google.gson.annotations.SerializedName; public class WaterModel { @SerializedName(value = "id", alternate = {"a"}) private int id; @SerializedName(value = "date", alternate = {"b"}) private String date; @SerializedName(value = "waterMl", alternate = {"c"}) private int waterMl; @SerializedName(value = "waterPercent", alternate = {"d"}) private float waterPercent; // 保留原有的getter/setter方法 public int getId() { return id; } public void setId(int id) { this.id = id; } public String getDate() { return date; } public void setDate(String date) { this.date = date; } public int getWaterMl() { return waterMl; } public void setWaterMl(int waterMl) { this.waterMl = waterMl; } public float getWaterPercent() { return waterPercent; } public void setWaterPercent(float waterPercent) { this.waterPercent = waterPercent; } }
这样Gson解析时,不管JSON里是a还是id,都会映射到id字段,旧数据就能正常解析了。
2. 迁移旧数据到未混淆格式
解析成功后,把数据重新用未混淆的字段名序列化,存回SharedPreferences,避免后续一直兼容旧格式:
Gson gson = new Gson(); String oldJson = sharedPreferences.getString(WATER_LIST, null); Type type = new TypeToken<List<WaterModel>>() {}.getType(); List<WaterModel> modelList = gson.fromJson(oldJson, type); // 重新序列化未混淆的JSON String newJson = gson.toJson(modelList); // 存回SharedPreferences sharedPreferences.edit().putString(WATER_LIST, newJson).apply();
执行一次后,SP里的JSON就会变成{"id":1, "date":"20/07/2022"...}这种格式,后续就不需要再兼容旧别名了(后续版本可以去掉alternate参数)。
3. 确认ProGuard规则生效
确保你的ProGuard规则已经正确保护了WaterModel,避免后续再出现字段混淆:
- 方法一:在ProGuard配置文件中添加规则:
-keep class com.your.package.name.WaterModel { *; }
- 方法二:直接在
WaterModel类上添加@Keep注解(需导入androidx.annotation.Keep或android.support.annotation.Keep):
import androidx.annotation.Keep; @Keep public class WaterModel { // ...字段和方法 }
额外注意
如果后续还有其他POJO类需要序列化,一定要提前配置ProGuard保护,或者用@Keep/@SerializedName固定字段名,避免再次出现类似问题。
内容的提问来源于stack exchange,提问作者user18504539
相关产品推荐
相关产品推荐

