Proguard and Scala default arguments - android

I have an Android Scala app that uses SBT + ProGuard for building.
In a library project I have this:
package es.fcc.bibl.bd.sincr
class Columna[T] { ... }
class TablaBase {
lazy val columnas: List[Columna[_]] = ....
}
trait Soporte {
this: TablaBase =>
def fabricaSoporte(w: Writer, cols: List[Columna[_]] = columnas) {
}
in my app code, I have this:
package es.fcc.incidencias.bd
object sgiein extends TablaBase with Soporte { .... }
and when building my project, I get these cryptic errors:
Warning: es.fcc.incidencias.bd.sgiein: can't find referenced method 'void es$fcc$bibl$bd$sincr$TablaBaseSincronizada$_setter_$cols_$eq(scala.collection.immutable.List)' in program class es.fcc.incidencias.bd.sgiein$
Warning: es.fcc.incidencias.bd.sgiein: can't find referenced method 'scala.collection.immutable.List cols()' in program class es.fcc.incidencias.bd.sgiein$
Your input classes appear to be inconsistent.
You may need to recompile the code.
(http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedprogramclassmember)
The problem is related with the default value of the argument cols.
If I remove that argument, everything builds ok.
I've tried to change the ProGuard options to these with no luck:
-keepclassmembers class es.fcc.bibl.bd.sincr.TablaBaseSincronizada* {
** *(**);
}
-keepclassmembers class es.fcc.incidencias.bd.* {
** *(**);
}
I don't understand why I'm having this problem.

I've come to the conclusion that these errors can be safely ignored.
It must be some internal error in ProGuard.
Use the -dontwarn directive in the ProGuard configuration for that purpose.

Related

How can I prevent proguard from keeping some of my method names

I have been testing my apk against an online apk decompiler and I've noticed that some of my method names are there in clear text.
For example on one of my activities I have a suspend method called `mySuspendMethod' and this is what I will find when the code is decompiled:
#C0463c(mo2892c = "mypackage.MyActivity$mySuspendMethod$2", mo2893f = "MyActivity.kt", mo2894l = {304}, mo2895m = "invokeSuspend")
/* renamed from: mypackage.MyActivity$j */
/* compiled from: MyActivity.kt */
static final class C2963j extends w02 implements rb0<C5499yq, C0328iq<? super Boolean>, Object> {
MyActivity has to have an exclusion with -keep class because it is an Activity but I still want most of the methods to be totally obfuscated.
I only have this on keepattributes:
-keepattributes *Annotation*,Signature
I also have this, can't remember why:
-repackageclasses ''
Any idea how to prevent that type of stuff from showing up when decompiling the apk?
Edit: I think this is where the decompiler is getting it from (this is from the smali file.
.annotation runtime Lkotlin/coroutines/jvm/internal/c;
c = "mypackage.MyActivity$mySuspendMethod$2"
f = "MyActivity.kt"
l = {
0x136
}
m = "invokeSuspend"
.end annotation
Edit: using the whyareyoukeeping I got the explanation but it doesn't make a ton of sense:
mypackage.MyActivity
|- is referenced in keep rule:
| /Users/me/.gradle/caches/transforms-3/4de4b1c7915434eb501f4eea74700a11/transformed/jetified-ads-sdk-3.9.0.3/proguard.txt:44:1
java.lang.Object mypackage.MyActivity.mySuspendMethod(kotlin.coroutines.Continuation)
|- is invoked from:
| java.lang.Object mypackage.MyActivity.access$mySuspendMethod(mypackage.MyActivity,kotlin.coroutines.Continuation)
|- is invoked from:
| java.lang.Object mypackage.MyActivity$anotherMethodOnMyActivity$1.invokeSuspend(java.lang.Object)
|- is overriding method:
| java.lang.Object kotlin.coroutines.jvm.internal.BaseContinuationImpl.invokeSuspend(java.lang.Object)
|- is referenced in keep rule:
| /Users/me/somepath/app/proguard-rules.pro:108:1
The line that proguard file is pointing to is:
-keep class com.google.** { *; }
I don't remember why I have that line but I'm guessing it is needed. I don't know why it has to do with any of this though. Could it be that it is referencing the wrong rule? If I look at line 108 of the final configuration.txt file I see -dontnote android.net.http.**. Seems as unlikely to be at fault as the other one.
ProGuard has an option -whyareyoukeeping which will output some explanation for why it can't shrink something. Check out the documentation at https://www.guardsquare.com/manual/configuration/usage
To check a specific method, use something like this in your proguard file:
-whyareyoukeeping class mypackage.MyActivity* {
int myMethodName(...);
}
See the full syntax definition here: https://www.guardsquare.com/manual/configuration/usage#classspecification
try this:
-renamesourcefileattribute MyApplication
-keepattributes SourceFile,LineNumberTable
You can try:
-keep class mypackage.MyActivity {
private void !mySuspendMethod();
// NOTE: you have to change private, void and the parameters in () to your mySuspendMethod signature
}
! negates the method, so everything outside of the method will be kept.
Do make sure that the method signature is followed exactly if not this won't work.
If it does not work, feel free to leave a comment and I check the solution.
Thanks!

Missing class: com.google.android.aidl.BaseProxy

Occasionally after generating the Signed APK, the following warning would appear
Missing class: com.google.android.aidl.BaseProxy
Missing Class: com.google.android.aidl.BaseStub
However, the APK would be successfully generated. Only when released the warning would be detrimental to the app.
Fatal Exception: java.lang.NoClassDefFoundError
Failed resolution of: Lcom/google/android/aidl/BaseStub
What gradle dependancy is required so this class is found and resolved?
Here are links to my gradle files (shared on google drive):
build.gradle (module: app)
build.gradle (project)
Thanks.
Try to update your proguard rules with the following:
-keepclassmembers class com.google.android.aidl.** { *; }
EDIT: (from proguard documentation)
-keep: Specifies classes and class members (fields and methods) to be preserved as entry points to your code.
-keepclassmembers: Specifies class members (only) to be preserved, if their classes are preserved as well.
If you specify a class, without class members, ProGuard only preserves the class and its parameterless constructor as entry points. It may still remove, optimize, or obfuscate its other class members.
If you specify a method, ProGuard only preserves the method as an entry point. Its code may still be optimized and adapted.
So if you're not sure which option you need, you should probably simply use -keep. It will make sure the specified classes and class members are not removed in the shrinking step, and not renamed in the obfuscation step.
(below -keep includes all classes and class members from aidl)
-keep class com.google.android.aidl.** { *; }
In your case you are missing BaseProxy and BaseStub classes. You can specify only these classes in your -keep and -keepclassmembers and test which method is suitable for you with best code obfuscation for your release build.
(below -keep includes only BaseProxy and BaseStub)
-keep class com.google.android.aidl.BaseProxy { *; }
-keep class com.google.android.aidl.BaseStub { *; }
My suggestion is to specify the class names you don't want to remove and utilize the code obfuscation to reduce your app size.
The symptoms of your issue (only happens in release build means proguard is removing the class) leads me to suggest :
if the class missing is one of yours add this annotation to the that class
#Keep class TheClass { ... }
if the class giving you pain is in the third party lib (mostly you add lib via gradle file in your project ) then normally in the library readme file (from their website like Github repo readme etc ) there is a proguard rules note that you need to add something like :
# Parceler library
-keep interface org.parceler.Parcel
-keep #org.parceler.Parcel class * { *; }
-keep class **$$Parcelable { *; }

How to keep package-level kotlin functions in proguard?

I declared a package-level function as utility in my library and I want to use it in my main app.
My issue is that I am not able to keep it from code obfuscation using proguard (and consequently use it in my main app).
My file it.blabla.util.Extensions.kt
fun foo(context: Context, action: String) {
...
}
I already tried to keep it in proguard using:
-keep class it.blablabla.util.UtilPackage.** { *; }
or
-keep class it.blablabla.util.** { *; }
but none of these is working.
In my app I'm trying to use foo as follows:
foo(applicationContext, "test")
but I'm not able to find the right import to let foo become visible in my app through the aar module.
I keep getting the following compilation error:
Unresolved reference: foo
You most likely have to keep the the class as well as keeping the metadata (proguard doc):
-keep class it.blablabla.util.ExtensionsKt {
*;
}
-keepkotlinmetadata

How to resolve ProGuard warnings (notes) about missing protobuf classes when using play-services-wearable

I have an android wear 2.0 project with the following dependency:
compile 'com.google.android.gms:play-services-wearable:11.0.4'
The play-services-wearable dependency results in an inherited dependency on play-services-basement, which contains classes such as com.google.protobuf.zzc that contain reflective code e.g:
final class zzc {
private static Class<?> zzcrO = zzLq();
private static Class<?> zzLq() {
try {
return Class.forName("com.google.protobuf.ExtensionRegistry");
} catch (ClassNotFoundException var0) {
return null;
}
}
This dependency therefore results in the following proguard Notes:
Note: com.google.protobuf.zzc: can't find dynamically referenced class com.google.protobuf.ExtensionRegistry
Note: com.google.protobuf.zzd: can't find dynamically referenced class com.google.protobuf.Extension
Note: com.google.protobuf.zze: can't find dynamically referenced class libcore.io.Memory
Note: com.google.protobuf.zze: can't find dynamically referenced class org.robolectric.Robolectric
Note: there were 4 unresolved dynamic references to classes or interfaces.
You should check if you need to specify additional program jars.
(http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclass)
So my questions are:
Do I need to include an additional dependency to prevent the ProGuard from displaying the above notes?
If so, why doesn't play-services-basement include the required transitive dependencies (i.e. protobuf) automatically?
Would it be safe to add '-dontnote' rules to my proguard files to hide the above warnings? I'm concerned that since this code is reflective, there's a chance that it may actually be used by google play services and cause a Runtime exception if I just ignore the problem.

json4s serializes a case class Test("test") to "{}" on Android

I'm serializing a case class graph to JSON in an Android Scala app (using "com.hanhuy.sbt" % "android-sdk-plugin" % "1.3.5").
I'm using "org.json4s" %% "json4s-native" % "3.2.10", and it fails even with a simple case class which looks like this:
package test
case class Test(text: String)
The code to actually serialize looks like this:
import org.json4s._
import org.json4s.native.Serialization
import org.json4s.native.Serialization.{read, write}
// ...
implicit val formats = Serialization.formats(NoTypeHints)
val test = Test("test")
val serialized = write(test)
info(s"Serialized to '$serialized'")
The output is:
Serialized to '{}'
I suspect a ProGuard problem and my ProGuard settings in build.sbt are like this:
proguardScala in Android := true
proguardOptions in Android ++= Seq(
"-dontobfuscate",
"-dontoptimize",
"-keepattributes Signature",
"-dontwarn scala.collection.**", // required from Scala 2.11.3
"-dontwarn scala.collection.mutable.**", // required from Scala 2.11.0
"-ignorewarnings",
"-keep class scala.Dynamic",
"-keep class test.**"
)
I tried also with json4s-jackson but it made no difference.
The ProGuard log looks like this:
Warning: com.thoughtworks.paranamer.AnnotationParanamer$Jsr330Helper: can't find referenced class javax.inject.Named
Warning: com.thoughtworks.paranamer.AnnotationParanamer$Jsr330Helper: can't find referenced class javax.inject.Named
Warning: org.joda.convert.JDKStringConverter$9: can't find referenced class javax.xml.bind.DatatypeConverter
Warning: org.joda.convert.JDKStringConverter$9: can't find referenced class javax.xml.bind.DatatypeConverter
Warning: org.joda.convert.JDKStringConverter$9: can't find referenced class javax.xml.bind.DatatypeConverter
Note: com.google.android.gms.internal.av calls '(com.google.ads.mediation.MediationAdapter)Class.forName(variable).newInstance()'
Note: com.google.android.gms.maps.internal.q: can't find dynamically referenced class com.google.android.gms.maps.internal.CreatorImpl
Note: org.joda.time.DateTimeZone calls '(org.joda.time.tz.Provider)Class.forName(variable).newInstance()'
Note: org.joda.time.DateTimeZone calls '(org.joda.time.tz.NameProvider)Class.forName(variable).newInstance()'
Note: there were 1 unresolved dynamic references to classes or interfaces.
You should check if you need to specify additional program jars.
(http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclass)
Note: there were 3 class casts of dynamically created class instances.
You might consider explicitly keeping the mentioned classes and/or
their implementations (using '-keep').
(http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclasscast)
Warning: there were 5 unresolved references to classes or interfaces.
You may need to add missing library jars or update their versions.
If your code works fine without the missing classes, you can suppress
the warnings with '-dontwarn' options.
(http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedclass)
Note: You're ignoring all warnings!
Any ideas?
You can create a JSONObject from a String using the constructor:
JSONObject json = new JSONObject(myString);
And to convert your JSONObject to a String, just use the toString() method:
String myString = json.toString();
Additionally, if you are trying to get a specific String value from the JSONObject, you can do this:
if (json.has("content"))
{
String content = json.getString("content");
//do something with content string
}
Finally, if you aren't very comfortable using JSONObject, I recommend using the tools provided by droidQuery to help you parse, such as:
Object[] array = $.toArray(myJSONArray);
and
Map<String, ?> map = $.map(myJSONObject);

Categories

Resources