Unable to access companion object used in kotlin class after enabling proguard - kotlin

I have a Kotlin class with some variables in companion object. After enabling proguard, The variables are not getting accessed.
class Test{
......
companion object {
const val USER_NAME = "user_name"
.....
}
.....
}
Proguard rules include:-
-keep class kotlin.** { *; }
-keep class kotlin.Metadata { *; }
-dontwarn kotlin.**
-keepclassmembers class **$WhenMappings {
<fields>;
}
-keepclassmembers class kotlin.Metadata {
public <fields>;
public <methods>;
}
-keepclassmembers class * {
static final % *;
static final java.lang.String *;
}

Problem resolved using #Keep before companion object
class Test{
......
#Keep companion object {
const val USER_NAME = "user_name"
.....
}
.....
}

The accepted answer uses the #Keep annotation. If that works for you, then great, but in our case it didn't make a difference.
For anyone else in the same boat, here's the solution that worked for us (add to your proguard rules):
-keepclassmembers class com.example.some.package.SomeClass {
public static ** Companion;
}

After many struggles with it the thing that worked best for me is:
-keep class <class>$Companion { *; }
no annotations needed.

I faced a similar problem, there was a function in the companion object that was not being accessed after enabling proguard.
#Keep didn't work for me, after a lot of struggle. I found the solution.
Just add #JvmStatic annotation to the function inside the companion object.
And you are good to go.

Related

Kotlin's "internal" keyword Java interop

I'm trying to figure out what happens with internal classes when seen from Java's perspective.
Found this in the docs:
Members of internal classes go through name mangling, to make it harder to accidentally use them from Java and to allow overloading for members with the same signature that don’t see each other according to Kotlin rules
So I was very curious to see how it looks like in practice.
I created a simple Kotlin class:
internal class Foo(i : Int) {}
Built a project, unpacked the jar and used javap to have a look at the actual class... and it displayed a standard public class with the original name:
Compiled from "Foo.kt"
public final class Foo {
public Foo(int);
}
Am I missing something? or is it just the docs that are misleading?
Docs mention members of internal classes, but I tried that as well:
internal class Foo(someInt : Int) {
var someString : String
get() {
TODO()
}
set(value) {}
fun foo() { }
class Bar { }
}
And got the expected output:
Compiled from "Foo.kt"
public final class Foo {
public Foo(int);
public final java.lang.String getSomeString();
public final void setSomeString(java.lang.String);
public final void foo();
}
and:
Compiled from "Foo.kt"
public final class Foo$Bar {
public Foo$Bar();
}

How to keep method arguments names from obfuscation by ProGuard

For given class:
class KeepMe(val keepThisArgument: Int) {
fun keepMethod(keepThisArgument: Int) {
println(keepThisArgument)
}
}
and proguard configuration:
-keep class com.KeepMe { *; }
following code is produced by proguard:
public final class KeepMe {
private final int keepThisArgument;
public final void keepMethod(int paramInt) {
System.out.println(paramInt);
}
public final int getKeepThisArgument() {
return this.keepThisArgument;
}
public KeepMe(int paramInt) {
this.keepThisArgument = paramInt;
}
}
constructor and method argument names is changed from "keepThisArgument" to "paramInt". Is there a way to keep it from happening? I use net.sf.proguard gradle plugin, version 6.2.2.
Turns out there is separate configuration to keep all argument names in all classes that are kept from obfuscating:
-keepparameternames

Is there a way to keep Kotlin annotations only for public functions/members when obfuscating with proguard?

I am trying to obfuscate a library written in Kotlin using Proguard.
In the library I use default and named arguments. In order for these to work when including the obfuscated jar as a lib I need the flag -keepattributes RuntimeVisibleAnnotations in the Proguard file.
With this flag all private functions are no longer obfuscated, because the annotations for them contain the plain names. Is there a possibility to apply this flag only to public functions and members and to delete the annotations for private functions and members?
This is probably also connected to the fact that public members of an interface only work with the above-mentioned flag. Is there a solution that solves the problem with both the interface and the classes?
current Proguard file:
-dontwarn
-dontoptimize
-keepparameternames
-keepattributes Signature, InnerClasses, Exceptions
-keepattributes RuntimeVisibleAnnotations
-keep class custom.package.** {
!private <fields>;
!private <methods>;
}
-keep interface custom.package.** {
!private <fields>;
!private <methods>;
}
obfuscation result with this config:
public class ExampleClass {
private val clearNameAttr: kotlin.String /* compiled code */
private fun clearPrivateMethod (namedParam: kotlin.String) : kotlin.Boolean { /* compiled code */ }
public fun clearPublicMethod (namedParam: kotlin.String) : kotlin.Boolean { /* compiled code */ }
}
desired obfuscation result:
public class ExampleClass {
private String a
private boolean a (String var1) { /* compiled code */ }
public boolean clearPublicMethod (String namedParam) { /* compiled code */ }
}

Error generating signed APK due to proguard rules

