【问题标题】:What am I missing in this Proguard configuration for Android?我在这个适用于 Android 的 Proguard 配置中缺少什么?
【发布时间】:2013-04-03 09:36:49
【问题描述】:

我尝试了无数方法,但在使用 Proguard 压缩代码时无法防止我的应用崩溃(混淆已禁用)。启用 Proguard 时,我总是遇到以下异常:

04-03 10:26:37.277 E/AndroidRuntime(29460): FATAL EXCEPTION: main
04-03 10:26:37.277 E/AndroidRuntime(29460): java.lang.ExceptionInInitializerError
04-03 10:26:37.277 E/AndroidRuntime(29460):     at com.company.nativeapp.activitycontrollers.LoginController.onLogInSuccess(LoginController.java:199)
04-03 10:26:37.277 E/AndroidRuntime(29460):     at com.company.datamanager.BfAccountStateManager$AccountWebViewClient.shouldOverrideUrlLoading(BfAccountStateManager.java:326)
04-03 10:26:37.277 E/AndroidRuntime(29460):     at android.webkit.CallbackProxy.uiOverrideUrlLoading(CallbackProxy.java)
04-03 10:26:37.277 E/AndroidRuntime(29460):     at android.webkit.CallbackProxy.handleMessage(CallbackProxy.java)
04-03 10:26:37.277 E/AndroidRuntime(29460):     at android.os.Handler.dispatchMessage(Handler.java)
04-03 10:26:37.277 E/AndroidRuntime(29460):     at android.os.Looper.loop(Looper.java)
04-03 10:26:37.277 E/AndroidRuntime(29460):     at android.app.ActivityThread.main(ActivityThread.java)
04-03 10:26:37.277 E/AndroidRuntime(29460):     at java.lang.reflect.Method.invokeNative(Native Method)
04-03 10:26:37.277 E/AndroidRuntime(29460):     at java.lang.reflect.Method.invoke(Method.java:511)
04-03 10:26:37.277 E/AndroidRuntime(29460):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1028)
04-03 10:26:37.277 E/AndroidRuntime(29460):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:795)
04-03 10:26:37.277 E/AndroidRuntime(29460):     at dalvik.system.NativeStart.main(Native Method)
04-03 10:26:37.277 E/AndroidRuntime(29460): Caused by: java.lang.ExceptionInInitializerError
04-03 10:26:37.277 E/AndroidRuntime(29460):     at com.company.android.bfsdk.diffusion.requests.mcs.BaseMCSRequest.<clinit>(BaseMCSRequest.java:28)
04-03 10:26:37.277 E/AndroidRuntime(29460):     ... 12 more
04-03 10:26:37.277 E/AndroidRuntime(29460): Caused by: java.lang.ExceptionInInitializerError
04-03 10:26:37.277 E/AndroidRuntime(29460):     at com.company.mobile.mcs.service.descriptor.inplay.Inplay.<clinit>(Inplay.java:20585)
04-03 10:26:37.277 E/AndroidRuntime(29460):     ... 13 more
04-03 10:26:37.277 E/AndroidRuntime(29460): Caused by: java.lang.RuntimeException: Generated message class "com.company.mobile.mcs.service.descriptor.Mcs$MCSRequestMessage$Builder" missing method "getUserAgent".
04-03 10:26:37.277 E/AndroidRuntime(29460):     at com.google.protobuf.GeneratedMessage.getMethodOrDie(GeneratedMessage.java:1359)
04-03 10:26:37.277 E/AndroidRuntime(29460):     at com.google.protobuf.GeneratedMessage.access$1300(GeneratedMessage.java:57)
04-03 10:26:37.277 E/AndroidRuntime(29460):     at com.google.protobuf.GeneratedMessage$FieldAccessorTable$SingularFieldAccessor.<init>(GeneratedMessage.java:1485)
04-03 10:26:37.277 E/AndroidRuntime(29460):     at com.google.protobuf.GeneratedMessage$FieldAccessorTable.<init>(GeneratedMessage.java:1432)
04-03 10:26:37.277 E/AndroidRuntime(29460):     at com.company.mobile.mcs.service.descriptor.Mcs$1.assignDescriptors(Mcs.java:2083)
04-03 10:26:37.277 E/AndroidRuntime(29460):     at com.google.protobuf.Descriptors$FileDescriptor.internalBuildGeneratedFileFrom(Descriptors.java:298)
04-03 10:26:37.277 E/AndroidRuntime(29460):     at com.company.mobile.mcs.service.descriptor.Mcs.<clinit>(Mcs.java:2109)
04-03 10:26:37.277 E/AndroidRuntime(29460):     ... 14 more
04-03 10:26:37.277 E/AndroidRuntime(29460): Caused by: java.lang.NoSuchMethodException: getUserAgent []
04-03 10:26:37.277 E/AndroidRuntime(29460):     at java.lang.Class.getConstructorOrMethod(Class.java:460)
04-03 10:26:37.277 E/AndroidRuntime(29460):     at java.lang.Class.getMethod(Class.java:915)
04-03 10:26:37.277 E/AndroidRuntime(29460):     at com.google.protobuf.GeneratedMessage.getMethodOrDie(GeneratedMessage.java:1357)
04-03 10:26:37.277 E/AndroidRuntime(29460):     ... 20 more

