简体   繁体   中英

ProGuard obfuscation leads to ClassNotFoundException

I try to obfuscate my code by ProGuard, but when I do that, it does not even find the initial Activity defined in AndroidManifest anymore (ClassNotFoundException).

This is how the Activity looks:

public class LoadingActivity extends Activity
{
    private static final String TAG = LoadingActivity.class.getSimpleName();
    private int effectiveWidth;
    private int effectiveHeight;
    private AsyncTask<Void, Void, Void> bitmapLoaderTask;

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_loading);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);

        initSpecs();
    }

    @Override
    protected void onPause()
    {
        super.onPause();

        if (bitmapLoaderTask != null)
        {
            bitmapLoaderTask.cancel(true);
        }
    }

    @Override
    protected void onStart()
    {
        super.onStart();

        if (ResizedBitmapMapping.isStillHoldingAllImages())
        {
            Logger.log(TAG, "ResizedBitmapMapping still contains all images, skip loading...", LogController.isLoggingEnabled(), Log.DEBUG);

            startMenu();
        }
        else
        {
            bitmapLoaderTask = new BitmapLoaderTask(getResources(), effectiveWidth, effectiveHeight, this);
            bitmapLoaderTask.execute();
        }
    }

    @SuppressWarnings("deprecation")
    private void initSpecs()
    {
        PackageNameHolder.setPackageName(getPackageName());

        WindowManager windowManager = (WindowManager)this.getSystemService(Context.WINDOW_SERVICE);
        Point size = new Point();

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2)
        {
            windowManager.getDefaultDisplay().getSize(size);

            effectiveWidth = size.x;
            effectiveHeight = size.y;
        }
        else
        {
            Display display = windowManager.getDefaultDisplay();

            effectiveWidth = display.getWidth();
            effectiveHeight = display.getHeight();
        }
    }

    public void startMenu()
    {
        final Intent gameIntent = new Intent(this, MenuActivity.class);
        startActivity(gameIntent);
        overridePendingTransition(0, 0);
    }

    public void cancel()
    {
        finish();
    }
}

My proguard.cfg looks like this:

-dontoptimize 
-dontshrink
-verbose

-keep class com.chartboost.** { *; }

-keep class * extends java.util.ListResourceBundle {
    protected Object[][] getContents();
}

-keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
    public static final *** NULL;
}

-keepnames @com.google.android.gms.common.annotation.KeepName class *
-keepclassmembernames class * {
    @com.google.android.gms.common.annotation.KeepName *;
}

-keepnames class * implements android.os.Parcelable {
    public static final ** CREATOR;
}

For testing I added

-keep class com.myproject.** { *; }

then, the app works, but it's not obfuscated (which is clear). Any ideas how to obfuscated properly? Actually this is something ProGuard has to care about, right?

This is the error message while starting the app:

10-25 00:29:04.600: E/AndroidRuntime(3299): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.mydomain.myapp/com.mydomain.myapp.LoadingActivity}: java.lang.ClassNotFoundException: com.mydomain.myapp.LoadingActivity in loader dalvik.system.PathClassLoader[/data/app/com.mydomain.myapp-2.apk]
10-25 00:29:04.600: E/AndroidRuntime(3299):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1680)
10-25 00:29:04.600: E/AndroidRuntime(3299):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1784)
10-25 00:29:04.600: E/AndroidRuntime(3299):     at android.app.ActivityThread.access$1500(ActivityThread.java:123)
10-25 00:29:04.600: E/AndroidRuntime(3299):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:939)
10-25 00:29:04.600: E/AndroidRuntime(3299):     at android.os.Handler.dispatchMessage(Handler.java:99)
10-25 00:29:04.600: E/AndroidRuntime(3299):     at android.os.Looper.loop(Looper.java:130)
10-25 00:29:04.600: E/AndroidRuntime(3299):     at android.app.ActivityThread.main(ActivityThread.java:3835)
10-25 00:29:04.600: E/AndroidRuntime(3299):     at java.lang.reflect.Method.invokeNative(Native Method)
10-25 00:29:04.600: E/AndroidRuntime(3299):     at java.lang.reflect.Method.invoke(Method.java:507)
10-25 00:29:04.600: E/AndroidRuntime(3299):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:864)
10-25 00:29:04.600: E/AndroidRuntime(3299):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:622)
10-25 00:29:04.600: E/AndroidRuntime(3299):     at dalvik.system.NativeStart.main(Native Method)
10-25 00:29:04.600: E/AndroidRuntime(3299): Caused by: java.lang.ClassNotFoundException: com.mydomain.myapp.LoadingActivity in loader dalvik.system.PathClassLoader[/data/app/com.mydomain.myapp-2.apk]
10-25 00:29:04.600: E/AndroidRuntime(3299):     at dalvik.system.PathClassLoader.findClass(PathClassLoader.java:240)
10-25 00:29:04.600: E/AndroidRuntime(3299):     at java.lang.ClassLoader.loadClass(ClassLoader.java:551)
10-25 00:29:04.600: E/AndroidRuntime(3299):     at java.lang.ClassLoader.loadClass(ClassLoader.java:511)
10-25 00:29:04.600: E/AndroidRuntime(3299):     at android.app.Instrumentation.newActivity(Instrumentation.java:1021)
10-25 00:29:04.600: E/AndroidRuntime(3299):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1672)
10-25 00:29:04.600: E/AndroidRuntime(3299):     ... 11 more

[UPDATE]
If I add

-keep public class com.mydomain.myapp.LoadingActivity

it starts, but then it doesn't find the next Activity, because it searches in AndroidManfest for the obfuscated Activities?

10-25 13:20:16.159: E/AndroidRuntime(3195): android.content.ActivityNotFoundException: Unable to find explicit activity class {com.mydomain.myapp/com.mydomain.myapp.G}; have you declared this activity in your AndroidManifest.xml?
10-25 13:20:16.159: E/AndroidRuntime(3195):     at com.mydomain.myapp.LoadingActivity.a(Unknown Source)
10-25 13:20:16.159: E/AndroidRuntime(3195):     at com.mydomain.myapp.e.a.a(Unknown Source)
10-25 13:20:16.159: E/AndroidRuntime(3195):     at com.mydomain.myapp.e.a.onPostExecute(Unknown Source)

proguard.config parameter should be

proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt

or for optimization,

proguard.config=${sdk.dir}/tools/proguard/proguard-android-optimize.txt:proguard-project.txt

This way necessary settings are included, such as:

# We want to keep methods in Activity that could be used in the XML attribute onClick
-keepclassmembers class * extends android.app.Activity {
   public void *(android.view.View);
}

At the moment I'm partly confident with the following solution, but I'd prefer a better obfuscation:

-dontoptimize 
-dontshrink
-verbose
-flattenpackagehierarchy

-keepnames class com.mydomain.myapp.** { *; }

#...and some more classes for Google Services API

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM