ProGuard混淆会导致ClassNotFoundException

时间:2014-10-24 22:13:43

标签: java android proguard obfuscation

我尝试通过ProGuard对我的代码进行模糊处理,但是当我这样做时,它甚至都找不到AndroidManifest中定义的初始Activity(ClassNotFoundException)。

这是活动的外观:

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();
    }
}

我的proguard.cfg看起来像这样:

-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;
}

为了测试,我添加了

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

然后,该应用程序工作,但它没有混淆(很明显)。任何想法如何正确混淆?实际上这是ProGuard必须关心的事情,对吧?

这是启动应用时的错误消息:

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]
如果我添加

-keep public class com.mydomain.myapp.LoadingActivity

它开始了,但它没有找到下一个Activity,因为它在AndroidManfest中搜索模糊的Activity?

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)

2 个答案:

答案 0 :(得分:3)

proguard.config参数应为

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

或用于优化,

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

这种方式包括必要的设置,例如:

# 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);
}

答案 1 :(得分:0)

目前,我对以下解决方案充满信心,但我更喜欢更好的混淆:

-dontoptimize 
-dontshrink
-verbose
-flattenpackagehierarchy

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

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