除了 Android 应用的标准 Proguard 配置之外,我还添加了以下几行:

-keep public class com.company.**

-keep class com.company.* { *; }
-keepclassmembernames class com.company.* { *; }

-keep class * extends com.google.protobuf.GeneratedMessage { *; }
-keepclassmembernames class * extends com.google.protobuf.GeneratedMessage { *; }

但是我还是遇到了上面提到的异常……

我错过了什么?

【问题讨论】:

  • 我倾向于认为 Proguard 的主要好处是它的混淆而不是它的收缩能力。所以我的配置中只有“-dontshrink”行,
  • @NickT 是的,但我真的需要缩小功能......请参阅:stackoverflow.com/questions/15436956/…
  • @RicardoAmaral:你解决了这个问题吗?如果是,请您分享您的发现吗?我在同一个问题上停留了很长时间。
  • @Atul 可能,但这是 3 年前的事了,我不记得实际的解决方案,抱歉。接受的答案对您没有帮助吗?
  • @RicardoAmaral:不。虽然接受的答案有一些尝试的线索,但它对我没有帮助。尝试其他一些事情。无论如何感谢您的回复。我只是不知何故忽略了,在你问了三年之后:)

标签: android exception protocol-buffers proguard


【解决方案1】:

问题是 ProtocolBuffers 使用 reflection 调用方法,但 Proguard 看不到反射调用。 Proguard 可以更改方法/对象的名称或删除方法/对象,无论哪种方式反射都找不到它。

选项:

  • 您可以尝试查找所有可能的反射调用并在其中添加适当的 Proguard 语句。但您可能需要为每个新版本的协议缓冲区更改此设置。 我个人不会走这条路

  • 您可以尝试将 optimize_for SPEED 选项添加到 Proto Definition 并重新生成 java 代码,这将导致更大的类不使用反射并且可以与 Proguard 一起使用。

  • 尝试其中一种 JavaMe protobuf 解决方案 - 它们要小得多。见previous question

问题代码:

 private static Method getMethodOrDie(
      final Class clazz, final String name, final Class... params) {
    try {
      return clazz.getMethod(name, params);
    } catch (NoSuchMethodException e) {
      throw new RuntimeException(
        "Generated message class \"" + clazz.getName() +
        "\" missing method \"" + name + "\".", e);
    }
  }

【讨论】:

  • 但这正是我不明白的...... Proguard 没有看到反射调用,因此检测到一些“未使用”的方法并将其删除。但它们不应该被删除,因为我告诉 Proguard 不要删除 com.company.** 下的任何内容,还是应该删除?
  • 我们已经在使用优化了速度的 proto 文件,但出于某种原因仍在使用反射!?但是,我下载了最新的 Proto Buffer 库和编译器,生成了所有 .java 文件,再次针对速度进行了优化,现在它似乎可以工作了。也许我们使用的是旧的 .proto 文件,或者这个新版本的 Protocol Buffers 在某种程度上有所帮助。现在已经修好了,这才是最重要的。
  • @Ricardo 要将 一切 保留在 com.company 下,您需要“-keep class com.company.** { *; }”。然而,这将在很大程度上破坏优化和混淆的意义。
  • @EricLafortune 我知道,但现在的重点只是因为这个而缩小:stackoverflow.com/questions/15436956/… 但也许你的评论是这个问题的正确答案。如果您想为此创建答案,我将切换已接受的答案。此外,该一般规则更多地用于测试目的,而不是我打算对其进行微调。
  • 我很好奇为什么使用“优化速度”选项生成的 proto 类不会造成混淆问题。我遇到了错误。
【解决方案2】:

我也遇到过这个问题:java.lang.RuntimeException Generated message class "xxx" missing method "xxx" in signed apk,但在调试模式下是没问题的。而且我确信 Proguard 配置没问题。

通过对堆栈跟踪日志的分析,找到了问题的根源:打印protobuf文件日志太大,像

List<UserPb.UserInfo> userInfos = obj.getUserInfoList();

Log.d(TAG, "userInfos: " + userInfos);

这个 UserPb.java 文件非常庞大,包含超过 50000 行代码。

所以不要在签名的apk中打印protobuf相关的登录

【讨论】:

    猜你喜欢
    • 2019-07-01
    • 1970-01-01
    • 2010-12-24
    • 2021-09-19
    • 2011-01-24
    • 1970-01-01
    • 1970-01-01
    • 2017-06-17
    • 1970-01-01
    相关资源
    最近更新 更多