Interface implemented methods removed after proguard

My codes implement the onComplete method of interface com.google.android.gms.tasks.OnCompleteListener. And used by com.google.firebase.messaging.FirebaseMessaging.getInstance().getToken().addOnCompleteListener(). But after proguard, this onComplete method has been completely removed, and got runtime java.lang.AbstractMethodError crash. I have tried many combination of “-keep class” without luck! Please help, Thanks!

Original codes before proguard:

import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.messaging.FirebaseMessaging;

public class MyClass {

    static public void testToken() {
        FirebaseMessaging.getInstance().getToken().addOnCompleteListener(new OnCompleteListener<String>() {
            @Override
            public void onComplete(@NonNull Task<String> task) {
                String token = task.isSuccessful() ? task.getResult() : null;
                System.out.println("Token received:" + token);
            }
        });
    }
}

In proguard-project.txt:

-keep public class com.google.android.gms.tasks.* { *; }
-keep public class com.google.firebase.messaging.* { *; }

-dontwarn com.google.android.gms.tasks.**
-dontwarn com.google.firebase.messaging.**

After proguard:

import com.google.android.gms.tasks.OnCompleteListener;
import com.google.firebase.messaging.FirebaseMessaging;

public class MyClass {

    public static void testToken() {
        FirebaseMessaging.getInstance().getToken().addOnCompleteListener(new OnCompleteListener<String>() {
        });
    }
}

And it was been removed, not renamed. It got the runtime exception!

16942 E AndroidRuntime: FATAL EXCEPTION: main
16942 E AndroidRuntime: Process: com.example.sample, PID: 16942
16942 E AndroidRuntime: java.lang.AbstractMethodError: abstract method "void com.google.android.gms.tasks.OnCompleteListener.onComplete(com.google.android.gms.tasks.Task)"
16942 E AndroidRuntime: 	at com.google.android.gms.tasks.zzj.run(Unknown Source)
16942 E AndroidRuntime: 	at android.os.Handler.handleCallback(Handler.java:739)
16942 E AndroidRuntime: 	at android.os.Handler.dispatchMessage(Handler.java:95)
16942 E AndroidRuntime: 	at android.os.Looper.loop(Looper.java:148)
16942 E AndroidRuntime: 	at android.app.ActivityThread.main(ActivityThread.java:5417)
16942 E AndroidRuntime: 	at java.lang.reflect.Method.invoke(Native Method)
16942 E AndroidRuntime: 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
16942 E AndroidRuntime: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
  788 W ActivityManager:   Force finishing activity com.example.sample/.MainActivity

Hi @potingwu ,

The easiest way to resolve this is by using the ProGuard Playground. This way you can visualise which classes are kept to make sure you target the correct one with the -keep options. You need to keep the anonymous class created in the method testToken. In the end you will end up with something similar to;
-keep class com.example.MyClass$1 { *; }

Kind regards,

Jonas

Yes, it works! Thanks! But I need to use an extra internal class to keep it. There are many of them, thought I can create a rule to handle/keep the original Interface implementation in general.

2 Likes

Hi @potingwu ,

I’m not sure if it would help you but you can use wildcards to target all these inner classes;
-keep class com.example.MyClass$* { *; }

Best regards,

Jonas

1 Like