Proguard and Scoreloop

819 Views Asked by At

I'm trying to use Proguard on my Android projet and keep getting the same error at runtime on the Scoreloop (version 3.0.3) library...

I defined the proguard config file as follow in the project.properties file:

proguard.config=${sdk.dir}/tools/proguard/proguard-android-optimize.txt:proguard-project.txt
proguard.enabled=true

And here is my proguard-project.txt file (with everything included in case I did something wrong somewhere...):

# ####### #
# Project #
# ####### #
-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


# ##### #
# AdMob #
# ##### #
-keep public class com.google.ads.** {*;}
-keep public class com.google.gson.** {*;}


# #### #
# ACRA #
# #### #
# we need line numbers in our stack traces otherwise they are pretty useless
-renamesourcefileattribute SourceFile
-keepattributes SourceFile,LineNumberTable

# ACRA needs "annotations" so add this... 
-keepattributes *Annotation*

# keep this class so that logging will show 'ACRA' and not a obfuscated name like 'a'.
# Note: if you are removing log messages elsewhere in this file then this isn't necessary
-keep class org.acra.ACRA {*;}

# keep this around for some enums and classes that ACRA needs
-keep class org.acra.ReportingInteractionMode {*;}
#-keep class org.acra.ReportField {*;}
-keepnames class org.acra.ReportField {*;}

# keep this otherwise it is removed by ProGuard
-keep public class org.acra.ErrorReporter {
    public void addCustomData(java.lang.String,java.lang.String);
}
-keep public class org.acra.ErrorReporter {
    public org.acra.ErrorReporter$ReportsSenderWorker handleSilentException(java.lang.Throwable);
}


# ######### #
# Scoreloop #
# ######### #
-dontwarn com.scoreloop.client.android.core.paymentprovider.**
-keep class com.scoreloop.client.android.core.paymentprovider.fortumo.FortumoPaymentProviderController {*;}
-keep class com.scoreloop.client.android.core.paymentprovider.fortumo.FortumoPaymentProvider {*;}
-keep class com.scoreloop.client.android.core.paymentprovider.paypalx.PayPalXPaymentProviderController {*;}
-dontwarn com.scoreloop.client.android.core.ui.WebViewDialog
-keep class com.scoreloop.client.android.core.ui.WebViewDialog {*;}
-keep class com.facebook.android.** {*;}


# ############## #
# In-App Billing #
# ############## #
# -keep class com.android.vending.billing.**


# ####### #
# OrmLite #
# ####### #
# OrmLite uses reflection
-keep class com.j256.**
-keepclassmembers class com.j256.** { *; }
-keep enum com.j256.**
-keepclassmembers enum com.j256.** { *; }
-keep interface com.j256.**
-keepclassmembers interface com.j256.** { *; }

I'm getting this error at runtime:

Caused by: java.lang.IllegalArgumentException: java.lang.NoSuchMethodException: <init> [class com.scoreloop.client.android.core.b.aw]
    at com.scoreloop.client.android.core.b.j.a(SourceFile:692)
    at com.scoreloop.client.android.core.b.j.<init>(SourceFile:368)
    at com.sofresh.games.megaflux.MegaFluxApplication.onCreate(SourceFile:106)
    at com.sofresh.games.megaflux.MegaFluxApplication_.onCreate(SourceFile:19)
    at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1000)
    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4391)
    ... 10 more
 Caused by: java.lang.NoSuchMethodException: <init> [class com.scoreloop.client.android.core.b.aw]
    at java.lang.Class.getConstructorOrMethod(Class.java:460)
    at java.lang.Class.getConstructor(Class.java:431)
    at com.scoreloop.client.android.core.b.j.a(SourceFile:684)

From the file mapping.txt, I found this regarding the problematic classes and calls:

com.scoreloop.client.android.core.model.Client -> com.scoreloop.client.android.core.b.j:
    java.util.Map a -> a
    com.scoreloop.client.android.core.model.ClientObserver b -> b
    com.scoreloop.client.android.core.model.Session c -> c
    103:104:boolean a(java.util.Properties,java.lang.String,boolean) -> a
    155:178:java.util.Properties a(android.content.Context) -> a
    182:185:void a(java.util.Properties,java.lang.String) -> a
    188:194:void a(java.util.Properties,java.lang.String,java.lang.String) -> a
    198:232:void a(android.content.Context,java.lang.String) -> a
    380:387:void a(java.util.Properties) -> a
    638:640:int b(java.util.Properties,java.lang.String) -> b
    684:692:void a(java.lang.Class) -> a
    708:711:void a$2a1b557e(com.scoreloop.client.android.core.model.Session) -> a
    715:718:boolean a(com.scoreloop.client.android.core.model.Session) -> b
    722:723:void b(android.content.Context) -> b
[...]
com.scoreloop.client.android.core.model.Session -> com.scoreloop.client.android.core.b.aw:
[...]

So I thought the error said that it couldn't find the constructor of Client taking a Session. I tried adding the following to my proguard conf:

-keep class com.scoreloop.client.android.core.model.** {*;}
-keepclassmembers class com.scoreloop.client.android.core.model.**

With no luck, now I'm getting this error:

Caused by: java.lang.IllegalArgumentException: java.lang.NoSuchMethodException: <init> [class com.scoreloop.client.android.core.model.Session]
    at com.scoreloop.client.android.core.model.Client.a(SourceFile:692)
    at com.scoreloop.client.android.core.model.Client.a(SourceFile:605)
    at com.scoreloop.client.android.core.model.Client.<init>(SourceFile:368)
    at com.blabla.MyApplication.onCreate(SourceFile:106)
    at com.blabla.MyApplication_.onCreate(SourceFile:19)
    at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1000)
    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4391)
    ... 10 more
 Caused by: java.lang.NoSuchMethodException: <init> [class com.scoreloop.client.android.core.model.Session]
    at java.lang.Class.getConstructorOrMethod(Class.java:460)
    at java.lang.Class.getConstructor(Class.java:431)
    at com.scoreloop.client.android.core.model.Client.a(SourceFile:684)

And now I'm a bit lost on what to try next... Any idea and enlightenment on this error ?

2

There are 2 best solutions below

1
On BEST ANSWER

After a response from Scoreloop support and some tests on my side, here is the ProGuard configuration for Scoreloop:

# ######### #
# Scoreloop #
# ######### #
-dontwarn com.scoreloop.client.android.core.paymentprovider.**
-keep class com.scoreloop.client.android.core.paymentprovider.fortumo.FortumoPaymentProviderController {*;}
-keep class com.scoreloop.client.android.core.paymentprovider.fortumo.FortumoPaymentProvider {*;}
-keep class com.scoreloop.client.android.core.paymentprovider.paypalx.PayPalXPaymentProviderController {*;}
-dontwarn com.scoreloop.client.android.core.ui.WebViewDialog
-keep class com.scoreloop.client.android.core.ui.WebViewDialog {*;}
-keep class com.facebook.android.** {*;}
-keep class com.scoreloop.client.android.core.** { *; }
1
On

The code performs reflection and can't find a constructor, so you indeed have to make sure that it's preserved. Your -keep option is preserving all classes/fields/methods in the specified package and its subpackages:

-keep class com.scoreloop.client.android.core.model.** {*;}

However, the code is probably trying to find the constructor of a class outside this package -- the stack trace unfortunately doesn't tell. You'll have to figure out which class (or set of classes) this is, and then keep its constructor.

Note that your -keepclassmembers option doesn't do anything (because it doesn't specify any class members), but it is not necessary.