android onClick events and pro guard - android

i'm trying to obfuscate my app before uploading to the market.
i've setup pro guard and i allready handled the Serialzie issue (prog guard maul - serialize) however i still have a problem (MethodNotFoundException) when trying to press one of the buttons in my home screen.
they are simple LinearLayout with background that in the xml have the android:onClick="doOnClick" attribute. in my HomeScreenActivity i have a method named :
public void doOnClick(View v){...}
that should be called whenever a button is pressed.
the code works GREAT when not obfuscated, but once obfuscated android class loader in unable to find my method. Before i move in to use only code and not xml callbacks (maybe advisable) i would like to know if there is a nice way around it.
Trying to prevent method obfuscation did not work for me (trying to prevent obfuscation of methods that extends Activity and are of the form public void on(android.view.View); or public void On(android.view.View).
If anyone have done it i'll appreciate the hint :-)

It's really simple, this should work.
-keepclasseswithmembers class MyActivity {
public void doOnClick(android.view.View);
}

Add this to your proguards file.
-keep class com.android.toto.ClassName {
public void doOnClick(android.view.View);
}

the -keep or keepclasswithmemebers do not apply since i already have -keep public class * extends android.app.Activity which will include ALL Activities.
I managed to find the problem in which the methods had been totally removed by proguard optimization and replaced with direct inline code. This happens because there are no specific calls to those functions in code; note that the XML calls to the code aren't taken into account.
adding the following to the proguard configuration solves the problem:
-keepclassmembers class * extends android.app.Activity {
public void *On*Click(android.view.View);
public void *on*Click(android.view.View);
}

Related

Dynamic Feature with appbundle and PROGUARD not working

OVERVIEW:
I am facing an issue while accessing the activity of the on-demand dynamic feature module from the base module due to proguard. (most probably I guess)
DESCRIPTION:
I have implemented an ON-DEMAND dynamic feature module with app bundle and uploaded on play store.
Implemented proguard with custom rules with it.
After downloading the application from the play store and while accessing that module at runtime, the module gets downloaded. Just after downloading it, I have a call for accessing an activity from my base module to that dynamic module.
I am getting error as like below
...
java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{xxx.yyyyyy.zzzzzz.stage/xxx.yyyyyy.zzzzzz.apphub.appview.view.AppHubActivity}:
java.lang.ClassNotFoundException: Didn't find class "xxx.yyyyyy.zzzzzz.apphub.appview.view.AppHubActivity"
on path: DexPathList[[zip file "/system/framework/org.apache.http.legacy.boot.jar", zip file
...
...
FYI:
xxx.yyyyyy.zzzzzz is my changed package name for privacy.
IRONY:
This entire code is working perfectly in debugging while accessing it from the app bundle locally without proguard.
I have tried all the links below to overcome this but could not.
1) https://issuetracker.google.com/issues/120517460
2) https://github.com/android/plaid/issues/764
3) java.lang.NoClassDefFoundError:failed resolution of :Lorg/apache/http/ProtocolVersion
4) https://issuetracker.google.com/issues/79478779
5) https://github.com/android/app-bundle-samples/issues/17
I have also tried all types of proguard files which we can use, but still helpless.
Also kept that both classes in proguard: base and dynamic module activity class but got no success.
Hopefully looking for the solution here.
UPDATE:
not working in android OS 8,9 but working file in android 10.
I started implementing dynamic feature module this month in my app and proguard was given me issues. I also didn't wanted to push my app to playstore without obfuscating the codes. So this is how i solved this with proguard enabled.
Android proguard optimizer already keeps all classes that extends android.view.View. That means any class that extends the View class will not be obfuscated by proguard.
So i created a class in my featured module and extended View and overrided just the first method because it's not for view in my views hierarchy
public class YourCalssName extends View {
public YourClassName(Context context) {
super(context);
}
public static void launchActivity(Activity activity){
activity.startActivity(new Intent(activity,YourMainActivityInYourFeatureModule.class));
}
}
But Android proguard optimizer doesn't keep method names. Only setters and getters are kept.
So i added a proguard keep rule in my main app to not obfuscate static methods to classes that extends android.view.View
-keepclassmembers public class * extends android.view.View {
public static <methods>;
}
Then i used reflection to call the static method to launch my featured module main activity
Class myClass = Class.forName("your_fully_qualified_name");//Without .class
Method method = myClass.getDeclaredMethod("launchActivity",Activity.class);
method.invoke(null, this) ;
This will keep your class name and methods that launches your featured module activity and it static methods.
Also make sure you add this code to all your activities in your featured module
#Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base)
SplitCompat.installActivity(this);
}
Make sure you use SplitCompat in the activities of your on-demand module AND in your Application.
See https://developer.android.com/guide/playcore#access_downloaded_modules which explains in more details how to do so.

Why some package-private classes are not obfuscated by Proguard?

