Google Drive API 不能很好地与 ProGuard (NPE) 配合使用
Posted
技术标签:
【中文标题】Google Drive API 不能很好地与 ProGuard (NPE) 配合使用【英文标题】:Google Drive API doesn't play well with ProGuard (NPE) 【发布时间】:2013-01-02 20:21:00 【问题描述】:目前,我的经验是,一段代码使用 Google Drive API在不引入 ProGuard 的情况下运行良好。
但是,在引入 ProGuard 后,我收到以下运行时错误。
at java.lang.Thread.run(Thread.java:856)
Caused by: java.lang.NullPointerException
at com.google.api.client.util.Types.getActualParameterAtPosition(Types.java:329)
at com.google.api.client.util.Types.getIterableParameter(Types.java:309)
at com.google.api.client.json.JsonParser.parseValue(JsonParser.java:546)
at com.google.api.client.json.JsonParser.parse(JsonParser.java:350)
at com.google.api.client.json.JsonParser.parseValue(JsonParser.java:586)
at com.google.api.client.json.JsonParser.parse(JsonParser.java:289)
at com.google.api.client.json.JsonObjectParser.parseAndClose(JsonObjectParser.java:76)
at com.google.api.client.json.JsonObjectParser.parseAndClose(JsonObjectParser.java:71)
at com.google.api.client.http.HttpResponse.parseAs(HttpResponse.java:491)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:456)
at com.jstock.c.b.a(CloudFile.java:136)
请注意,崩溃发生在我的代码中(如果我使用 mapping.txt 进行回溯,则为 com.jstock.c.b.a)
// request is Files.List
FileList files = request.execute();
在我的 proguard 中,我认为有以下 2 个关键指令可以防止崩溃发生:我告诉 ProGuard 永远不要接触 jackson 和 Google 库。
-keep class org.codehaus.** *;
-keep class com.google.** *;
-keep interface org.codehaus.** *;
-keep interface com.google.** *;
但这不起作用。 NPE 仍然发生在Types.java
请注意,我有另一个尝试是,我认为 混淆 过程会导致 NPE 发生。因此,我尝试使用-dontobfuscate
禁用它。但这一次,我将无法生成 APK 文件,并收到一条流行的错误消息:Conversion to Dalvik format failed with error 1
这是导致 Google Drive API 出现 NPE 的 proguard 配置。
-optimizationpasses 1
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
# Comment out the following line, will cause popular "Conversion to Dalvik format failed with error 1"
##-dontobfuscate
-dontwarn sun.misc.Unsafe
-dontwarn com.google.common.collect.MinMaxPriorityQueue
-dontwarn javax.swing.**
-dontwarn java.awt.**
-dontwarn org.jasypt.encryption.pbe.**
-dontwarn java.beans.**
-dontwarn org.joda.time.**
-dontwarn com.google.android.gms.**
-dontwarn org.w3c.dom.bootstrap.**
-dontwarn com.ibm.icu.text.**
-dontwarn demo.**
# Hold onto the mapping.text file, it can be used to unobfuscate stack traces in the developer console using the retrace tool
-printmapping mapping.txt
# Keep line numbers so they appear in the stack trace of the develeper console
-keepattributes *Annotation*,EnclosingMethod,SourceFile,LineNumberTable
-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 android.support.v4.app.** *;
-keep interface android.support.v4.app.** *;
-keep class com.actionbarsherlock.** *;
-keep interface com.actionbarsherlock.** *;
# https://sourceforge.net/p/proguard/discussion/182456/thread/e4d73acf
-keep class org.codehaus.** *;
-keep class com.google.** *;
-keep interface org.codehaus.** *;
-keep interface com.google.** *;
-assumenosideeffects class android.util.Log
public static int d(...);
public static int i(...);
public static int e(...);
public static int v(...);
-keepclasseswithmembernames class *
native <methods>;
-keepclasseswithmembers class *
public <init>(android.content.Context, android.util.AttributeSet);
-keepclasseswithmembers class *
public <init>(android.content.Context, android.util.AttributeSet, int);
-keepclassmembers class * extends android.app.Activity
public void *(android.view.View);
-keepclassmembers enum *
public static **[] values();
public static ** valueOf(java.lang.String);
-keep class * implements android.os.Parcelable
public static final android.os.Parcelable$Creator *;
-assumenosideeffects class android.util.Log
public static *** d(...);
public static *** v(...);
public static *** i(...);
-keepclasseswithmembers class com.google.common.base.internal.Finalizer
<methods>;
还有什么我可以尝试的吗?
我不确定这可能是由库的组合引起的。 (虽然在没有引入 ProGuard 的情况下运行良好)
如果我查看 NPE 崩溃位置 (Types.getActualParameterAtPosition(Types.java:329))
private static Type getActualParameterAtPosition(Type type, Class<?> superClass, int position)
ParameterizedType parameterizedType = Types.getSuperParameterizedType(type, superClass);
Type valueType = parameterizedType.getActualTypeArguments()[position];
// this is normally a type variable, except in the case where the class of iterableType is
// superClass, e.g. Iterable<String>
if (valueType instanceof TypeVariable<?>)
Type resolve = Types.resolveTypeVariable(Arrays.asList(type), (TypeVariable<?>) valueType);
if (resolve != null)
return resolve;
return valueType;
我怀疑Types.getSuperParameterizedType
会返回null
。所以,我进一步研究了Types.getSuperParameterizedType
。
public static ParameterizedType getSuperParameterizedType(Type type, Class<?> superClass)
if (type instanceof Class<?> || type instanceof ParameterizedType)
outer: while (type != null && type != Object.class)
Class<?> rawType;
if (type instanceof Class<?>)
// type is a class
rawType = (Class<?>) type;
else
// current is a parameterized type
ParameterizedType parameterizedType = (ParameterizedType) type;
rawType = getRawClass(parameterizedType);
// check if found Collection
if (rawType == superClass)
// return the actual collection parameter
return parameterizedType;
if (superClass.isInterface())
for (Type interfaceType : rawType.getGenericInterfaces())
// interface type is class or parameterized type
Class<?> interfaceClass =
interfaceType instanceof Class<?> ? (Class<?>) interfaceType : getRawClass(
(ParameterizedType) interfaceType);
if (superClass.isAssignableFrom(interfaceClass))
type = interfaceType;
continue outer;
// move on to the super class
type = rawType.getGenericSuperclass();
return null;
可能导致getSuperParameterizedType
经过ProGuard处理后返回null
的根本原因是什么?
【问题讨论】:
【参考方案1】:以下组合对我有用:
-keep class com.google.** *;
-keep interface com.google.** *;
-dontwarn com.google.**
-dontwarn sun.misc.Unsafe
-dontwarn com.google.common.collect.MinMaxPriorityQueue
-keepattributes *Annotation*,Signature
-keep class * extends com.google.api.client.json.GenericJson
*;
-keep class com.google.api.services.drive.**
*;
这为最近的 Google Drive 项目提供了一个有效的 proguard 兼容解决方案。
虽然不能完全归功于此解决方案,最初在此链接中找到 here
【讨论】:
谢谢。过几天再试试,因为我现在没有开发机器。 感谢您承认您的来源并包含返回我网站的链接 :-) 我在 -keepattributes 下缺少签名 没有保留所有 com.google,而是为我修复了所有崩溃问题:-keep class com.google.api.client.** *;
【参考方案2】:
正确的组合是:
-keepattributes Signature,RuntimeVisibleAnnotations,AnnotationDefault
Google 为项目 google-api-java-client 准备了 proguard 配置
https://github.com/google/google-api-java-client/blob/57fe35766cbba0a0d5a9a296be81468d730a29f8/google-api-client-assembly/proguard-google-api-client.txt
【讨论】:
我不知道 Google 为他们的库准备了 proguard 配置。打算试试看。【参考方案3】:首先 - 保留一个课程并不意味着不接触它。意思是不要改名,以此作为判断其他类是否不被引用&是否可以删除的依据。
优化仍然存在,这可能是您的问题。我要做的下一步是尝试: -不要优化
这应该会导致您的其他优化被忽略。
顺便说一句,不确定您使用的是什么版本的 SDK。我正在使用 15,20 是最新的,并且使用该项目创建了一个 proguard-project.txt 文件。它使用的优化选项是:
-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
如果关闭优化使其运行,也许关闭 SDK 所做的所有优化(这就是!所做的),也将允许您进行优化。
【讨论】:
尝试仅使用-keepattributes *Annotation*
,并禁用优化。没有运气。同样的 NPE 仍然发生 :( dropbox.com/s/av2y9how104zsq1/proguard-project.txt dropbox.com/s/7yqvl652bua3gx5/project.properties
也许检查 bin/proguard/obfuscated.jar 以查看 getSuperParameterizedType() 方法对代码的真正作用。您可以目视检查与上述来源的比较。不是直接的答案,但根据结果可能会有用。如果您需要反编译器,可以使用link。【参考方案4】:
Types.getSuperParameterizedType 方法依赖于有关泛型的信息。泛型在 Java 中被删除。编译器只将它们添加为注解属性,JVM 会忽略它们,ProGuard 会丢弃它们,除非你告诉它不要这样做。所以这可能会有所帮助:
-keepattributes *Annotation*
【讨论】:
虽然我可以看到我已经有-keepattributes *Annotation*,EnclosingMethod,SourceFile,LineNumberTable
,但我想我今晚会用-keepattributes *Annotation*
再试一次。感谢您的澄清。
尝试仅使用-keepattributes *Annotation*
,并禁用优化。没有运气。同样的 NPE 仍然发生 :( dropbox.com/s/av2y9how104zsq1/proguard-project.txt dropbox.com/s/7yqvl652bua3gx5/project.properties
你是对的,我错过了它已经在你的配置中。问题一定出在其他地方。我得调查一下。【参考方案5】:
最近对 GooglePlayServices 的更新很少。我不喜欢新的 API。我有同样的问题。
我无法使用 proguard 编译已签名的应用程序。 Google 的 Proguard 模板对我不起作用。
我将这四行添加到我的 proguard 配置中并且它正在工作:
-dontwarn com.google.android.gms.**
-keep interface com.google.** *;
-keep class * extends com.google.api.client.json.GenericJson *;
-keep class com.google.api.services.drive.** *;
这很奇怪。以前版本的 google-api-services-drive-v2 编译没有任何问题。
我目前使用的是最新版本:google-api-services-drive-v2-rev47-1.12.0-beta.jar
【讨论】:
【参考方案6】:您的代码是否使用任何实现 Serializable 的东西?所有这些也需要排除。
【讨论】:
以上是关于Google Drive API 不能很好地与 ProGuard (NPE) 配合使用的主要内容,如果未能解决你的问题,请参考以下文章
当 sleep() 不能很好地与警报一起工作时,我还能做啥“睡眠”?
python 子进程不能很好地与 gsutil 复制/移动命令一起使用