为啥我在使用 Proguard 时会从 Play Services lib 获得 ClassNotFoundException?
Posted
技术标签:
【中文标题】为啥我在使用 Proguard 时会从 Play Services lib 获得 ClassNotFoundException?【英文标题】:Why am I getting a ClassNotFoundException from Play Services lib when using Proguard?为什么我在使用 Proguard 时会从 Play Services lib 获得 ClassNotFoundException? 【发布时间】:2017-01-09 18:42:29 【问题描述】:我刚刚在我的构建中打开了 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 Services 一起使用的所有内容都应该包含在 Android Gradle 插件中:
注意:ProGuard 指令包含在 Play 服务客户端中 库以保留所需的类。 Android 插件 Gradle 自动在 AAR 中附加 ProGuard 配置文件 (Android ARchive) 打包并将该包附加到您的 ProGuard 配置。在项目创建过程中,Android Studio 会自动 创建 ProGuard 配置文件和 build.gradle 属性 供 ProGuard 使用。要将 ProGuard 与 Android Studio 一起使用,您必须启用 build.gradle buildTypes 中的 ProGuard 设置。更多 信息,请参阅 ProGuard 指南。
这是我的应用模块 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()
我错过了什么?
【问题讨论】:
【参考方案1】:ClassNotFoundException 通常发生在应用程序尝试通过其字符串名称加载类但找不到具有指定名称的类的定义时。
从此forum,您可以通过添加com.google.android.gms.** *;
来修复它。
只需添加到您的 proguard-project.txt:
保留类 com.google.android.gms.** *; 不要警告 com.google.android.gms.**
您也可以查看SO question 中的建议评论。
Google Play 服务 aars 包含带有必要条款的 proguard.txt。所以这个设置不应该真的是必要的。您可以调查 ProGuard 输出文件中的片段发生了什么。检查 app/build/output/mapping/buildVariant/usage.txt 和 mapping.txt。该片段应在其中之一中提及。
希望这会有所帮助!
【讨论】:
谢谢。我添加了那些保持/不警告标志。很高兴知道他们“不应该”像我想的那样需要。我会调查输出映射。【参考方案2】:我知道这是一篇相当老的帖子,但我想强调以下内容,如果它对未来的人有所帮助。
就像@abielita 提到的那样,ClassNotFoundException
是由未处理的反射情况引起的。
当使用广泛的 -keep
选项(以 .** *;
结尾)时,您将指示 ProGuard 不要缩小、优化或混淆通配符之前提到的包名称的所有类和类成员。这最终会导致一个优化不佳的项目。因此,最好将此类-keep
选项缩小到仅针对缺失的类。在 OP 的示例中,为缺少的类添加 -keep
选项(如下所示)将解决此特定问题;
-keep class com.google.android.gms.chimera.GmsModuleInitializer
如果您将-addconfigurationdebugging
添加到配置文件中,ProGuard 可以帮助您设置缩小的-keep
选项,有关此功能的更多详细信息记录在ProGuard 手册here 中。
最近发布了ProGuard Playground,您可以快速看到广泛的-keep
选项与缩小选项的效果。这里的一个很好的好处是您不需要不断(重新)构建项目。
【讨论】:
以上是关于为啥我在使用 Proguard 时会从 Play Services lib 获得 ClassNotFoundException?的主要内容,如果未能解决你的问题,请参考以下文章
使用 google-play-services 进行 Proguard
通过将 proguard 规则映射文件上传到 google play 控制台去混淆生产 Android 错误
使用 Proguard 在 dist 上混淆 Play 2 Web 应用程序?
Proguard 使用 Google Play 服务库返回错误