Generating signed APK giving error after I updated Android Studio to 3.3-rc01 and enabled R8 code shrinking.
It is giving following proguard error :
Error: ~/app/proguard-rules.pro, offset: 2613, line: 74, column: 7, Expected char '-' at ~/app/proguard-rules.pro:74:7
-dump class_files.txt
before android studio 3.3-rc01 and without R8 code shrinking it was working perfectly fine.
Any workarounds for this or I have to disable the proguard rules now.
Following is my proguard-rules.pro file
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
# Retrofit does reflection on generic parameters and InnerClass is required to use Signature.
-keepattributes Signature, InnerClasses
# Retain service method parameters when optimizing.
-keepclassmembers,allowshrinking,allowobfuscation interface * {
#retrofit2.http.* <methods>;
}
# Ignore annotation used for build tooling.
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
# Ignore JSR 305 annotations for embedding nullability information.
-dontwarn javax.annotation.**
# Guarded by a NoClassDefFoundError try/catch and only used when on the classpath.
-dontwarn kotlin.Unit
# Top-level functions that can only be used by Kotlin.
-dontwarn retrofit2.-KotlinExtensions
# A resource is loaded with a relative path so the package of this class must be preserved.
-keepnames class okhttp3.internal.publicsuffix.PublicSuffixDatabase
# Animal Sniffer compileOnly dependency to ensure APIs are compatible with older versions of Java.
-dontwarn org.codehaus.mojo.animal_sniffer.*
# OkHttp platform used only on JVM and when Conscrypt dependency is available.
-dontwarn okhttp3.internal.platform.ConscryptPlatform
-dontwarn javax.xml.stream.**
-dontwarn rx.internal.util.unsafe.**
#Glide proguard rules
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** {
**[] $VALUES;
public *;
}
-keep class android.support.v7.widget.LinearLayoutManager { *; }
-keep public class * extends android.support.v7.widget.RecyclerView$LayoutManager {
public <init>(...);
}
##---------------Begin: proguard configuration common for all Android apps ----------
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-dontpreverify
-verbose
-dump class_files.txt
-printseeds seeds.txt
-printusage unused.txt
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-allowaccessmodification
-keepattributes *Annotation*
-renamesourcefileattribute SourceFile
-repackageclasses ''
-keep class com.qikcircle.qiketask.models.** { *; }
-keep class android.support.v4.** {*;}
-keep public class * extends android.app.Activity
-keep public class * extends android.support.v4.app.Fragment
-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
-keep public class com.android.vending.licensing.ILicensingService
-dontnote com.android.vending.licensing.ILicensingService
# Explicitly preserve all serialization members. The Serializable interface
# is only a marker interface, so it wouldn't save them.
-keepclassmembers class * implements java.io.Serializable {
static final long serialVersionUID;
private static final java.io.ObjectStreamField[] serialPersistentFields;
private void writeObject(java.io.ObjectOutputStream);
private void readObject(java.io.ObjectInputStream);
java.lang.Object writeReplace();
java.lang.Object readResolve();
}
# Preserve all native method names and the names of their classes.
-keepclasseswithmembernames class * {
native <methods>;
}
-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembernames class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
# Preserve static fields of inner classes of R classes that might be accessed
# through introspection.
-keepclassmembers class **.R$* {
public static <fields>;
}
# Preserve the special static methods that are required in all enumeration classes.
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep public class * {
public protected *;
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
##---------------End: proguard configuration common for all Android apps ----------
##---------------Begin: proguard configuration for Gson ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
# For using GSON #Expose annotation
# Gson specific classes
-keep class sun.misc.Unsafe { *; }
#-keep class com.google.gson.stream.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { *; }
##---------------End: proguard configuration for Gson ----------
#removing logs
-assumenosideeffects class android.util.Log {
public static boolean isLoggable(java.lang.String, int);
public static int v(...);
public static int i(...);
public static int w(...);
public static int d(...);
public static int e(...);
}
#for getting crash reports
-assumenosideeffects class android.util.Log {
public static int v(...);
public static int d(...);
}
#Crashlytics proguard rules
-keepattributes SourceFile,LineNumberTable
-keep public class * extends java.lang.Exception
-ignorewarnings
-keep class * {
public private *;
}
I've tried the dump directive with Proguard (I didn't use it before) and all works fine.
[...]
## Strip Log.d
-assumenosideeffects class android.util.Log {
public static *** d(...);
}
-dump foo.txt
[...]
And I find my foo.txt under ./app/foo.txt
Printing classes to [./app/foo.txt]...
Then I enable R8 in legacy mode:
# For the bravests
android.enableR8=true
# For the crazyest. Must be enable also the previous setting
#android.enableR8.fullMode=true
And I got your error.
Without this line I can compile my APK even in full mode without any (apparent) issue.
So I confirm that this directive is not supported. Remember that R8 is still in beta. If you want you can submit an issue on the link I posted in comment.
Opened the issue here.
for me i had to remove the first line " public private *; " in my prograuard.pro file

Kotlin: Visibility of static nested Java class declared inside a non-visible class

Using java my static-nested java class is visible, but using Kotlin it is not. See my example below. Is there a good reason it is not allowed, or is it a bug? And are there any workarounds so that I can extend NestedStaticClass from Kotlin?
I have a package-private java class containing the static-nested class
package javapackage;
class HiddenClass {
public static class NestedStaticClass {}
}
HiddenClass is extended by a public class.
package javapackage;
public class VisibleClass extends HiddenClass{}
From my java class extending VisibleClass, I can see NestedStaticClass (It compiles)
package otherpackage;
import javapackage.VisibleClass;
public class JavaClass extends VisibleClass {
public static class C4 extends NestedStaticClass {}
public JavaClass() {
new NestedStaticClass();
}
}
But from Kotlin this does not work. I get the compile error: "Unresolved reference NestedStaticClass"
package otherpackage
import javapackage.VisibleClass
class KotlinClass() : VisibleClass() {
class C1() : NestedStaticClass()
init {
val v = NestedStaticClass()
}
}