为什么我在使用Proguard时从Play Services lib获取ClassNotFoundException?

时间:2016-09-01 18:59:12

标签: google-play-services proguard

我刚刚在我的构建中启用了ProGuard,现在我得到了

java.lang.ClassNotFoundException: Didn't find class "com.google.android.gms.chimera.GmsModuleInitializer" on path: DexPathList[[zip file "/system/app/PlayGames.apk"],nativeLibraryDirectories=[/vendor/lib, /system/lib]]

文档说我需要将所有使用Proguard和Play服务的内容包含在Android Gradle插件中:

  

注意:ProGuard指令包含在Play服务客户端中   库以保留所需的类。 Android插件   Gradle会自动将ProGuard配置文件附加到AAR中   (Android ARchive)包并将该包附加到您的ProGuard   组态。在项目创建期间,Android Studio会自动生成   创建ProGuard配置文件和build.gradle属性   用于ProGuard。要在Android Studio中使用ProGuard,您必须启用   build.gradle buildTypes中的ProGuard设置。更多   有关信息,请参阅ProGuard指南。

这是我的app模块build.gradle文件的重要部分:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.3"
    defaultConfig {
        ...
    }
    ...
    buildTypes {
        ...{
            applicationIdSuffix ".debug"
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'),
                    'proguard-rules.pro'
        }
    }
}


dependencies {
    ...

    //google play services
    compile 'com.google.android.gms:play-services-gcm:8.4.0'
    compile 'com.google.android.gms:play-services-analytics:8.4.0'
    compile 'com.google.android.gms:play-services-location:8.4.0'
}

这是我的顶级build.gradle文件:

buildscript {
    repositories {
        jcenter()
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.1.2'
    }
}

allprojects {
    repositories {
        jcenter()
        mavenCentral()
    }
}

我错过了什么?

2 个答案:

答案 0 :(得分:6)

ClassNotFoundException通常在应用程序尝试通过其字符串名称加载类时发生,但是找不到具有指定名称的类的定义。

通过此forum,您可以通过添加com.google.android.gms.** { *; }来解决此问题。

  

只需添加到您的proguard-project.txt:

     
      
  • keep class com.google.android.gms。** {*; }
  •   
  • dontwarn com.google.android.gms。**
  •   

您还可以在此SO question中查看建议的评论。

  

Google Play服务aars包含带有必要条款的proguard.txt。因此,设置不应该是必要的。您可以调查ProGuard输出文件中的片段发生了什么。检查app / build / output / mapping / {buildVariant} /usage.txt和mapping.txt。应该在其中一个中提到该片段。

希望这有帮助!

答案 1 :(得分:0)

我知道这是一篇相当老的帖子,但我想强调以下内容,如果它在未来对某人有所帮助。

就像@abielita 提到的那样,ClassNotFoundException 是由未处理的反射案例引起的。

当使用广泛的 -keep 选项(以 .** { *; } 结尾)时,您将指示 ProGuard 不要缩小、优化或混淆通配符之前提到的包名称的所有类和类成员。这最终将导致一个优化不佳的项目。因此,最好缩小此类 -keep 选项以仅针对缺少的类。在 OP 的示例中,为缺失的类添加一个 -keep 选项,如下所示将解决这个特定问题;

-keep class com.google.android.gms.chimera.GmsModuleInitializer

如果将 -keep 添加到配置文件中,ProGuard 可以帮助您设置缩小的 -addconfigurationdebugging 选项,有关此功能的更多详细信息记录在 ProGuard 手册 here 中。

最近发布了 ProGuard Playground,您可以快速查看广泛的 -keep 选项与缩小选项的效果。一个不错的好处是您不需要不断(重新)构建项目。