启用ProGuard后Android项目构建报StackOverflowError问题
问题背景
启用ProGuard后,我的Android项目构建耗时近一小时,最终还抛出了StackOverflowError。以下是相关的错误日志、Gradle配置文件及ProGuard规则文件,求帮忙排查解决这个构建报错问题。
错误日志
Cause: java.lang.StackOverflowError at com.android.build.gradle.shrinker.parser.GrammarActions.method(GrammarActions.java:302) at com.android.build.gradle.shrinker.parser.GrammarActions.fieldOrAnyMember(GrammarActions.java:210) at com.android.build.gradle.shrinker.parser.ProguardParser.member(ProguardParser.java:2280) at com.android.build.gradle.shrinker.parser.ProguardParser.members(ProguardParser.java:1982) at com.android.build.gradle.shrinker.parser.ProguardParser.classSpecification(ProguardParser.java:1599) at com.android.build.gradle.shrinker.parser.ProguardParser.prog(ProguardParser.java:331) at com.android.build.gradle.shrinker.parser.GrammarActions.parse(GrammarActions.java:64) at com.android.build.gradle.shrinker.parser.GrammarActions.include(GrammarActions.java:82) at com.android.build.gradle.shrinker.parser.ProguardParser.prog(ProguardParser.java:316) at com.android.build.gradle.shrinker.parser.GrammarActions.parse(GrammarActions.java:64) at com.android.build.gradle.shrinker.parser.GrammarActions.include(GrammarActions.java:82) //Stacktrace containing repeated elements shortened at com.android.build.gradle.shrinker.parser.GrammarActions.include(GrammarActions.java:82) at com.android.build.gradle.shrinker.parser.ProguardParser.prog(ProguardParser.java:316) at com.android.build.gradle.shrinker.parser.GrammarActions.parse(GrammarActions.java:64) at com.android.build.gradle.shrinker.parser.GrammarActions.include(GrammarActions.java:82)
Gradle配置文件
apply plugin: 'com.android.application' android { compileSdkVersion 27 defaultConfig { applicationId "package_name" minSdkVersion 15 targetSdkVersion 27 versionCode 5 versionName "1.0.4" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "com.android.test.runner.MultiDexTestRunner" multiDexEnabled true } signingConfigs { release { //key info } } dexOptions { javaMaxHeapSize "4g" } buildTypes { release { debuggable false minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debug { debuggable true minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } dataBinding { enabled = true } } dependencies { testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' implementation 'com.android.support.test:runner:1.0.2' implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'com.android.support:multidex:1.0.3' implementation 'com.android.support:design:27.1.1' implementation 'com.android.support:appcompat-v7:27.1.1' implementation 'com.android.support:cardview-v7:27.1.1' implementation 'com.android.support:customtabs:27.1.1' implementation 'com.android.support.constraint:constraint-layout:1.1.0' implementation 'com.google.firebase:firebase-core:16.0.0' implementation 'com.google.firebase:firebase-messaging:17.0.0' implementation 'com.google.firebase:firebase-crash:16.0.0' implementation 'com.google.firebase:firebase-config:16.0.0' implementation 'com.google.android.gms:play-services-location:15.0.1' implementation 'com.google.android.gms:play-services-maps:15.0.1' implementation 'com.google.android.gms:play-services-auth:15.0.1' implementation 'com.squareup.retrofit2:retrofit:2.3.0' implementation 'com.squareup.retrofit2:converter-gson:2.3.0' implementation 'com.google.code.gson:gson:2.8.0' implementation 'com.squareup.okhttp3:logging-interceptor:3.9.1' implementation 'com.squareup.picasso:picasso:2.5.2' implementation ('com.facebook.android:facebook-android-sdk:4.33.0') { exclude module: 'support-compat' } implementation ('com.appyvet:materialrangebar:1.4.1') { exclude module: 'support-compat' } } apply plugin: 'com.google.gms.google-services'
ProGuard规则文件
-keepclassmembers class fqcn.of.javascript.interface.for.webview { public *; } # Uncomment this to preserve the line number information for # debugging stack traces. -include proguard-rules.pro -keepattributes SourceFile,LineNumberTable # If you keep the line number information, uncomment this to # hide the original source file name. -renamesourcefileattribute SourceFile # Proguard rules that are applied to your test apk/code. -ignorewarnings -keepattributes *Annotation* -dontnote junit.framework.** -dontnote junit.runner.** -dontwarn android.test.** -dontwarn android.support.test.** -dontwarn org.junit.** -dontwarn org.hamcrest.** -dontwarn com.squareup.javawriter.JavaWriter # Uncomment this if you use Mockito #-dontwarn org.mockito.** # Support design -dontwarn android.support.design.** -keep class android.support.design.** { *; } -kee
问题分析与解决方案
核心问题定位
从错误日志里重复出现的栈帧就能看出问题所在:ProGuard解析器一直在反复执行include动作——这是因为你的ProGuard规则文件里写了-include proguard-rules.pro,这条命令会让ProGuard无限递归地包含当前文件本身,直接导致解析器陷入死循环,最终触发StackOverflowError,同时因为反复解析同一个文件,构建时间被无限拉长。
另外,你的ProGuard文件最后一行是-kee,这明显是未完成的规则语句,也会引发解析异常。
具体修复步骤
移除循环引用的include语句
打开proguard-rules.pro,直接删除-include proguard-rules.pro这一行。这条语句完全没有存在的必要,反而会引发致命的递归解析问题。补全不完整的ProGuard规则
文件最后一行的-kee是未完成的输入,根据上下文推测应该是-keep开头的规则,比如如果是要保留某个类或成员,补全为完整的语句,例如:-keep class android.support.design.** { *; } # 根据你的实际需求补全规则,比如其他keep类或成员的语句优化Debug构建类型(可选但强烈推荐)
Debug版本通常不需要混淆和资源压缩,这两项操作会大幅增加构建时间,建议修改Gradle配置中的Debug构建类型:debug { debuggable true minifyEnabled false // 关闭混淆 shrinkResources false // 关闭资源压缩 // 如果你不需要Debug混淆,也可以保留proguardFiles配置,但关闭minifyEnabled后它不会生效 }
验证修复效果
完成以上修改后,重新执行构建命令,StackOverflowError应该会立即消失,构建时间也会恢复到正常水平。
内容的提问来源于stack exchange,提问作者Kaushik

