Cannot solve dynamic reference to constructor - java

I have been trying to fix this problem for a week now. I create a shadowJar (uber jar) and it starts fine. When I run obfuscation, I get an error on startup:
Caused by: java.lang.UnsatisfiedLinkError: Can't obtain peer field ID for class com.sun.jna.Pointer
I have been using Proguard to run obfuscation and I always get this after the process
"Note: com.sun.jna.Structure accesses a constructor '(com.sun.jna.Pointer)' dynamically"
Here is a snippet of my .pro file:
-dontshrink
-dontoptimize
-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,LocalVariable*Table,*Annotation*,Synthetic,EnclosingMethod
-keep class com.sun.jna.** {
<fields>;
<methods>;
}
-keep,allowshrinking class com.sun.jna.** {
<fields>;
<methods>;
}
Am I doing it wrong or missing something important? I am assuming the message after processing is related to the start-up error I have from the obfuscated jar.

Related

R8: NullPointerException during IR Conversion

I have a problem when trying to generate a release version of my app. It gives a strange error
C:\Users\rshal\.gradle\caches\transforms-2\files-2.1\6c326691eb00442622017dd95f96e92a\jetified-firebase-config-19.1.3-runtime.jar: R8: NullPointerException during IR Conversion
> Task :app:minifyProdReleaseWithR8 FAILED
I have been using firebase analytics and firebase remote config without problems. And also I had no issue this R8 minimization.
Recently I have integrated google-speech-api and after that, I am not able to use R8.
I did not have this problem until I integrated google-speech-api in the app. I know that google-speech-api is not officially supported on Android. Maybe that is the core issue. Before that, I had an issue with firebase-config dependency. It is not compatible with the google-speech-api library I think. I solved that issue with this Gradle configuration
implementation('com.google.firebase:firebase-config', {
exclude group: 'com.google.protobuf' // google-cloud-speech causes this. see https://github.com/firebase/firebase-android-sdk/issues/1143
})
I have followed this fix.
Now I am stuck with this error that I showed above.
I have tried different versions on R8 as suggested here
This is gradle build log
> Task :app:minifyProdReleaseWithR8
R8: Missing class: org.apache.logging.log4j.spi.ExtendedLoggerWrapper
R8: Missing class: org.eclipse.jetty.npn.NextProtoNego$ClientProvider
R8: Missing class: javax.servlet.ServletContextListener
R8: Missing class: org.jboss.marshalling.ByteOutput
R8: Missing class: java.lang.ClassValue
R8: Missing class: org.eclipse.jetty.alpn.ALPN$ClientProvider
R8: Missing class: org.jboss.marshalling.ByteInput
R8: Missing class: org.eclipse.jetty.alpn.ALPN$ServerProvider
R8: Missing class: org.eclipse.jetty.npn.NextProtoNego$ServerProvider
R8: Library class android.net.http.AndroidHttpClientConnection implements program class org.apache.http.HttpInetConnection
R8: Library class android.net.http.AndroidHttpClientConnection implements program class org.apache.http.HttpConnection
C:\Users\rshal\.gradle\caches\transforms-2\files-2.1\6c326691eb00442622017dd95f96e92a\jetified-firebase-config-19.1.3-runtime.jar: R8: NullPointerException during IR Conversion
> Task :app:minifyProdReleaseWithR8 FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:minifyProdReleaseWithR8'.
> com.android.tools.r8.CompilationFailedException: Compilation failed to complet
this is build.gradle file
this is top-level Gradle file
Answering my own question because it turned out to be an R8 bug and after me reporting it, they solved the issue. Which is great.
Full bug report and how to apply fix is here
Short version:
change gradle configuration to this
buildscript {
repositories {
maven {
url 'https://storage.googleapis.com/r8-releases/raw'
}
}
dependencies {
classpath 'com.android.tools:r8:1.6.88' // Must be before the Gradle Plugin for Android.
classpath 'com.android.tools.build:gradle:3.6.2'
}
}
I have encountered this bug when implementing Google Speech API in my android app.
For anyone who might need it, this is my final groguard configuration
-keep class com.google.api.gax.** {*;}
-keep class com.google.cloud.** {*;}
-keep class com.google.api.services.translate.** {*;}
-keep class com.google.api.client.util.** {*;}
-keep class com.google.api.client.googleapis.** {*;}
-keep class com.google.cloud.speech.v1.stub.** {*;}
-keep class io.grpc.** {*;}
-keep class com.google.auth.oauth2.** {*;}
-keep class com.google.auth.** {*;}

