I was using this keywords for obfuscation with proguard in my android-java project :
do
if
for
int
new
try
byte
case
char
else
goto
long
this
void
break
catch
class
const
final
float
short
super
throw
while
double
import
native
public
return
static
switch
throws
boolean
default
extends
finally
package
private
abstract
continue
strictfp
volatile
interface
protected
transient
implements
instanceof
synchronized
but I'm switching to Kotlin and now the question is what keywords should i use for Kotlin ?
I've found this but should i use all of them ?
You are misunderstanding what proguard obfuscates. Proguard operates on Java Bytecode. Giving it a list of keywords from a JVM language really doesn't do anything for your obfuscation.
Related
Is it possible to tell the ProGuard to completely skip the class if there is native function in it ?
-keepclasseswithmembernames class * { native <methods>; }
Above doesn't work for me because it keeps the class names and the native functions names but obfuscates other members
I'd like to know if it's possible to keep everything in such classes without explicitly specifying every class
Thank you
Is it possible to tell the ProGuard to completely skip the class if there is native function in it
Use these rules:
-keepclasseswithmembers class com.your.packages.** {
native <methods>;
}
-keepclassmembers class com.your.packages.** {
native <methods>;
}
Note, that "completely skipping" class with Proguard is a always bad idea, because it may also indirectly keep some classes, used from code of your kept classes. Instead I recommend the following mode:
-keepclasseswithmembers,allowshrinking,allowoptimization class com.your.packages.** {
native <methods>;
}
-keepclassmembers class com.your.packages.** {
native <methods>;
}
It will allow shrinking and optimizing code of non-native methods, present in the same class.
You can do even better: if your native methods are resolved by names (e.g. they are called something like Java_com_your_packages_methodName), and you don't use RegisterNatives to register them explicitly, you may allow shrinking away unused native methods by removing the second rule, which will leave only
-keepclasseswithmembers,allowshrinking,allowoptimization class com.your.packages.** {
native <methods>;
}
If you want some of class members to be accessible from JNI (e.g. you have some static callback methods to be called from native code), you should keep them explicitly: annotate each such member with specialized annotation and use an annotation-based rule to keep them:
-keepclassmembers,allowoptimization,includedescriptorclasses class com.your.packages.** {
#android.support.annotation.Keep *;
}
You can use your own annotation in place of the one from Android support library — in fact, it is better to use your own in order to avoid interference from existing consumer rules, coming from Android Gradle plugin or other libraries.
In general, I recommend you to reduce the amount of friction between JNI and Java code as much as possible. If you have multiple related Java methods, called from JNI, try to put them together in the same method:
#Keep
public static void callback(int action, String arg) {
switch (action) {
...
}
}
Throw your exceptions from Java code (you was going to reflectively invoke their constructors anyway, so may as well invoke a static helper method instead):
#Keep
public static void throwException(int type, String message) {
switch (type) {
case 0:
throw new BadThingsHappenedException(message);
case 1:
throw new AllHopeIsLostError();
...
}
}
If you have a class, that has to be passed to JNI, try to pass individual fields instead of that class:
public final class DataClass {
int intField;
String stringField;
public void doSomeNativeOperation() {
JNI.doSomeNativeOperation(this);
}
}
public final class JNI {
public static void doSomeNativeOperation(DataClass arg) {
doSomeNativeOperation0(arg.intField, arg.stringField);
}
private static native void doSomeNativeOperation0(int intField, String stringField);
}
If you have a native peer class (a class, closely connected to some structure in native memory), you can keep a pointer to native structure in that class in long field, and pass that field to native methods. Then in native methods cast that long to pointer:
public final class Peer {
long pointer;
// constructor is invoked from JNI
#Keep
protected Peer(long pointer) {
this.pointer = pointer;
}
public void doSomeNativeOperation() {
JNI.doSomeNativeOperation(this);
}
}
public final class JNI {
public static void doSomeNativeOperation(Peer peer) {
doSomeNativeOperation0(peer.pointer);
}
private static native void doSomeNativeOperation0(long pointer);
}
And in native code:
void JNIEXPORT Java_com_your_packages_methodName(JNIEnv* env, jobject type, jlong ptr) {
struct my_struct peer = (struct my_struc*) (intptr_t) ptr;
...
}
These simple rules will allow you to fully obfuscate any huge application using JNI, except for a single small class, that contains all native methods.
I suggest you go even further and push for repackaging classes, referenced by native callbacks.
Instead of
#Keep
public static void callback(YourCustomType arg) {
...
}
You can omit a type of parameter by replacing it with Object:
#Keep
public static void callback(Object arg) {
// this cast won't make much difference in performance, but it makes huge
// difference for Proguard!
YourCustomType instance = (YourCustomType) arg;
...
}
This will let you obfuscate and repackage even types of callback arguments.
Use -keep instead of -keepclasseswithmembernames
-keep class * { native <methods>; }
For more info: https://jebware.com/blog/?p=418
-keep disables all of ProGuard’s goodness. No shrinking, no obfuscation; not for classes, not for members.
I would like to log information in model classes - not necessarily for unit testing purposes but for real life scenarios where I am trying to debug.
However, if I try to use android.util.Log methods I get the following errors when running JUnit tests:
java.lang.RuntimeException: Method d in android.util.Log not mocked. See http://g.co/androidstudio/not-mocked for details.
I understand why this occurs, I should not be using Android framework code in model classes that are designed to be framework independent! I'm not really arguing against the error, but rather I am trying to find a way to work around this.
I have one idea, does this make sense?
Create a CustomLog class along these lines:
public class CustomLog {
private static ILogger mLogger;
public static void setLogger(ILogger logger) {
mLogger = logger;
}
public static void e(String tag, String message) {
mLogger.e(tag, message);
}
}
Where ILogger is an interface with the required methods to perform the log functionality (e, d, etc. methods...)
I could create an ILoggerImpl that uses the android.util.Log methods, and a MockLogger class that simply prints out to System.out.println and/or does nothing (or anything else!).
I think that'd perfectly fit my needs (I would be required to setup my CustomLog class very early on in the lifecycle, but that's not a huge deal).
However, if I ever needed to add third party libraries/outside code to my model classes, this would likely break again in the same manner if the new libraries/code use android.util.Log methods.
So, is there a "catch all" type behavior I could use? What do you think?
One way of solving the "Not mocked" exception you cited is to use PowerMockito to mock the Logging methods. Instead of calling PowerMockito.mockStatic(Log.class); as explained in the linked answer, you can take inspiration from this, and use PowerMockito to replace() Android.util's Log.v, Log.d, Log.i & Log.e with methods that will run System.out.println instead. This allows you to see the logged messages in Android Studio's Run window.
String[] logMethods = {"v", "d", "i", "e"};
InvocationHandler systemOutPrintln = new InvocationHandler() {
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
StringBuilder messageBuilder = new StringBuilder();
for (int i = 0; i < args.length; i++) {
String arg = args[i].toString();
messageBuilder.append(arg);
// add separators, ASCII art, ...
}
System.out.println(messageBuilder);
return messageBuilder.toString().length();
}
};
for (String logMethod : logMethods) {
replace(method(Log.class, logMethod, String.class, String.class)).with(systemOutPrintln);
replace(method(Log.class, logMethod, String.class, String.class, Throwable.class)).with(systemOutPrintln);
}
Disclaimer: I'm not sure if the above is the most idiomatic implementation.
I'm using codes as shown below, but somehow everything is working perfectly fine in debug version but as soon as I compile release version of the app, I get the error.
no such column: IMAGE_ID
Currently using sugarORM version 1.3 also using proguard
public class Favorite extends SugarRecord<Favorite> {
private int imageId;
private int licenseId;
public Favorite(int imageId, int licenseId){
this.imageId = imageId;
this.licenseId = licenseId;
}
}
This is the query i am using to find the image_id
List<Favorite> favorites = Favorite.find
(Favorite.class, "IMAGE_ID = ?", ((String) ("" + imageId)));
if (!favorites.isEmpty()) {
return favorites.get(0);
}
I've tried using image_id Image_Id image_Id image_ID and few other
but I always get error
`no such column exception in my release version of my application.
I have also tried many suggestion asked in the such type of question(s) but nothing is working as expected.
AS #Harsh mentioned you need to add rules to skip the obfuscation of classes are extending SugarRecord and SugarApp.This is just another way of doing the same thing.
#skip every public class that extends com.orm.SugarRecord
#and their public/protected members
-keep public class * extends com.orm.SugarRecord {
public protected *;
}
-keep class com.orm.** { *; }
Related Issues
https://github.com/satyan/sugar/issues/219
https://github.com/satyan/sugar/issues/395
Extra:
Use following rule to enable line numbers in logcat when running a proguard enabled apk build, be sure to remove when publishing.
-keepattributes SourceFile,LineNumberTable
Otherwise logcat lines will be like following
at android.support.v4.app.Fragment.b(Unknown Source)
Make sure to remove it when publishing.
I'm using SugarORM with proguard, which also obfuscate the model ( databases ) classes.
In order to use SugarORM with proguard you need to update proguard setting so that will it not obfuscate your database classes.
-keep public class com.youcompany.appname.xx.<ClassName> extends SugarRecord{*;}
-keep public class com.youcompany.appname.XX.<ClassName> extends SugarApp{*;}
Iam facing with XmlGregorianCalendar convertion issue on android 2.3.X application project
iam building an android 2.3.X application that interact with Rest Services. Some objects provided by thes services have XMLGregorianCalendar datatype . these object classes have been generate throuth JAXB Binding.
on the android side i got the solution on using Gson to deserialise an serialise XMLGregorianCalendar datatype by this code
public class XMLGregorianCalendarConverter {
public static class Serializer implements JsonSerializer{
public Serializer(){
super();
}
#Override
public JsonElement serialize(Object t, Type type, JsonSerializationContext context) {
XMLGregorianCalendar xgcal = (XMLGregorianCalendar) t;
return new JsonPrimitive(xgcal.toXMLFormat());
}
}
public static class Deserializer implements JsonDeserializer{
#Override
public Object deserialize(JsonElement t, Type type, JsonDeserializationContext context) {
try
{
return DatatypeFactory.newInstance().newXMLGregorianCalendar(t.getAsString());
}
catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
}
this code worked fine in java desktop environment. but in android i got some Logcat saying "xerces.jaxp.datatype.DataTypeFactoryImpl not found".
I tryed to include xerces from apache as mentioned in one workaround for this kind of problem in this forum. but i got some dalvik error and i was unable to build my project.
please i need help on how to fix this. I dont want to change anything on the Rest side.
If you use proguard, then you can try to add this to the proguard.txt file:
-dontwarn org.apache.xml.resolver.**
-dontwarn org.xml.sax.**
I am creating a library project for a number of android apps.
The apps all have some common functionality that I wish to include in the library project but the library project functions require use of application specific constants
So I am looking for a way to provide the library functions with the names of the constants and allow each app to define them
An example of a specific app constant and how it is used within the library project
public class AppConstants {
public static final long APP_ID = 6;//Needs to be set for each app
}
public static long getCurrentAppId(Context context) {
return getLongPreference(context, CURRENT_APP_ID_KEY, AppConstants.APP_ID);
}
This is just one example of approximately 60 constants that need to be defined for each app for a large number of library functions
Obviously I would normally just import/include the project specific app_constants.java file but this is not possible in the library project files as it hasn't got a clue about the specific applications (rightly so)
So what is the best way to have each specific app override the constants?
Update
I took a long time deciding on which of the superb answers I have been provided with best suited my needs (Thanks everyone) In the end I chose the xml solution. I don't particularly like it because it clutters up my apps resources and I did seriously consider using the interface solution but the xml solution does work nicely
Option #1
Extend your AppConstants class in each project
Better Option#2
Use XML resources to define the constants
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item type="integer" name="app_id" format="integer">6</item>
</resources>
then you can retrieve them by
Context.getResources().getInteger(R.integer.app_id);
add the xml file to your resources in each project with only the values you need different
I don't know of a great schema to do that but it would certainly work this way:
define some base class in your library
// class, enum or whatever you want it to be.
class BaseConstants {
// use some real singleton instead
public static final BaseConstants instance = new BaseConstants();
// define those values - sadly static inheritance does not work
private static final int APP_ID = 0;
private static final int CURRENT_APP_ID_KEY = 24;
// so we have to do that via methods
protected int getAppId() {
return APP_ID;
}
protected int getAppIdKey() {
return CURRENT_APP_ID_KEY;
}
}
let each Activity that wants something custom implement that
class App1Constants extends BaseConstants {
public static final App1Constants instance = new App1Constants();
private final static int APP_ID = 1;
// want a different APP_ID here.
protected int getAppId() {
return APP_ID;
}
// getAppIdKey not implemented here, uses default
}
Use that class as context to the constants for your library
class Library {
public static long getCurrentAppId(Context context, BaseConstants settings) {
return getLongPreference(context, settings.getAppIdKey(), settings.getAppId());
}
}
Activities would be like so
class myActivity extends Activity {
// each Activity can implement it's own constants class and overwrite only some values
private static final BaseConstants CONSTANTS = App1Constants.instance;
private void whatever() {
long appId = Library.getCurrentAppId(this, CONSTANTS);
}
}
class myActivity2 extends Activity {
// or could just use the default ones
private static final BaseConstants CONSTANTS = BaseConstants.instance;
private void whatever() {
long appId = Library.getCurrentAppId(this, CONSTANTS);
}
}
That schema is kind of ugly but it would work at least
Define them as enum's in your library project, like
public enum Planet { MERCURY, VENUS, MARS }
Android proper takes another approach, the dreaded constant interface, like,
interface Planets {
static final int MERCURY = 1;
static final int VENUS = 2;
...
}
However, this is a well-known Java anti-pattern (constant interface, and is covered in detail in Effective Java, I quote,
The constant interface pattern is a poor use of interfaces. That a
class uses some constants internally is an implementation detail.
Implementing a constant interface causes this implementation detail to
leak into the class’s exported API. It is of no consequence to the
users of a class that the class implements a constant interface. In
fact, it may even confuse them. Worse, it represents a commitment: if
in a future release the class is modified so that it no longer needs
to use the constants, it still must implement the interface to ensure
binary compatibility. If a nonfinal class implements a constant
interface, all of its subclasses will have their namespaces polluted
by the constants in the interface.
If you need the constants to have int values for some reason, and calling toString() on the enum isn't sufficient, you can give the enum's a extra information like,
public enum ZipCode {
LYNNWOOD(98036), SAN_JOSE(95112), ...;
private int zipCode;
private ZipCode(int zipCode) { this.zipCode = zipCode; }
public int getZipCode() { return zipCode; }
}
Note that enum's are slightly less performing than integer constants, but from a code organization and clarity perspective they are far superior.