5

我最近將我的Android項目從Eclipse遷移到了Android Studio。Android Studio - Proguard'keep'規則被忽略?

由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 ComponentInfo{com.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 

所以似乎keep規則我在我的proguard-rules.pro f中指定由於無法找到com.example.myapp.SplashActivity類,因此沒有使用該文件。

我檢查了Android Developers ProGuard頁面,它看起來像我已經正確設置了一切,所以我不知道爲什麼它不工作。

任何人都可以建議我需要做什麼才能結束與混淆apk的作品?

+2

謝謝,但我不認爲我有一個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指令。

0

不使用-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

+0

感謝您。我還必須添加'-twtwarn twitter4j。​​*'和'-keep class twitter4j。​​* {*; }來構建應用程序,但在運行時我仍然遇到同樣的問題。我還添加了'-keep public class * extends android.support.v7.app.AppCompatActivity'(SplashActivity是其後代)以防萬一,但這並沒有幫助。 –

+0

我也將我的應用程序的build.gradle文件中的行更改爲'proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),'proguard-rules。親',但這也沒有任何區別。看來我的proguard-rules.pro文件沒有被處理... –

+0

NB - 我執行了一個快速測試(在我的proguard-rules.pro文件中引入了一個語法錯誤,並且當我嘗試生成簽名的APK,所以我知道我的proguard-rules.pro文件正在被讀取。 –