Let ProGuard touch only one class

I am working on an app that someone else wrote and i am trying to only obfuscate the classes that I added. I've seen this post: With ProGuard, how do I obfuscate just one class?
I tried my luck with that (I added a single class and configured ProGuard as shown in the above post) and had only partial success.
It seems like ProGuard is still touching all the other files (md5 hashes change).
This is my ProGuard config:
-dontshrink
-dontoptimize
-dontpreverify
-dontnote
-dontwarn
-target 1.8
-keep class !com.example.Test { *; }
You should also try keeping all the other packages, like:
-keep class com.my.example.** { *; }
When you use a rule containing an exclusion pattern like that:
-keep class !com.example.Test { *; }
it will internally be treated like this:
-keep class !com.example.Test,** { *; }
The ** at the end is implicit and doesn't have to be added. Basically you are trying to say "keep all classes except com.example.Test" (and their methods/fields of course).

ProGuard SimException

I'm trying to get ProGuard to work, after roughly 4 hours of randomly trying options to try and get this amazing software to work.
My project is using LibGDX and KryoNet. This is my current ProGuard configuration:
-verbose
-dontobfuscate
-dontwarn android.support.**
-dontwarn com.badlogic.gdx.backends.android.AndroidFragmentApplication
-dontwarn com.badlogic.gdx.utils.GdxBuild
-dontwarn com.badlogic.gdx.jnigen.BuildTarget*
-dontwarn com.badlogic.gdx.graphics.g2d.freetype.FreetypeBuild
-keepclassmembers class com.badlogic.gdx.backends.android.AndroidInput* {
<init>(com.badlogic.gdx.Application, android.content.Context, java.lang.Object, com.badlogic.gdx.backends.android.AndroidApplicationConfiguration);
}
# Kryo
-dontwarn sun.reflect.**
-dontwarn java.beans.**
-dontwarn sun.nio.ch.**
-dontwarn sun.misc.**
-keep class com.esotericsoftware.kryo.** {*;}
-keep class com.esotericsoftware.** {*;}
-keep class java.beans.** { *; }
-keep class sun.reflect.** { *; }
-keep class sun.nio.ch.** { *; }
This does not compile. It throws multiple of the following errors: Uncaught translation error: com.android.dx.cf.code.SimException: local variable type mismatch: attempt to set or access a value of type float using a local variable of type int. This is symptomatic of .class transformation tools that ignore local variable information.
I found some information about this error: Compile with Proguard gives SimException: "local variable type mismatch".
The solution given was to edit some main-rules.xml file from ANT, but I'm using Gradle. A comment was posted with a fix for Gradle : to add project.tasks.withType(com.android.build.gradle.tasks.Dex) { additionalParameters=['--no-locals'] }. But apparently the Dex class is removed, so this no longer works.
I read this is a bug in ProGuard, and that obfuscating should fix it. But when I remove the -dontobfuscate line, my app does not start anymore: java.lang.UnsatisfiedLinkError: No implementation found for void com.a.a.c.a.k.g() (tried Java_com_a_a_c_a_k_g and Java_com_a_a_c_a_k_g__).
Does anyone know how to work around these issues?
The problem might be related to a specific optimization of ProGuard.
You can disable it like that:
-optimizations !code/allocation/variable
Furthermore you can also remove the LocalVariableTable and LocalVariableTypeTable attributes which do not seem to be updated properly (and are not needed in an application anymore). For this you would need to enable obfuscation though and then use something like:
-keepattributes !LocalVariable*,**
This rule would keep all attributes but the LocalVariable related ones.
The obfuscation problem with libGDX might be solved by this rule:
# Keep names - Native method names. Keep all native class/method names.
-keepclasseswithmembers,includedescriptorclasses class * {
native <methods>;
}

