Android Build Tools使ProGuard不会删除未使用的appcompat库类

时间:2015-02-26 07:17:19

标签: android gradle proguard

以下是我build.gradle的一部分:

android {
    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:21.0.3'
}

proguard-rules.pro中没有任何内容,但我注意到生成了一个名为aapt_rules.txt的文件,其中包含以下内容:

# view res/layout/abc_action_menu_item_layout.xml #generated:17
-keep class android.support.v7.internal.view.menu.ActionMenuItemView { <init>(...); }

# view res/layout/abc_expanded_menu_layout.xml #generated:17
-keep class android.support.v7.internal.view.menu.ExpandedMenuView { <init>(...); }

# view res/layout/abc_list_menu_item_layout.xml #generated:17
# view res/layout/abc_popup_menu_item_layout.xml #generated:17
-keep class android.support.v7.internal.view.menu.ListMenuItemView { <init>(...); }

# view res/layout/abc_screen_toolbar.xml #generated:27
-keep class android.support.v7.internal.widget.ActionBarContainer { <init>(...); }

# view res/layout/abc_action_mode_bar.xml #generated:19
# view res/layout/abc_screen_toolbar.xml #generated:43
-keep class android.support.v7.internal.widget.ActionBarContextView { <init>(...); }

# view res/layout/abc_screen_toolbar.xml #generated:17
-keep class android.support.v7.internal.widget.ActionBarOverlayLayout { <init>(...); }

# view res/layout/abc_screen_content_include.xml #generated:19
-keep class android.support.v7.internal.widget.ContentFrameLayout { <init>(...); }

# view res/layout/abc_screen_simple_overlay_action_mode.xml #generated:23
-keep class android.support.v7.internal.widget.FitWindowsFrameLayout { <init>(...); }

# view res/layout/abc_screen_simple.xml #generated:17
-keep class android.support.v7.internal.widget.FitWindowsLinearLayout { <init>(...); }

# view v11/res/layout-v11/abc_screen_content_include.xml #generated:19
-keep class android.support.v7.internal.widget.NativeActionModeAwareLayout { <init>(...); }

# view res/layout/abc_action_mode_close_item_material.xml #generated:17
# view res/layout/abc_search_dropdown_item_icons_2line.xml #generated:27
# view res/layout/abc_search_dropdown_item_icons_2line.xml #generated:37
# view res/layout/abc_search_dropdown_item_icons_2line.xml #generated:48
# view res/layout/abc_search_view.xml #generated:116
# view res/layout/abc_search_view.xml #generated:128
# view res/layout/abc_search_view.xml #generated:38
# view res/layout/abc_search_view.xml #generated:60
# view res/layout/abc_search_view.xml #generated:97
-keep class android.support.v7.internal.widget.TintImageView { <init>(...); }

# view res/layout/abc_screen_simple.xml #generated:25
# view res/layout/abc_screen_simple_overlay_action_mode.xml #generated:32
-keep class android.support.v7.internal.widget.ViewStubCompat { <init>(...); }

# view res/layout/abc_action_menu_layout.xml #generated:17
-keep class android.support.v7.widget.ActionMenuView { <init>(...); }

# view res/layout/abc_activity_chooser_view.xml #generated:19
-keep class android.support.v7.widget.LinearLayoutCompat { <init>(...); }

# view res/layout/abc_search_view.xml #generated:78
-keep class android.support.v7.widget.SearchView$SearchAutoComplete { <init>(...); }

# view res/layout/abc_screen_toolbar.xml #generated:36
-keep class android.support.v7.widget.Toolbar { <init>(...); }

这显然保留了XML在支持库中使用的所有内容,即使根本不使用这些XML。并且再次保存的代码会使用shrinkResources true来跳过所有资源。并且即使在支持库中没有使用任何内容,apk大小也会增加很多。其他图书馆也是如此。

那么有没有办法自定义aapt_rules.txt或做类似的事情来删除那些未使用的代码和资源? (或者我需要在某个地方为此打开一个问题吗?)

3 个答案:

答案 0 :(得分:1)

你可以看到aapt_rules.txt中有评论。除了每个保留的类之外,还有引用此类的相应布局文件。像那样:

# view res/layout/abc_list_menu_item_layout.xml #generated:17
# view res/layout/abc_popup_menu_item_layout.xml #generated:17
-keep class android.support.v7.internal.view.menu.ListMenuItemView { <init>(...); }

如果从构建过程中删除布局文件,则此行将消失,并且不会保留类。如果它没有在某个地方实际使用过,那么该课将会缩小。

