Com4j integration works fine in my Java application, but not when using Proguard obfuscation (other options turned off). What could I be doing wrong ?
Program hangs at at the COM4J.createInstance(...). I have seen this code stop at the same position before, namely when the Com4j library could not find the underlying com4j.dll native file. However, this code is indeed working without Proguard.
package mypackage;
public abstract class ClassFactory {
private ClassFactory() {}
public static MyInterface createMyComObjectInstance() {
return COM4J.createInstance(MyInterface.class, ComObject_idString );
}
}
The interface is defined thus:
public interface MyInterface extends Com4jObject {....}
Ditto ProGuard config file (tried several variants).
-libraryjars myPath\com4j.jar
-keep public class mypackage.** {*;}
-keep public interface MyInterface {*;}
-keep public abstract class mypackage.ClassFactory {
public static MyInterface createMyComObjectInstance();
//also tried this
*;
}
Note also that Proguard works just fine on the rest of the code, including some JNI/native modules.
Related
I am using an external library(Picasso) from Jcenter in my Android application. I am implementing an interface of that library in my app. The problem is that proguard always strips the methods of the implemented interface in my app.
The interface defined in the external library is
public interface Callback {
void onSuccess();
void onError();
}
And i implement this interface in my code. When i run proguard and check my .class files, i find that there are no onSuccess and onError methods in my implemented class.
I have already added the configurations to skip all that external library completely in my proguard file by adding this
-keep class com.squareup.picasso.** {*;}
-dontwarn com.squareup.picasso.**
One way of preventing the above stripping is that i do this, where PicassoCallback is my implementation of Callback interface
-keep class com.package.className$PicassoCallback{
public void onSuccess();
public void onError();
}
But then i will have to do this for every implementation of the external interface in my project.
Any proguard configuration that can help me to prevent stripping the methods throughout my project?
You can configure ProGuard to keep all classes that implement the Callback interface using this rule:
-keep class ** implements com.squareup.picasso.Callback { *; }
Another way is to add the #Keep annotation to all of you callbacks, which basically tells ProGuard to not strip/modify them in any way.
Just add this line:
-keep interface com.squareup.picasso.** { *; }
after this one:
-keep class com.squareup.picasso.** {*;}
I use several squareup libs so I have the next configuration in my project:
-keep class com.squareup.** { *; }
-keep interface com.squareup.** { *; }
EDIT:
Some useful examples: https://www.guardsquare.com/en/proguard/manual/examples
I've looked at many different tuts. on Youtube and scoured the forums but I've had to result to asking a question.
Everytime I obfuscate my jar file (with Jnative hook library) the main class gets obfuscated too EVEN WHEN I PUT IN THE CONFIG;
-keep public class com.apk.Main {
public static void main(java.lang.String[]);
}
Why is it doing this? I need to obfuscate my work and it simply won't let me...
CONFIG
-injars Native.jar
-outjars Out
-libraryjars 'C:\Program Files\Java\jre1.8.0_121\lib\rt.jar'
-dontshrink
-dontoptimize
-keep,allowshrinking class com.apk.Main
# Keep - Applications. Keep all application classes, along with their 'main'
# methods.
-keepclasseswithmembers public class * {
public static void main(java.lang.String[]);
}
# Also keep - Enumerations. Keep the special static methods that are required in
# enumeration classes.
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# Also keep - Database drivers. Keep all implementations of java.sql.Driver.
-keep class * extends java.sql.Driver
# Also keep the main class
-keep public class com.apk.Main
# and if that doesnt work dont touch the publicstaticvoidmainstringargs
-keep public class com.apk.Main {
public static void main(java.lang.String[]);
}
}
EDIT
So I'm fairly confident that it's because my main class is getting obfuscated, but I have no idea why - since I've created a config which shouldn't do that.
Parent question: Android proguard, keep inner class
My problem is with inner class of inner class
One of the SDKs in my android project has a class A, which has two static inner class. They are found to be stripped after applying proguard.
public class A{
....
static class B{
...
static class D {
....
}
}
static class C{
...
}
}
My proguard looks like this
-keepattributes Exceptions, InnerClasses
-keep class com.xxx.A
-keep class com.xxx.A$*
Which prevents class B, C from proguard. But no luck with class D. I have tried -keep class com.xxx.A$** as well.
I think you're missing the Class specification as shown in the ProGuard manual.
Try replacing:
-keep class com.xxx.A
With:
-keep class com.xxx.** {*;}
I'm using that rule with the following file and it's working fine on Android Studio 2.2.3 with build tools 25.0.1 (just in case those might affect the version of ProGuard being used)
A.java
package com.xxx;
public class A {
....
public class B {
....
public class C {
....
}
}
}
As you can see the only real difference between my file and yours is that my inner classes are public and non-static.
If that doesn't work
You can always use a rule without wildcards. The following will do the trick:
-keep class com.xxx.A$B$D
I have distributed an application on the Android Marketplace. I am getting error reports back in from a small handful of users (maybe 2%) where they are getting NullPointerExceptions where it doesn't make logical sense.
I have never been able to replicate this myself. The code is relatively straightforward and is a common code path that EVERY user has to follow. I've actually taken every separate line of code that could possibly be creating the NPE and wrapped it in a try-catch block and throw a custom runtime exception, but I'm still getting NullPointerException errors not caught.
At this point, the only thing I can imagine it would be is something related to my Proguard obfuscation. I have seen some other article talking about taking out the -overloadaggressively option if you notice odd behavior, but as far as I can tell, I'm not using that option.
Has anybody else experienced mysterious NPEs using android and proguard. Are there any other settings people can recommend to dial down the optimizations that might be causing this issue?
Any other ideas?
For reference, here is the unobfuscated function that is getting the NPE:
public MainMenuScreen(final HauntedCarnival game) {
super(game);
game.startMusic("data/music/intro.mp3");
stage = new Stage(Screen.SCREEN_WIDTH, Screen.SCREEN_HEIGHT,true);
stage.addActor(new Image("background", Assets.mainMenuBackground));
Image title = new Image("title", Assets.mainMenuTitle);
title.x = 0;
title.y = 340;
resetEyeBlink();
stage.addActor(title);
dispatcher.registerInputProcessor(stage);
settings = game.getSettings();
eyeBlinkImage = new Image("eyeBlink", Assets.eyeBlink);
if (settings.getPlayers().isEmpty()) {
settings.addPlayer("Player One");
settings.save(game);
}
setupContinue();
}
So the only possibilities I can see are game, dispatcher and settings.
game gets set via this code in another class. game is a final variable in that other class:
game.setScreen(new MainMenuScreen(game));
dispatcher gets set within in the call to super above.
getSettings() returns a settings object that gets set at the very start of the application, is private and never gets unset. Its also used before this method several times.
There are not auto-boxing primitives.
here is the proguard config:
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-keepattributes Signature
-keep public class com.alkilabs.hauntedcarnival.settings.Settings
-keep public class com.alkilabs.hauntedcarnival.settings.Settings {
*;
}
-keep public class com.alkilabs.hauntedcarnival.settings.Player
-keep public class com.alkilabs.hauntedcarnival.settings.Player {
*;
}
-keepnames public class com.alkilabs.hauntedcarnival.world.World
-keepnames public class * extends com.alkilabs.hauntedcarnival.world.upgrades.Upgrade
-keepnames public class * extends com.alkilabs.hauntedcarnival.world.achievments.Achievement
-keepnames public class com.alkilabs.hauntedcarnival.world.monsters.MonsterType
-keepclassmembers class * extends com.alkilabs.hauntedcarnival.world.monsters.Monster {
public <init>(com.alkilabs.hauntedcarnival.world.monsters.MonsterType, java.lang.Integer, com.alkilabs.hauntedcarnival.world.World);
}
-keepnames public class com.alkilabs.hauntedcarnival.world.items.ItemType
-keepclassmembers class * extends com.alkilabs.hauntedcarnival.world.items.Item {
public <init>(com.alkilabs.hauntedcarnival.world.World, java.lang.Integer, java.lang.Integer);
}
-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
-dontwarn com.badlogic.gdx.scenes.scene2d.ui.utils.DesktopClipboard
-dontwarn com.badlogic.gdx.utils.JsonWriter
-dontwarn com.badlogic.gdx.utils.XmlWriter
-keepclasseswithmembernames class * {
native <methods>;
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}
-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}
-keepclassmembers class * extends android.app.Activity {
public void *(android.view.View);
}
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keep class * implements android.os.Parcelable {
public static final android.os.Parcelable$Creator *;
}
OK, I think I got to the root of the issue/confusion.
One of the things proguard does is in-line some methods. Because of this, the entire contents of my setupContinue() function at the bottom of my constructor was added directly into the contents of my constructor. So now I have a bunch more code to review, and I do see some more possibilities for NPEs. I'm pretty sure I'll get to the bottom of my issue.
I figured this out by taking the obfuscated.jar that proguard produces, and running it through a decompiler. Its an interesting exercise as you get get little more insight into the inner workings of proguard. I highly recommend it for people wanting to better understand the impacts that proguard has on their code.
Your best bet would be to use the mapping.txt file and the retrace tool to find the exact location of the error.
From there it would be easier to understand if it's indeed Proguard or some other end-case you didn't think of.
To do this, you need to copy the stack trace from the developer's console to another file, let's assume it's called
c:\trace.txt
Now, in your project, you'll find a Proguard folder with 4 files.
Let's assume your project is in
c:\project
What you'll need to do is run the retrace tool (using the batch file for easier use) located at (change to the location of your Android Sdk folder) :
c:\android-sdk-windows\tools\proguard\bin\retrace.bat
Go to that folder and run:
retrace c:\project\proguard\mapping.txt c:\trace.txt
From there on, it would be much easier to figure our the exact line of the exception and to probably find the error.
From my experience, the only things that could get messed up are third party libraries. Normal Android code, for all my projects, was never harmed from obfuscation.
Sorry I can't post comments yet (I'm new to SO).
This could be another problem I've encountered myself. On some phones there was a problem at some point with missing Android libraries like a JSon library.
I'd recommend you take a closer look at what phones that actually get the NPE - there might be some similarities.
In my case it was the HTC Desire Z, that was missing the JSon library and so the app force closed every time the JSon part was called. The problem was fixed by HTC later on with a hotfix to the Desire Z's rom.
I use in my project a piece of code as described here
http://lexandera.com/2009/01/extracting-html-from-a-webview/
I create the .apk file, install it on my device and it correctly works. If I try to use the obfuscation with proguard the project fails, the method showHTML(String html) of MyJavaScriptInterface is not reached.
My proguard configuration regarding that
-keep public class com.mypackage.MyClass.MyJavaScriptInterface
-keep public class * implements com.mypackage.MyClass.MyJavaScriptInterface
-keepclassmembers class * implements com.mypackage.MyClass.MyJavaScriptInterface {
<methods>;
}
according to this this answer Android proguard Javascript Interface problem.
SOLVED.
As Eric suggested, I changed the Proguard configuration file like this:
-keep public class com.mypackage.MyClass$MyJavaScriptInterface
-keep public class * implements com.mypackage.MyClass$MyJavaScriptInterface
-keepclassmembers class com.mypackage.MyClass$MyJavaScriptInterface {
<methods>;
}
Now my project works perfectly.
For API 17+ you also need to preserve the #JavascriptInterface annotations:
-keepattributes JavascriptInterface
http://developer.android.com/reference/android/webkit/JavascriptInterface.html
If MyJavaScriptInterface is an inner class of MyClass, ProGuard expects a fully qualified name com.mypackage.MyClass$MyJavaScriptInterface. The naming convention with $ is used in the compiled class files on which ProGuard operates. Note that ProGuard mentions class names in the configuration that it can't find in the input jar, suggesting that these names may have been misspelled.
-keepclassmembers class com.mypackage.MyClass$JavaScriptInterface {
public *;
}
Use only this. It works for me.
Those Who are laze to provide the entire package path.
-keepclassmembers class **.*$PaymentJavaScriptInterface{
public *;
}
As suggested by edit in question,
out of those suggestions,
only using
-keepclassmembers class com.mypackage.MyClass$MyJavaScriptInterface {
public *;
}
with Important -
For API 17+ to preserve #JavascriptInterface annotations:
-keepattributes JavascriptInterface
(Which was stopping my app to work on Marshmallow)