Google Play服务使得apk文件太大。

17

我已经安装了Google Play服务,并创建了一个Hello World应用程序来测试一切是否正常工作,但我认为这个应用程序的大小太大:4.98 MB。我正在使用Android Studio,并且遵循了Android开发者网站上详细的说明。

这是我的gradle文件:

apply plugin: 'android'

android {
    compileSdkVersion 19
    buildToolsVersion "19.0.1"

    defaultConfig {
        minSdkVersion 15
        targetSdkVersion 19
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            runProguard false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.google.android.gms:play-services:4.3.23'
}

编辑

这是我的ProGuard文件:

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

**编辑2**

我使用Intellij Idea的最新版本安装了Google Play服务,现在apk大小为3.52 MB。我不知道这是否是可接受的大小。

这正常吗?


如果将runProguard设置为true会发生什么? - Daenyth
我已经尝试过了。同样的apk大小为4.98MB。 - Marcos
所以你配置得不对。Proguard 可以将 APK 大小减少约一半。 - Gaskoin
我已经包含了我的Proguard文件。 - Marcos
2个回答

15
不,这并不正常-早期版本的GPSTest app包含Google Play Services地图后使用Proguard混淆后仅为808KB-当前版本(添加另一个库后)混淆后约为1,497KB。我建议按照以下步骤通过命令行导出APK以避免在Android Studio中出现潜在问题:
  1. 进入命令行中的项目根目录
  2. 运行gradlew assembleRelease
  3. /app/build/apk文件夹中找到签名和混淆的APK
如果您通过Android Studio导出APK,请注意存在已知问题,即Android Studio默认使用assembleDebug任务而不是assembleRelease任务进行导出。因此,特定于发布buildType的build.gradle文件中的任何Proguard运行配置都将不会执行。
作为通过Android Studio导出的解决方法,您可以通过以下步骤更改默认的Build Variant:
1. 在Android Studio中,打开“View->Tool Windows->Build Variants” 2. 在打开的窗口中,将“Build Variant”从“debug”更改为“release”。
现在,当您执行“Build->Generate Signed APK…”时,Android Studio应该运行发布Build Variant,如果您在build.gradle中正确配置了Proguard,则应该运行Proguard。您可以在正常情况下调试应用程序时切换回“debug”变量。
如果您想复制GPSTest中的设置,这是proguard.cfg:
-optimizationpasses 5
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*

-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.preference.Preference

-keepclasseswithmembers class * {
    native <methods>;
}

-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet);
}

-keepclasseswithmembers class * {
    public <init>(android.content.Context, android.util.AttributeSet, int);
}

-keepclassmembers enum * {
    public static **[] values();
    public static ** valueOf(java.lang.String);
}

-keep class * implements android.os.Parcelable {
  public static final android.os.Parcelable$Creator *;
}

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

-dontwarn **CompatHoneycomb
-dontwarn **CompatCreatorHoneycombMR2
-dontwarn **AccessibilityServiceInfoCompatJellyBeanMr2
-dontwarn android.support.v4.view.**
-dontwarn android.support.v4.media.**
-dontwarn com.actionbarsherlock.internal.**
-keep class android.support.v4.** { *; }
-keepattributes *Annotation*
-keep public class * extends android.view.View
-keep public class * extends android.view.ViewGroup
-keep public class * extends android.support.v4.app.Fragment

-keepclassmembers class * extends com.actionbarsherlock.ActionBarSherlock {
    <init>(android.app.Activity, int);
}

...和build.gradle

apply plugin: 'android'

android {
    compileSdkVersion 19
    buildToolsVersion "19.0.0"

    defaultConfig {
        minSdkVersion 8
        targetSdkVersion 19
    }

    if (project.hasProperty("secure.properties")
            && new File(project.property("secure.properties")).exists()) {

        Properties props = new Properties()
        props.load(new FileInputStream(file(project.property("secure.properties"))))

        signingConfigs {
            debug {
                storeFile file("gpstest.debug.keystore")
            }

            release {
                storeFile file(props['key.store'])
                keyAlias props['key.alias']
                storePassword "askmelater"
                keyPassword "askmelater"
            }
        }
    } else {
        signingConfigs {
            debug {
                storeFile file("gpstest.debug.keystore")
            }

            release {
                // Nothing here
            }
        }
    }

    buildTypes {
        release {
            runProguard true
            proguardFile 'proguard.cfg'
            signingConfig signingConfigs.release
        }
    }
}

task askForPasswords << {
    // Must create String because System.readPassword() returns char[]
    // (and assigning that below fails silently)
    def storePw = new String(System.console().readPassword("\nKeystore password: "))
    def keyPw = new String(System.console().readPassword("Key password: "))

    android.signingConfigs.release.storePassword = storePw
    android.signingConfigs.release.keyPassword = keyPw
}

tasks.whenTaskAdded { theTask ->
    if (theTask.name.equals("packageRelease")) {
        theTask.dependsOn "askForPasswords"
    }
}