How to make ProGuard work in a simple way?

I tested ProGuard on a simple application. It works very well. However, when i tried to use it on something more complex, it thows all types of warnings and error like one class depends on other or a class tries to use reflection etc.
This is the configuration
-injars Test.jar
-outjars Test2.jar
-libraryjars <java.home>/lib/rt.jar
-libraryjars <java.home>/lib/jce.jar
-printmapping myapplication.map
-keep class com.teradata.** {*;}
-keep class org.quartz.** {*;}
-keep class org.terracotta.** {*;}
-keep class com.sun.** {*;}
-keep class javax.** {*;}
-keep class org.apache.** {*;}
-keep class org.slf4j.** {*;}
-keep class com.** {*;}
-keep public class com.test.Main {
public static void main(java.lang.String[]);
}
Is there any simple way to make it work. If something should be in -keep, can it automatically do so? Process as much as it can, and leave the rest .
I also tried the gui version . But I couldn't figure out how to -keep the jars.
Also it's too verbose even without the verbose keyword . I can't get to the root of the problem because of enormous number of the duplicate error message like Maybe blah blah and then the same thing again and again .
Is there any simple way to just make it work ?
If you do not want to be bothered by looking at the warnings and fix them appropriately (or use -dontwarn directives to ignore harmless ones), you can use the -ignorewarnings directive, which will instruct ProGuard to keep processing your application even if there are some warnings remaining.

Proguard warnings despite kept classes

I'm using Proguard to shrink my code. My strategy is to enable it and then follow the warnings to keep anything it complains about. If there are outside libraries, I try to follow the Proguard instructions the authors make available. Many instructions include a -dontwarn flag. If I disable the -dontwarn flag, I will get warnings. If we are keeping most classes via -keep flag, why do warnings still come up?
Example:
-keep class javax.** { *; }
# for butterknife
-keep class butterknife.** { *; }
-dontwarn butterknife.internal.**
-keep class **$$ViewBinder { *; }
-keepclasseswithmembernames class * {
#butterknife.* <fields>;
}
-keepclasseswithmembernames class * {
#butterknife.* <methods>;
}
Warning:butterknife.internal.ButterKnifeProcessor: can't find referenced class javax.annotation.processing.AbstractProcessor
Warning:butterknife.internal.ButterKnifeProcessor: can't find referenced class javax.annotation.processing.ProcessingEnvironment
Warning:butterknife.internal.ButterKnifeProcessor: can't find referenced class javax.lang.model.element.TypeElement
Warning:butterknife.internal.ButterKnifeProcessor: can't find referenced class javax.lang.model.element.Element
Warning:butterknife.internal.ButterKnifeProcessor: can't find referenced class javax.annotation.processing.Filer
Warning:butterknife.internal.ButterKnifeProcessor: can't find referenced class javax.tools.JavaFileObject
...
There are many warnings in ProGuard meaning different things. This particular one:
Warning:A: can't find referenced class B
Means that while ProGuard was processing class A it encountered reference to class B. But class B wasn't included as a source (-injars class_path) or as a library (-libraryjars class_path).
First note that for this particular warning in case of standard Android build chain adding -keep rules will not help. ProGuard transitively keeps referenced code.
This warning can happen for several reasons. Often a library X can contain code that uses another library Y. And X uses Y optionally - only when Y is present on the classpath, X doesn't enforce presence of Y. This way ProGuard is unable to find classes from Y.
To get rid of the warnings you have to either add Y as a dependency or ignore the relevant warnings.
In case of ButterKnife the situation is slightly different. Butterknife uses annotation processing. And it contains both the library and annotation processor in one dependency (latest version 7.0.1). So class butterknife.internal.ButterKnifeProcessor is still present in the compiled classes (even though it's work is already finished - used during java compilation). And ProGuard tries to process it. ProGuard fails to find the missing classes because they were used only during annotation processing and are not present for ProGuard processing.
In this case it's really necessary to ignore the warnings.

Categories

Resources