Google Drive API 与 ProGuard (NPE) 不能很好地配合

问题描述 投票:0回答:7

目前,我的经验是,一段使用 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

请注意,我还有另一个尝试,我认为obfuscate过程会导致NPE发生。因此,我尝试使用

-dontobfuscate
禁用它。但这一次,我将无法生成 APK 文件,并收到一条流行的错误消息:转换为 Dalvik 格式失败,错误 1

这是导致 Google Drive API 出现 NPE 的混淆器配置。

-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 的情况下运行得很好)

enter image description here

如果我查看 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
的可能根本原因是什么?

android google-api google-drive-api proguard google-api-java-client
7个回答
37
投票

以下组合对我有用:

-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 项目提供了一个工作的混淆器兼容解决方案。

但不能将此解决方案全部归功于此解决方案,最初在此链接此处

找到

7
投票

正确的组合是:

-keepattributes 签名、运行时可见注释、注释默认

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


1
投票

首先,保留课程并不意味着不碰它。意思就是不要改它的名字,以此作为判断其他类是否不被引用、是否可以删除的依据。

优化仍然发生,这可能是您的问题。我要做的下一步是尝试: -不要优化

这应该会导致您的其他优化被忽略。

顺便说一句,不确定您使用的是哪个版本的 SDK。我使用的是 15,最新的是 20,并且随项目创建了一个 proguard-project.txt 文件。它使用的优化选项是:

-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*

如果关闭优化使其运行,也许关闭 SDK 所做的所有优化(这就是!所做的),也将允许您进行优化。


1
投票

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


0
投票

Types.getSuperParameterizedType 方法依赖于有关泛型的信息。 Java 中泛型被删除了。编译器仅将它们添加为注释属性,JVM 会忽略它们,并且 ProGuard 会丢弃它们,除非您告诉它不要这样做。所以这可能会有所帮助:

-keepattributes *Annotation*

0
投票

这对我有用。

-keepattributes Signature,RuntimeVisibleAnnotations,AnnotationDefault
-keepclassmembers class * {
  @com.google.api.client.util.Key <fields>;
}
-dontwarn com.google.api.client.extensions.android.**
-dontwarn com.google.api.client.googleapis.extensions.android.**
-dontwarn com.google.android.gms.**
-dontnote java.nio.file.Files, java.nio.file.Path
-dontnote **.ILicensingService
-dontnote sun.misc.Unsafe
-dontwarn sun.misc.Unsafe
-keep class * extends com.google.api.client.json.** { *; }
-keep class * extends com.google.api.client.util.** { *; }
-keep class com.google.api.services.drive.** { *; }

-1
投票

您的代码是否使用任何实现 Serialized 的东西?所有这些也需要排除。

© www.soinside.com 2019 - 2024. All rights reserved.