dependencies {
    compile project(':ShowcaseViewLibrary')
    compile 'com.google.android.gms:play-services:3.2.65'
    compile 'com.actionbarsherlock:actionbarsherlock:4.4.0@aar'
    compile 'org.jraf:android-switch-backport:1.2'
    compile 'com.google.maps.android:android-maps-utils:0.2.1'
}

如果您想将GPSTest源代码用作示例,可以在Github上获取整个源代码。

编辑

当您使用Google Play服务v6.5或更高版本的功能时,帮助缩小APK的另一种方法是仅包含您实际使用的Google Play服务中的库。

例如,如果您只使用Maps API v2,则可以在build.gradle中仅包含Maps API v2的库,而不是整个Google Play服务库:

compile 'com.google.android.gms:play-services:7.8.0'

...你只需要包含Maps API v2部分:

compile 'com.google.android.gms:play-services-maps:7.8.0'

请参阅Google Play服务 - "选择性地将API编译到可执行文件中"部分,了解可以拆分的API的详细信息。以下是截至2015年9月的列表:
Google+ com.google.android.gms:play-services-plus:7.8.0 Google Account Login com.google.android.gms:play-services-identity:7.8.0 Google Actions, Base Client Library com.google.android.gms:play-services-base:7.8.0 Google App Indexing com.google.android.gms:play-services-appindexing:7.8.0 Google App Invites com.google.android.gms:play-services-appinvite:7.8.0 Google Analytics com.google.android.gms:play-services-analytics:7.8.0 Google Cast com.google.android.gms:play-services-cast:7.8.0 Google Cloud Messaging com.google.android.gms:play-services-gcm:7.8.0 Google Drive com.google.android.gms:play-services-drive:7.8.0 Google Fit com.google.android.gms:play-services-fitness:7.8.0 Google Location, Activity Recognition, and Places com.google.android.gms:playservices-location:7.8.0 Google Maps com.google.android.gms:play-services-maps:7.8.0 Google Mobile Ads com.google.android.gms:play-services-ads:7.8.0 Mobile Vision com.google.android.gms:play-services-vision:7.8.0 Google Nearby com.google.android.gms:play-services-nearby:7.8.0 Google Panorama Viewer com.google.android.gms:play-services-panorama:7.8.0 Google Play Game services com.google.android.gms:play-services-games:7.8.0 SafetyNet com.google.android.gms:play-services-safetynet:7.8.0 Google Wallet com.google.android.gms:play-services-wallet:7.8.0 Android Wear com.google.android.gms:play-services-wearable:7.8.0

谢谢。我看到你的是 proguard.cfg 文件,而我的是 proguard-rules.txt。也许它们是不同的文件?我没有其他的 proguard 文件。 - Marcos
1
好的,我已经完成了,我的apk(在app/build/apk中)大小为725KB(是release-unaligned)。如果我从Android Studio安装debug-unaligned,则大约为1.3MB。 - Marcos
好的,很好。所以你的项目文件没问题,只是当你从UI导出时,Studio没有运行Proguard。我现在不在电脑前,但明天我会看一下(我从命令行导出)。 - Sean Barbeau
@enrmarc:在使用Android Studio导出签名APK时存在一个已知问题(https://code.google.com/p/android/issues/detail?id=56532),即默认情况下不会选择发布版本buildType,因此Proguard不会被执行。我更新了我的答案,提供了使用命令行导出(推荐方法)的说明,同时也包括了通过Android Studio导出的解决方法。请尝试这个方法并告诉我是否有效。 - Sean Barbeau
1
谢谢@Sean。现在我已经修复了!但是做了另一件事情(你的回答非常启发我,我已经发布了答案)。 - Marcos
显示剩余4条评论

2

好了,最终我遇到了问题(感谢@Sean Barbeau)。这是我模块的build.gradle文件。在BuildTypes部分,我使用了release而不是debug,因此我正在部署调试版本... 我已经更改了它,现在我的应用程序只有1.17兆字节!

buildTypes {
    debug {
        runProguard true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
    }
}

编辑

正如@SeanBarbeau所指出的那样,在调试模式下,runProguard被设置为true。如果我将其设置为false,那么我的应用程序将再次变得很大(大小为5 MB)。


1
你可以这样做,但每次启动应用程序(即在每次代码更改后)都需要运行Proguard,因为你已经指定在assembleDebug Build Type中使用Proguard。我真的不认为你想这样做(这也是为什么Gradle支持单独的debug和release Build Types的原因)。 - Sean Barbeau
1
哦,你说得对。现在我已经将runProguard false,应用程序大小为5 MB。该死。 - Marcos
是的 :) (我会说一点西班牙语)。我认为我的答案中的解决方法是处理这个问题的“正确”方式,直到他们在Studio中导出APK时默认使用发布版本类型。您可以使用此解决方案将“runProguard”从true切换为false进行调试,然后在导出时切换为true,但这很混乱,并会干扰版本控制。我认为最好在Studio中更改设置。 - Sean Barbeau
是的,非常感谢@SeanBarbeau。我想在开始我的小项目之前,我需要阅读一些Gradle教程 :) - Marcos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接