Working with an Android project in Android Studio 3.2, having enabled Proguard and some specific rules, I'm not able to figure out the following:
a specific package (and its subpackages) in a library module, used by client code, is preserved through the rule:
-keep public class com.mylib.mypackage.** {
public protected *;
}
Now, within this package there are also a number of package-private classes, which should not be picked by that rule. Some of those classes are effectively obfuscated, both in their own names and their member names, which is fine.
Instead there are some classes, implementing public interfaces, whose class names are not obfuscated, while I'd expect they should. For completeness, their member names, when not part of interface, are effectively obfuscated.
Example:
/* package */ class InternalComponent implements ExternalInterface {
// ExternalInterface is kept: Ok
// InternalComponent is kept: don't like, I'd like it renamed
#Override
public void ExternalMethod() {
// this is kept: Ok
}
public void InternalMethod() {
// this is renamed: Ok
}
}
I'd like to highlight that InternalComponent is created within some other (kept) class and only returned to client code through the ExternalInterface.
How can I also obfuscate their class names as well, if possible?
Edit #1
After #emandt answer on Proguard output files, I double checked and com.mylib.mypackage.InternalComponent is listed in seeds.txt, which according to this blog post lists all items matched by keep rules. So, for some reason, the rule above also picks package-private classes, which still seems wrong to me.
Edit #2
In the meantime, I ended up doing exactly the same approach proposed by #shizhen. For completeness, in order to extend the exclusion to any package named internal, I modified my proguard rule as:
-keep public class !com.mylib.mypackage.**.internal.*, com.mylib.mypackage.** {
public protected *;
}
(note the first part before the comma, prefixed by !)
I'll mark #shizhen answer, though I'd like to be curious as to why the original rule is also picking package-private components.
Are you working on an Android Library project? Probably YES.
In order to achieve your purpose, I am afraid that you need to re-organise your packages into something like below:
Public interfaces
com.my.package.apiforusers
Private/Internal implementations
com.my.package.apiforusers.internal
Then for your obfuscation rules, you can have it like below:
-keep public class com.my.package.apiforusers.** { public *; }
So that only the public classes/interfaces are kept and all those ones inside com.my.package.apiforusers.internal will be obfuscated.
Please note the double-asterisk at the end so that public classes/interface are also kept for the sub-packages.
In "/build/outputs/mapping/release/" folder there are few files ("usage.txt", "seeds.txt", etc..) that contain the REASONS of why and which classes/variables/methods/etc.. are not-processed/not-shrinked/ot-obfuscated via ProGuard utilities.

proguard propertie not understood

I am having a hard time understanding what this is doing in proguard:
Does it avoid obfocusing all protected methods in all public classes?
-keep public class * {
public protected *;
}
Please explain or refer to some good explanation
These lines keep all public classes, and inside these public classes, all public and all protected fields and methods. This means that it keeps all public API of the input code, which is suitable for processing libraries.
See the ProGuard manual > Examples > A typical library.

How to get Proguard to `keepclassmembers` of entire package

As title says: How do I get Proguard to keepclassmembers of entire package? Also to net delete methods with void signatures.
To keep all class members (fields and methods) of all classes in a given package and all of its subpackages:
-keepclassmembers class mypackage.** { *; }
This includes void methods. To only keep all void methods:
-keepclassmembers class mypackage.** { void *(...); }
These are unusual settings though, because keeping all class members or all void methods (without even keeping all classes) seems like a very random requirement.
For most configurations, -keep is more appropriate than -keepclassmembers, relevant classes are typically only public ones (matching public class), relevant classes typically extend a specific class or interface (e.g. matching extends somepackage.SomeClass), and relevant class members are typically a very specific set of public methods (e.g. public setters, matching public void set*(***)).

crash using ORMLite on Android with proguard

We're using ORMLite in our Android app. It's working fine, except when we try to do a build with proguard switched on.
I've read various similar posts, and so far I've got in my proguard-project.txt
-keep class com.j256.** {
*;
}
as suggested in the following discussion http://sourceforge.net/p/proguard/discussion/182456/thread/6765bb69
and I've got
-keepclassmembers class * {
public <init>(android.content.Context);
public <init>(android.app.Activity,int);
}
as suggested in another stackoverflow question Proguard with OrmLite on Android
But it still not working. I can get it to run if I add
-dontobfuscate
but that somewhat missing the point of using proguard in the first place.
When I run I get an
IllegalStateException: Could not find OpenHelperClass because none of the generic
parameters of class class <our.package.name>.LaunchActivity extends
OrmLiteSqliteOpenHelper. You should use getHelper(Context, Class) instead.
Where
public class LaunchActivity extends OrmLiteBaseActivity<DatabaseHelper>
and
public class DatabaseHelper extends OrmLiteSqliteOpenHelper
I've added
-keep public class * extends com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper
-keep public class <our.package.name>.LaunchActivity
But still no luck. This question seems to have been asked before (Problems with OrmLite and proguard obfuscation) but I'm hoping somebody will know what the solution is!
The error message mentions generic parameters, so ORMLite is probably using reflection to retrieve generic type information. This information is stored in optional Signature attributes (Java erases generic types), which ProGuard removes by default. You can keep them with
-keepattributes Signature

Categories

Resources