简体   繁体   中英

What am I missing in this Proguard configuration for Android?

I've tried countless things but I'm not being able to prevent my app to crash while using Proguard to shrink the code (obfuscation is disabled). I always get the following exception when Proguard is enabled:

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

Besides the standard Proguard configuration for Android apps, I've added the following lines:

-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 { *; }

But I still get the exception mentioned above...

What am I missing?

The problem is ProtocolBuffers is using reflection to call methods but Proguard can not see the reflection calls. Proguard could either change the name of a Method / Object or remove the Method / Object, either way reflection will not find it.

Options:

  • You could try Finding every possible reflection call and adding the appropriate Proguard statements in. But you might need to change this for each new version of protocol buffers. Personally I would not go this way

  • You could try adding optimize_for SPEED option to the Proto Definition and regenerating the java code, this will result in much larger class that does not use reflection and could be used with Proguard.

  • Try one of the JavaMe protobuf solutions - they are much smaller. see previous question

Problem Code :

 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);
    }
  }

I also encountered this issue: java.lang.RuntimeException Generated message class "xxx" missing method "xxx" in signed apk, but in debug mode it's out of question. And I'm sure the Proguard configuration is OK.

By analyzing the stack trace log, I found the root cause of the problem: print protobuf file log too huge, like

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

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

this UserPb.java file is so huge that contains over 50000 lines of code.

So DO NOT print protobuf related log in signed apk .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM