目前,我有经验,使用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永远不会触及jackson和Google库。
-keep class org.codehaus.** { *; }
-keep class com.google.** { *; }
-keep interface org.codehaus.** { *; }
-keep interface com.google.** { *; }
但这不起作用。 NPE仍然发生在Types.java
请注意,我还有另一种尝试是,我认为混淆过程会导致NPE发生。因此,我尝试使用-dontobfuscate
禁用它。但这一次,我无法生成APK文件,并收到一条热门的错误消息:转换为Dalvik格式失败,错误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;
}
ProGuard处理后可能导致getSuperParameterizedType
返回null
的可能根本原因是什么?
答案 0 :(得分:32)
以下组合对我有用:
-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云端硬盘项目提供了一个兼容的工作程序。
虽然最初在此链接here
找到了此解决方案,但无法获得所有功劳答案 1 :(得分:7)
正确的组合是:
-keepattributes Signature,RuntimeVisibleAnnotations,AnnotationDefault
Google为项目google-api-java-client
准备了proguard配置答案 2 :(得分:1)
第一级课并不意味着不接触它。这意味着不要更改其名称,并将其用作确定是否未引用其他类的基础。可以删除。
优化仍然会发生,这可能是您的问题。我要做的下一步是尝试: -dontoptimize
这会导致您的其他优化被忽略。
BTW,不确定您使用的是哪个版本的SDK。使用15,20是最新的,并且使用项目创建proguard-project.txt文件。它使用的优化选项是:
-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*
如果关闭优化使其运行,可能会关闭SDK所做的所有优化(那就是!),也可以让你进行优化。
答案 3 :(得分:0)
方法Types.getSuperParameterizedType依赖于有关泛型的信息。泛型在Java中被删除。编译器只将它们添加为注释属性,JVM忽略它们,ProGuard会丢弃它们,除非你告诉它不要。所以这可能会有所帮助:
-keepattributes *Annotation*
答案 4 :(得分:0)
你的代码是否使用任何实现Serializable的东西?所有这些都需要被排除在外。
答案 5 :(得分:0)
最近GooglePlayServices的更新很少。我不喜欢新的API。我遇到了同样的问题。
我无法使用proguard编译已签名的应用程序。谷歌的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