一些在升级 Gradle 插件时可能遇到的问题。
3.6.0+ 测试代码:
1 2 3 4 5 6 7 8 public class User { private String name; public String getName () { return name; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public void test () throws Exception { final String name = "admin" ; Assert.assertEquals(name, createUserWithName(name).getName()); } private User createUserWithName (String name) throws IllegalAccessException { User user = new User (); Field[] fields = user.getClass().getDeclaredFields(); if (fields.length > 0 ) { Field field = fields[0 ]; field.setAccessible(true ); field.set(user, name); } return user; }
升级之前的环境:
1 2 3 4 5 6 7 8 9 10 dependencies { classpath "com.android.tools.build:gradle:3.5.4" } buildTypes { debug { minifyEnabled true proguardFiles getDefaultProguardFile ('proguard-android-optimize.txt' ) , 'proguard-rules.pro' } }
这时运行上面的测试代码是没有问题的,接下来升级一下 Gradle 插件版本,其它环境不变:
1 2 3 dependencies { classpath "com.android.tools.build:gradle:3.6.0" }
运行结果:
1 2 3 4 5 6 7 com.android.example E/AndroidRuntime: FATAL EXCEPTION: main Process: com.android.example, PID: 19544 java.lang.AssertionError: expected:<admin> but was:<null> at c.a.a.a(Assert.java:89) at c.a.a.b(Assert.java:835) at c.a.a.a(Assert.java:120) at c.a.a.a(Assert.java:146)
为什么运行结果是 null ?,在 Android Studio 中打开 app/build/outputs/apk/debug/app-debug.apk
,看一下 dex 中混淆后的 User
类反编译出来的 smali:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 .class public Lcom/android/example/a; .super Ljava/lang/Object; .source "User.java" .method public constructor <init>()V .registers 1 .line 3 invoke-direct {p0}, Ljava/lang/Object; -><init>()V return-void .end method .method public a()Ljava/lang/String; .registers 2 .line 8 const/4 v0, 0x0 return-object v0 .end method
可以看到 name
这个属性直接被优化移除了,getName
虽然还在,但是直接返回了 null
。
解决办法:
添加混淆规则
1 -keepclassmembers, allowobfuscation class com.android.example.User {*;}
回退 Gradle 插件版本
1 2 3 dependencies { classpath "com.android.tools.build:gradle:3.5.4" }
参考