6

我有一个使用 Google 协议缓冲区的项目。一旦我尝试用 ProGuard 混淆它,似乎 protobuf 会导致问题。

我自己的所有课程都打包到mybuildedclasses.jar. 谷歌代码打包成protbuf.jar

mybuildedclasses.jar
protobuf.jar
other external jars

之后我试图混淆mybuildedclasses.jar. 配置文件与此类似。最终所有的罐子都被包装在另一个胖罐子里。

我运行程序,一旦尝试发送消息,就会打印这种异常。

 Caused by: java.lang.RuntimeException: Generated message class "org.mypackage.messages.Control$MessageControlHandCard$Builder" missing method "getCardId".
        at com.google.protobuf.GeneratedMessage.getMethodOrDie(GeneratedMessage.
java:1366)
        at com.google.protobuf.GeneratedMessage.access$1(GeneratedMessage.java:1
361)
        at com.google.protobuf.GeneratedMessage$FieldAccessorTable$SingularField
Accessor.<init>(GeneratedMessage.java:1502)
        at com.google.protobuf.GeneratedMessage$FieldAccessorTable.<init>(Genera
tedMessage.java:1441)
        at org.mypackage.Control$1.assignDescriptors(SourceFile:32
20)
        at com.google.protobuf.Descriptors$FileDescriptor.internalBuildGenerated
FileFrom(Descriptors.java:300)
        at org.evogame.common.messages.Control.<clinit>(SourceFile:3278)
        ... 60 more
Caused by: java.lang.NoSuchMethodException: org.evogame.common.messages.Control$
MessageControlHandCard$Builder.getCardId()
        at java.lang.Class.getMethod(Class.java:1622)
        at com.google.protobuf.GeneratedMessage.getMethodOrDie(GeneratedMessage.
java:1364)

 Exception in thread "AWT-EventQueue-0" java.lang.ExceptionInInitializerError
        at org.mypackage.messages.Control$MessageControlGameRequest.interna
lGetFieldAccessorTable(SourceFile:527)
        at com.google.protobuf.GeneratedMessage.getAllFieldsMutable(GeneratedMes
sage.java:105)
        at com.google.protobuf.GeneratedMessage.getAllFields(GeneratedMessage.ja
va:153)
        at com.google.protobuf.TextFormat$Printer.print(TextFormat.java:229)
        at com.google.protobuf.TextFormat$Printer.access$2(TextFormat.java:226)
        at com.google.protobuf.TextFormat.print(TextFormat.java:69)
        at com.google.protobuf.TextFormat.printToString(TextFormat.java:116)
        at com.google.protobuf.AbstractMessage.toString(AbstractMessage.java:87)

如果我不混淆,那么一切都会完美。那么具体应该如何配置-keepGoogle Protocol Buffers 相关代码的选项呢?

我已经尝试生成消息文件,但它给出了相同的例外。

-keep public class org.mypackage.messages.* {
 }
4

2 回答 2

11

看起来这可能只是包装未对齐的问题。看看错误:

 Caused by: java.lang.RuntimeException: Generated message class 
     "org.mypackage.Control$MessageControlHandCard$Builder" 
      missing method "getCardId".
 ...

就是这样org.mypackage.Control

现在看看你的 Proguard 配置:

-keep public class org.mypackage.messages.* {
}

那是使用org.mypackage.messages,其中不包括org.mypackage.Control.

现在大概这些不是您真正的包名称 - 但如果它们具有代表性,听起来您需要更改.proto文件以在包中发出类org.mypackage.messages而不是org.mypackage. (您可以改为更改您的 Proguard 配置,但听起来那样会太多。)

或者,您可以只使用继承树。我自己不是 Proguard 用户,但从示例来看,您可能想要:

-keep public class * extends com.google.protobuf.GeneratedMessage

我希望无论包如何,它都能在您的所有协议缓冲区类上工作。您可能会发现 protobuf 期望在“顶级”类中还有其他字段/方法。

编辑:进一步查看文档,您可能需要:

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

或者

-keep public class * extends com.google.protobuf.GeneratedMessageLite { *; }

以保护所有成员。还有其他“保留”选项正在查看而不是-keep,例如-keepnames

于 2013-01-02T06:58:02.953 回答
0

我更喜欢指定字段名称而不是保留整个类成员,这会产生更小的输出。

-keepclassmembers your.class.name {
  int sampleIntField;
  String sampleStringField;
}
于 2013-05-22T10:06:27.073 回答