Android Studio - Proguard“保留”规则被忽略?
Posted
技术标签:
【中文标题】Android Studio - Proguard“保留”规则被忽略?【英文标题】:Android Studio - Proguard 'keep' rules being ignored? 【发布时间】:2016-04-10 13:18:55 【问题描述】:我最近将我的 android 项目从 Eclipse 迁移到了 Android Studio。
由 Android Studio 创建的应用的调试版本在设备上运行良好,但发布版本在启动时崩溃。
这是我应用的build.gradle
文件:
apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'
android
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig
applicationId "com.example.myapp"
minSdkVersion 15
targetSdkVersion 23
versionCode 49
versionName "1.3.1"
buildTypes
release
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
packagingOptions
//exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/NOTICE'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
dependencies
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.android.support:design:23.1.1'
compile 'com.android.support:support-v13:23.1.1'
compile 'org.apache.httpcomponents:httpmime:4.2.3'
compile 'org.twitter4j:twitter4j-core:4.0.2'
compile 'com.facebook.android:facebook-android-sdk:4.8.2'
compile 'ch.acra:acra:4.7.0'
compile 'com.google.android.gms:play-services-analytics:8.3.0'
compile 'com.google.android.gms:play-services-ads:8.3.0'
compile 'com.google.android.gms:play-services-plus:8.3.0'
//compile 'com.google.android.gms:play-services:8.3.0'
compile 'com.google.android.gms:play-services-gcm:8.3.0'
这是我的proguard-rules.pro
文件:
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in P:\Program Files\Android\sdk/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the javascript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview
# public *;
#
#
# My Classes - start
#
-keep public class com.example.myapp.SplashActivity
-keep public class com.example.myapp.FragmentActivityWithListener
-keep public class com.example.myapp.AbstractHelpActivity
-keep public class com.example.myapp.GetContentFromWebTask$CompletedListener
# Don't rename the MenuBuilder filename as this is referenced in our AbstractHelpActivity.java file
-keep public class android.support.v7.internal.view.menu.MenuBuilder
-keep class android.support.v7.widget.ShareActionProvider *;
#
# My Classes - end
#
#
# Twitter library - start
#
-dontwarn twitter4j.**
-keep class twitter4j.** *;
#
# Twitter library - end
#
#
# Google Play Service library - start
#
-keep class * extends java.util.ListResourceBundle
protected Object[][] getContents();
-keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable
public static final *** NULL;
-keepnames @com.google.android.gms.common.annotation.KeepName class *
-keepclassmembernames class *
@com.google.android.gms.common.annotation.KeepName *;
-keepnames class * implements android.os.Parcelable
public static final ** CREATOR;
#
# Google Play Service library - end
#
#
# ACRA - start
#
#ACRA specifics
# Restore some Source file names and restore approximate line numbers in the stack traces,
# otherwise the stack traces are pretty useless
-keepattributes SourceFile,LineNumberTable
# ACRA needs "annotations" so add this...
# Note: This may already be defined in the default "proguard-android-optimize.txt"
# file in the SDK. If it is, then you don't need to duplicate it. See your
# "project.properties" file to get the path to the default "proguard-android-optimize.txt".
-keepattributes *Annotation*
# keep this class so that logging will show 'ACRA' and not a obfuscated name like 'a'.
# Note: if you are removing log messages elsewhere in this file then this isn't necessary
-keep class org.acra.ACRA
*;
# keep this around for some enums that ACRA needs
-keep class org.acra.ReportingInteractionMode
*;
-keepnames class org.acra.sender.HttpSender$**
*;
-keepnames class org.acra.ReportField
*;
# keep this otherwise it is removed by ProGuard
-keep public class org.acra.ErrorReporter
public void addCustomData(java.lang.String,java.lang.String);
public void putCustomData(java.lang.String,java.lang.String);
public void removeCustomData(java.lang.String);
# keep this otherwise it is removed by ProGuard
-keep public class org.acra.ErrorReporter
public void handleSilentException(java.lang.Throwable);
#
# ACRA - end
#
#
# Facebook - start
#
-keep class com.facebook.** *;
-keepattributes Signature
#
# Facebook - end
#
这是堆栈跟踪:
01-06 11:48:58.313 27667-27667/? E/ACRA: ACRA caught a RuntimeException for com.example.myapp
java.lang.RuntimeException: Unable to instantiate activity ComponentInfocom.example.myapp/com.example.myapp.SplashActivity: java.lang.ClassNotFoundException: Didn't find class "com.example.myapp.SplashActivity" on path: DexPathList[[zip file "/data/app/com.example.myapp-1/base.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2650)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2873)
at android.app.ActivityThread.access$900(ActivityThread.java:181)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1482)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:6145)
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:1399)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
Caused by: java.lang.ClassNotFoundException: Didn't find class "com.example.myapp.SplashActivity" on path: DexPathList[[zip file "/data/app/com.example.myapp-1/base.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
at java.lang.ClassLoader.loadClass(ClassLoader.java:469)
at android.app.Instrumentation.newActivity(Instrumentation.java:1079)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2640)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2873)
at android.app.ActivityThread.access$900(ActivityThread.java:181)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1482)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:6145)
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:1399)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
Suppressed: java.lang.NoClassDefFoundError: com.example.myapp.SplashActivity
at dalvik.system.DexFile.defineClassNative(Native Method)
at dalvik.system.DexFile.defineClass(DexFile.java:226)
at dalvik.system.DexFile.loadClassBinaryName(DexFile.java:219)
at dalvik.system.DexPathList.findClass(DexPathList.java:321)
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:54)
... 14 more
Suppressed: java.lang.ClassNotFoundException: com.example.myapp.SplashActivity
at java.lang.Class.classForName(Native Method)
at java.lang.BootClassLoader.findClass(ClassLoader.java:781)
at java.lang.BootClassLoader.loadClass(ClassLoader.java:841)
at java.lang.ClassLoader.loadClass(ClassLoader.java:504)
... 13 more
Caused by: java.lang.NoClassDefFoundError: Class not found using the boot class loader; no stack available
01-06 11:48:58.363 27667-27667/? E/ACRA: Not adding buildConfig to log. Class Not found : com.example.myapp.BuildConfig. Please configure 'buildConfigClass' in your ACRA config
01-06 11:48:58.453 27667-27691/? E/ACRA: ACRA caught a InternalError for com.example.myapp
java.lang.InternalError: Thread starting during runtime shutdown
at java.lang.Thread.nativeCreate(Native Method)
at java.lang.Thread.start(Thread.java:1063)
at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:920)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1336)
at com.android.okhttp.ConnectionPool.get(ConnectionPool.java:211)
at com.android.okhttp.internal.http.RouteSelector.next(RouteSelector.java:109)
at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:368)
at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:296)
at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:399)
at com.android.okhttp.internal.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:110)
at org.acra.e.b.a(HttpRequest.java:122)
at org.acra.sender.HttpSender.a(HttpSender.java:245)
at org.acra.af.a(SendWorker.java:181)
at org.acra.af.a(SendWorker.java:140)
at org.acra.af.run(SendWorker.java:76)
01-06 11:48:58.483 27667-27691/? E/ACRA: Not adding buildConfig to log. Class Not found : com.example.myapp.BuildConfig. Please configure 'buildConfigClass' in your ACRA config
01-06 11:48:58.503 27667-27691/? E/AndroidRuntime: FATAL EXCEPTION: Thread-2863
Process: com.example.myapp, PID: 27667
java.lang.InternalError: Thread starting during runtime shutdown
at java.lang.Thread.nativeCreate(Native Method)
at java.lang.Thread.start(Thread.java:1063)
at java.util.concurrent.ThreadPoolExecutor.addWorker(ThreadPoolExecutor.java:920)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1336)
at com.android.okhttp.ConnectionPool.get(ConnectionPool.java:211)
at com.android.okhttp.internal.http.RouteSelector.next(RouteSelector.java:109)
at com.android.okhttp.internal.http.HttpEngine.connect(HttpEngine.java:368)
at com.android.okhttp.internal.http.HttpEngine.sendRequest(HttpEngine.java:296)
at com.android.okhttp.internal.http.HttpURLConnectionImpl.execute(HttpURLConnectionImpl.java:399)
at com.android.okhttp.internal.http.HttpURLConnectionImpl.connect(HttpURLConnectionImpl.java:110)
at org.acra.e.b.a(HttpRequest.java:122)
at org.acra.sender.HttpSender.a(HttpSender.java:245)
at org.acra.af.a(SendWorker.java:181)
at org.acra.af.a(SendWorker.java:140)
at org.acra.af.run(SendWorker.java:76)
01-06 11:48:58.503 1038-1476/? W/ActivityManager: Force finishing activity com.example.myapp/.SplashActivity
看来我在proguard-rules.pro
文件中指定的keep
规则没有被使用,因为找不到com.example.myapp.SplashActivity
类。
我检查了Android Developers ProGuard 页面,看起来我已经正确设置了所有内容,所以我不知道为什么它不起作用。
任何人都可以建议我需要做什么才能最终得到一个有效的混淆 apk 吗?
【问题讨论】:
谢谢,但我不认为我有 DexIndexOverflowException 问题(?) 【参考方案1】:我发现了问题。它在我项目的 build.gradle 文件中:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript
repositories
jcenter() // This is the default repo
mavenCentral() // This is the Maven Central repo
dependencies
classpath 'com.android.tools.build:gradle:1.3.0'
classpath 'com.google.gms:google-services:1.5.0-beta2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
allprojects
repositories
jcenter() // This is the default repo
mavenCentral() // This is the Maven Central repo
task clean(type: Delete)
delete rootProject.buildDir
解决方案是将classpath 'com.android.tools.build:gradle:1.3.0'
更改为classpath 'com.android.tools.build:gradle:1.5.0'
。
(我通过创建一个新的测试项目并比较各个 build.gradle 文件中的值发现了这一点。)
顺便说一句,我的proguard-rules.pro
文件的内容现在只是...
#
# Twitter - start
#
-dontwarn twitter4j.**
-keep class twitter4j.** *;
#
# Twitter - end
#
#
# Support library / ShareActionProvider - start
#
-keep class android.support.v7.internal.** *;
-keep interface android.support.v7.internal.** *;
-keep class android.support.v7.** *;
-keep interface android.support.v7.** *;
#
# Support library / ShareActionProvider - start
#
#
# ACRA - start
#
#ACRA specifics
# Restore some Source file names and restore approximate line numbers in the stack traces,
# otherwise the stack traces are pretty useless
-keepattributes SourceFile,LineNumberTable
# ACRA needs "annotations" so add this...
# Note: This may already be defined in the default "proguard-android-optimize.txt"
# file in the SDK. If it is, then you don't need to duplicate it. See your
# "project.properties" file to get the path to the default "proguard-android-optimize.txt".
-keepattributes *Annotation*
# keep this class so that logging will show 'ACRA' and not a obfuscated name like 'a'.
# Note: if you are removing log messages elsewhere in this file then this isn't necessary
-keep class org.acra.ACRA
*;
# keep this around for some enums that ACRA needs
-keep class org.acra.ReportingInteractionMode
*;
-keepnames class org.acra.sender.HttpSender$**
*;
-keepnames class org.acra.ReportField
*;
# keep this otherwise it is removed by ProGuard
-keep public class org.acra.ErrorReporter
public void addCustomData(java.lang.String,java.lang.String);
public void putCustomData(java.lang.String,java.lang.String);
public void removeCustomData(java.lang.String);
# keep this otherwise it is removed by ProGuard
-keep public class org.acra.ErrorReporter
public void handleSilentException(java.lang.Throwable);
#
# ACRA - end
#
...所以我不需要很多旧指令或 Dhawal 在他的回答中建议的指令。
注意 - 我知道从 ACRA 4.8 起不再需要 ACRA 指令。
【讨论】:
【参考方案2】:不要使用-keep public class com.example.myapp.SplashActivity
删除 proguard 文件的所有行并使用以下方式,使用此 proguard 不会更改您的应用程序的类名称(添加以下行取决于您的要求,例如您的应用程序没有内容提供程序,然后删除它行)。
-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider
-keep public class * extends android.app.backup.BackupAgentHelper
-keep public class * extends android.preference.Preference
-keep public class com.android.vending.licensing.ILicensingService
-keep class org.xmlpull.v1.** *;
-dontnote com.android.vending.licensing.ILicensingService
阅读:how to use proguard in android app
【讨论】:
谢谢。我还必须添加-dontwarn twitter4j.**
和-keep class twitter4j.** *;
才能构建应用程序,但在运行时我仍然遇到同样的问题。为了以防万一,我还添加了-keep public class * extends android.support.v7.app.AppCompatActivity
(SplashActivity 是它的直接后代),但这并没有帮助。
我还将应用程序的 build.gradle 文件中的行更改为 proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
但这也没有任何区别。看来我的 proguard-rules.pro 文件没有被处理...
NB - 我执行了一个快速测试(在我的 proguard-rules.pro 文件中引入了一个语法错误,并在我尝试生成签名的 APK 时看到了错误,所以我知道我的 proguard-rules .pro 文件肯定正在被读取。以上是关于Android Studio - Proguard“保留”规则被忽略?的主要内容,如果未能解决你的问题,请参考以下文章
如何在android studio中启用proguard? [复制]
Android Studio & ProGuard:无法解析符号 getDefaultProguardFile?
Proguard 在 android Studio 中开箱即用?这是啥意思?
使用 Android Studio 签署 APK 时出现 Proguard 错误