I have the following ViewModel:
class SignInViewModel #Inject constructor(val api: BillingApi) : ViewModel() {
val googleApiClient: MutableLiveData<GoogleApiClient> = MutableLiveData()
}
On my Activity.onCreate(onSavedInstanceState: Bundle?) I have:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
...
signInViewModel = ViewModelProviders.of(this)
.get(SignInViewModel::class.java)
signInViewModel.googleApiClient.observe(this, Observer<GoogleApiClient?> {
... // here never gets trigged
}
Later on my code I have signInViewModel.googleApiClient.value = it. At this point (which happens after a button click, so I am in a resumed state) the I expected the LiveData to trigger my observer, but it does not.
While debugging I've noticed that my MutableLiveData is never on an active state.
What am I doing wrong? Please, I know I am using a GoogleApiClient instance in the example and that it should be initialized with the Activity with automanage and whatnot, but this is not the issue here. I want to set it dynamically and have my observer be triggered.
Edit: adding the code that calls the setValue
signInViewModel.someMethod(this)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(Consumer {
// This gets called but the observe callback does **not**
signInViewModel.googleApiClient.value = it
}, errorCallback)
It turns out minifyEnabled was true. I haven't seen anything about proguard rules for architecture components.
Found this issue which is not resolved yet but has the configuration needed to make it pass:
-keepclassmembers class * implements android.arch.lifecycle.LifecycleObserver {
<init>(...);
}
-keepclassmembers class * extends android.arch.lifecycle.ViewModel {
<init>(...);
}
-keepclassmembers class android.arch.lifecycle.Lifecycle$State { *; }
-keepclassmembers class android.arch.lifecycle.Lifecycle$Event { *; }
-keepclassmembers class * {
#android.arch.lifecycle.OnLifecycleEvent *;
}
-keep class * implements android.arch.lifecycle.LifecycleObserver {
<init>(...);
}
Related
I have a view binding extension for activity. Here is the implementation :
inline fun <reified T : ViewBinding> Activity.viewBinding() = ActivityViewBindingDelegate(T::class.java)
class ActivityViewBindingDelegate<T : ViewBinding>(private val bindingClass: Class<T>) : ReadOnlyProperty<Activity, T> {
/**
* initiate variable for binding view
*/
private var binding: T? = null
#Suppress("UNCHECKED_CAST")
override fun getValue(thisRef: Activity, property: KProperty<*>): T {
binding?.let { return it }
/**
* inflate View class
*/
val inflateMethod = bindingClass.getMethod("inflate", LayoutInflater::class.java)
/**
* Bind layout
*/
val invokeLayout = inflateMethod.invoke(null, thisRef.layoutInflater) as T
/**
* Set the content view
*/
thisRef.setContentView(invokeLayout.root)
return invokeLayout.also { this.binding = it }
}
}
When i run my app in debug variant, everything works fine.
When i run my app in release variant, at runtime when activity launching i get the following exception :
Caused by: java.lang.NoSuchMethodException: com.x.y.z.j.h1.inflate [class android.view.LayoutInflater]
isMinifyEnabled = true
isShrinkResources = true
I must obfuscate my activity. How to solve this problem ?
Add in proguard-rules
-keepclassmembers class ** implements androidx.viewbinding.ViewBinding {
public static ** bind(***);
public static ** inflate(***);
}
bindingClass.getMethod("inflate", LayoutInflater::class.java)
and
bindingClass.getMethod("bind", View::class.java)
are obfuscated with R8 obfuscation. Thus I get this exception. We should exclude obfuscation for inflate and bind methods.
Thus the following must be added to use the view binding extension function for fragment and activity
-keep class com.sample.myapplication.databinding.* {
public static ** inflate( ** );
public static ** bind( ** );
}
It solved my problem.
I have a class with a companion object which implements a factory interface.
class GoalInspectorData(
...
) {
companion object : DataClassFactory<GoalInspectorData> {
override fun fromV8Object(v8Object: V8Object): GoalInspectorData {
...
}
}
}
I have some code which examines this class at runtime using reflection to see if the class provides a factory method. It does this by checking to see if the class has a companion object (companionObjectInstance) and, if so, if that companion object implements the factory interface.
internal inline fun <reified T> convert(obj: Any): T {
val companionObject = T::class.companionObjectInstance
#Suppress("UNCHECKED_CAST")
return when {
T::class in builtInClasses -> obj as T
companionObject as? DataClassFactory<T> != null -> companionObject.fromV8Object(obj as V8Object)
else -> throw IllegalArgumentException("No converter for type ${T::class}")
}
}
This all works fine in a debug build.
It fails in a release build with R8 enabled (minifyEnabled true in build.gradle). It fails because companionObjectInstance returns null.
I'm using the don't optimize Proguard config:
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
and in my own proguard-rules.pro I've added just about every -keep rule I can imagine in an attempt to retain this companion object, and added #Keep annotations to everything, but nothing works. R8 is determined to strip it out.
For example:
-keep class my.package.** {
*;
}
-keep interface my.package.** {
*;
}
-if class **$Companion extends **
-keep class <2>
-if class **$Companion implements **
-keep class <2>
Are there any other -keep rules or configuration options which would instruct R8 to retain this companion object?
First of all, the keep rule
-keep class my.package.** {
*;
}
should be sufficient to keep all the classes - including companion classes in your program. You should not need the -dontoptimize flag, so using the configuration proguard-android-optimize.txt should be fine.
However, as you use Kotlin reflection you probably also need to keep the annotation class kotlin.Metadata and runtime visible annotations with these rules:
-keep #interface kotlin.Metadata {
*;
}
-keepattributes RuntimeVisibleAnnotations
If that does still not work could you please file an R8 issue? If you can include a simple reproduction that would be great.
In my project, I am performing API call using RxJava.
Without proguard, it is running fine. But when I apply proguard It gives java.lang.AssertionError: java.lang.NoSuchFieldException: HTTP_1_0
in onError(e: Throwable) of a subscriber.
I applied -keepclassmembers enum * { *; } in my proguard to prevent obfuscation.
Api Call
fun latestPosts(): Subscription {
return service.latestPosts
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(APICallSubscriber(presenterContract, ApiIndex.POSTS))
}
Subscriber
class APICallSubscriber<T>(private val callback: BasePresenterContract,
private val apiIndex: String) : Subscriber<Response<T>>() {
override fun onCompleted() {
}
override fun onError(e: Throwable) {
Log.d("HomeTest", "${e}")
}
override fun onNext(response: Response<T>) {
val jsonObject = App.gson().toJsonTree(response).asJsonObject
val responseCode = jsonObject
.get(PayloadKeys.RAW_RESPONSE).asJsonObject
.get(PayloadKeys.CODE).asInt
Log.d("HomeTest", "$jsonObject")
val body: JsonElement? = jsonObject.get(PayloadKeys.BODY)
if (body != null) {
val responseBody = body.asJsonObject
callback.onNetworkRequestCompletedWith(responseBody, responseCode, apiIndex)
} else {
val errorBody: JsonElement? = jsonObject.get(PayloadKeys.ERROR_BODY)
callback.onNetwordRequestError(errorBody!!.asJsonObject, apiIndex)
}
}
}
I have tried different proguard rules but no result.
Please help.
In case this helps anyone, I had an existing project with a library module I had made. To prevent my app from crashing after being minified by ProGuard, I needed to add
-keepclassmembers enum * { *; }
to not only the library's build.gradle, but also to the main module's build.gradle.
I was facing the same issue, I solved by adding all these in proguard-rules.pro file:
-keepclassmembers enum * { *; }
-keep class com.google.code.gson.* { *; }
-keepattributes *Annotation*, Signature, Exception
-keepclassmembers,allowobfuscation class * {
#com.google.gson.annotations.SerializedName <fields>;
}
below configuration always worked for me
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
In my current Kotlin Android project I just had to face the following problem:
For this class hierarchy
abstract class MyClass {
...
}
class MySubClassA: MyClass() {
...
}
class MySubClassB: MyClass() {
...
}
class MySubClassC: MyClass() {
...
}
I wrote a creator function like this:
private fun <T : MyClass> createMyClass(myClassType: KClass<T>): T? {
val constructor = myClassType.primaryConstructor
return constructor?.call()?.apply {
...
}
}
This worked nicely for the debug version but for the release version with R8 obfuscation turned on the constructor was alway null. My settings for R8 were this:
-keep class kotlin.** { *; }
-keep class kotlin.Metadata { *; }
-dontwarn kotlin.**
-keepclassmembers class **$WhenMappings {
<fields>;
}
-keepclassmembers class kotlin.Metadata {
public <methods>;
}
-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
static void checkParameterIsNotNull(java.lang.Object, java.lang.String);
}
-keep class kotlin.reflect.jvm.internal.impl.builtins.BuiltInsLoaderImpl
After some reverse engineering of the Kotlin reflection API I came up with the following workaround:
private fun <T : MyClass> createMyClass(myClassType: KClass<T>): T? {
val constructor = myClassType.constructors.firstOrNull() {
it.valueParameters.isEmpty()
}
return constructor?.call()?.apply {
...
}
}
This seems to indicate, that the constructor information of the class is preserved by R8 but the meta information about a constructor being primary gets lost.
Does anybody know how to solve this in general?
I came across this issue and was able to resolve it using the #Keep annotation.
abstract class MyClass {
}
class MySubClassA #Keep constructor(): MyClass() {
}
class MySubClassB #Keep constructor(): MyClass() {
}
class MySubClassC #Keep constructor(): MyClass() {
}
Here's a very simple class:
class MainActivity : AppCompatActivity() {
val prop: String = "test"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d("MainActivity", ::prop.name)
}
}
If I run this application with ProGuard using the following rules:
-dontwarn kotlin.**
-dontwarn org.w3c.dom.events.*
-dontwarn org.jetbrains.kotlin.di.InjectorForRuntimeDescriptorLoader
I get this exception:
a.d.g: Property 'prop' not resolved in class com.cypressworks.kotlinreflectionproguard.MainActivity
Which ProGuard rules do I need to apply to make it work?
If ProGuard is removing your attribute, the dontwarn rule will only hide the warning messages. What you need is to actually tell ProGuard to keep it.
One possible way could be:
-keepclassmembers public class com.cypressworks.kotlinreflectionproguard.** {
public * *;
}