Java ProGuard удалить (уменьшить) неиспользуемые классы - PullRequest
3 голосов
/ 15 августа 2011

Допустим, у меня есть это приложение Java:

package com.site;

public class MyAppBase {}

package com.site.free;

import com.site.MyAppBase;

public class MyApp extends MyAppBase {}

package com.site.pro;

import com.site.MyAppBase;

public class MyApp extends MyAppBase {}

package com.site;

public class Edition
{

    public static final int     FREE    = 1;
    public static final int     PRO     = 2;

    private static final int    EDITION = PRO;

    public static boolean is(final int edition)
    {
        return (EDITION == edition);
    }
}

package com.site;

public class EditionFactory
{

    public static MyAppBase get_app()
    {
        MyAppBase ret = null;

        if (Edition.is(Edition.FREE))
            ret = new com.site.free.MyApp();
        else if (Edition.is(Edition.PRO))
            ret = new com.site.pro.MyApp();

        return ret;
    }
}

Теперь любая комбинация конфигурации ProGuard, которую я пытаюсь избавить от невыбранной версии (в данном случае БЕСПЛАТНО), не работает.

Под «избавлением» я подразумеваю, чтобы фактический класс исчез (также из вызывающего кода).

Другими словами, такой звонок:

final MyAppBase app = EditionFactory.get_app();

.. в настоящее время переводится, после ProGuarding, это:

if (a.a(1))
    localObject5 = new c(); // <<< FREE
else if (a.a(2))
    localObject5 = new d(); // <<< PRO

.. хотя я бы хотел, чтобы это было переведено на это:

localObject5 = new d(); // <<< PRO only in the code (as set at Edition.EDITION)

Итог ( кроме того факта, что ProGuard БОЛЬШОЙ !! ), я не могу заставить его "видеть сквозь" и понимать что Edition.is () является логической функцией, возвращающей константу, которая позволяет удалять некоторые классы.

Я пробовал конфигурации, такие как:

-keep,allowshrinking,allowoptimization public class * extends com.site.MyAppBase
-optimizationpasses 10

.. ничего не работает.

С другой стороны, , если я обращаюсь к Edition.EDITION и сравниваю его встроенным (т.е. без каких-либо «прокси-функций»), компилятор Java (v1.6) обнаруживает его и удаляет всю ссылку в невыбранное издание / класс.
Это приводит к тому, что ProGuard удаляет / сокращает неиспользуемый класс, и это здорово.

Единственная проблема здесь связана с поддержкой - я был бы рад возможности использовать стиль EditionFactory.

Ответы [ 2 ]

7 голосов
/ 16 августа 2011

Оптимизация не выполняется, поскольку ProGuard решает не включать метод Edition#is, поэтому не может упростить полученную последовательность инструкций. Метод не встроенный, потому что он не очень короткий и также вызывается более одного раза. Вы можете обойти первый критерий с помощью этой недокументированной опции JVM для ProGuard:

-Dmaximum.inlined.code.length=16

Кроме того, вы можете обойти второй критерий, убедившись, что метод вызывается только один раз:

return Edition.is(Edition.FREE) ?
    new com.site.free.MyApp() :
    new com.site.pro.MyApp();

В качестве альтернативы, вы можете создать короткие функции isFree () и isPro (), потому что они будут возвращать константы, которые будут встроены.

Рекомендуется проверять обработанный код, если вы ожидаете каких-то особых оптимизаций, потому что они часто подвергаются сложным ограничениям.

Приятно слышать, что вам нравится ProGuard.

1 голос
/ 15 августа 2011

Это потому, что ваш метод is(...) может принимать больше значений, чем только 1 и 2. Это может быть вызвано в другом месте из кода с 3, 4, 6 ... Proguard не может исключить этот случай.

Решение вашей проблемы - сделать Edition enum. Вам больше не понадобится метод is(...), и вы можете положиться на equals(...).

...