那么我们如何从appcompat库中删除布局文件呢?我可以看到很少的选择,没有一个是完美的,但它们有效。

  1. 您只需从sdk \ extras \ android \ m2repository \ com \ android \ support \ appcompat-v7 \ version \ appcompat-v7-version.aar中删除文件即可。足够用于测试,对生产不利,因为在一些其他项目中可能使用相同的文件。我试过了它的确有效。

  2. 将具有相同名称的假文件放入项目中。名称冲突将发生。构建过程更喜欢您的假文件,因为项目文件具有更高的优先级。这样来自appcompat的文件将被忽略。我试过了它的确有效。

  3. 您可以制作一些花哨的gradle脚本,在构建过程中删除不需要的文件。我还没试过。

  4. (shrinkResources选项没有帮助,因为在实际涉及shrinkResources之前会生成aapt_rules.txt。)

    我希望有人会建议更好的方法来做到这一点

    这样做之后,所有不需要的线都从aapt_rules.txt消失了。但它从最终的apk大小中节省了大约100 KB。对我来说没什么大不了的。但在你的情况下,结果可能会有所不同。

答案 1 :(得分:0)

如果您使用sbt-android进行构建,则可以手动覆盖proguardConfig,如下所示:

proguardConfig in Android := List("-dontobfuscate",
  "-dontoptimize",
  "-renamesourcefileattribute SourceFile",
  "-keepattributes SourceFile,LineNumberTable",
  "-verbose",
  "-flattenpackagehierarchy",
  "-dontusemixedcaseclassnames",
  "-dontpreverify",
  "-optimizations !code/simplification/arithmetic,!code/simplification/cast,!field/*,!class/merging/*,!code/allocation/variable",
  "-keepattributes *Annotation*",
  "-dontnote android.annotation.**",
  "-dontwarn android.support.**",
  "-dontnote android.support.**",
  "-dontnote scala.ScalaObject",
  "-dontnote org.xml.sax.EntityResolver",
  "-dontnote scala.concurrent.forkjoin.**",
  "-dontwarn scala.beans.ScalaBeanInfo",
  "-dontwarn scala.concurrent.**",
  "-dontnote scala.reflect.**",
  "-dontwarn scala.reflect.**",
  "-dontwarn scala.sys.process.package$",
  "-dontwarn **$$anonfun$*",
  "-dontwarn scala.collection.immutable.RedBlack$Empty",
  "-dontwarn scala.tools.**,plugintemplate.**",

  "-keep class scala.collection.SeqLike { public java.lang.String toString(); }",

  "-keep class android.support.v7.view.menu.ListMenuItemView { <init>(...); }",
  ...
)

答案 2 :(得分:-1)

以下定义是在getDefaultProguardFile('proguard-android.txt')中编写的,这是{android-sdks} / tools / proguard

目录中的默认proguard设置之一
@RunWith(Arquillian.class)
public class BugTest {

private static final String CLEANUP_SCRIPT = "DROP SCHEMA IF EXISTS scheme1 CASCADE; "
        + "DROP SCHEMA IF EXISTS public CASCADE; " 
        + "CREATE SCHEMA public AUTHORIZATION testdba;";
private static final String CREATE_SCRIPT = "CREATE SCHEMA scheme1; "
        + "CREATE TABLE scheme1.dbconfig ( propkey character varying NOT NULL, propvalue character varying NOT NULL, CONSTRAINT dbconfig_pkey PRIMARY KEY (propkey) ); "
        + "INSERT INTO scheme1.dbconfig VALUES ('initialized', true), ('version', 2);";

@Deployment
public static Archive<?> createDeployment() {
    return ShrinkWrap.create(JavaArchive.class).addAsManifestResource("META-INF/beans.xml", "beans.xml")
            .addAsManifestResource("META-INF/persistence.xml", "persistence.xml");
}

@PersistenceContext
private EntityManager em;
@Inject
private UserTransaction transaction;

@Before
public void setUp() throws Exception {
    this.transaction.begin();
    this.em.createNativeQuery(CLEANUP_SCRIPT).executeUpdate();
    this.em.createNativeQuery(CREATE_SCRIPT).executeUpdate();
    this.transaction.commit();
}

// since an exception gets thrown in the setUp() method, these are not called
// they are only needed because the exception gets thrown for more than
// four tests methods
@Test public void test1() { }
@Test public void test2() { }
@Test public void test3() { }
@Test public void test4() { }
@Test public void test5() { }
@Test public void test6() { }
@Test public void test7() { }
@Test public void test8() { }
}

所以,它保留了一切。

无用的代码可以通过另一个proguard文件{android-sdks} /tools/proguard/proguard-android-optimize.txt传递,它使用默认值5 转而优化代码( -optimizationpasses 5 )。