即时应用程序如何做到不超过4MB?如何减小APK文件大小?

6
我在尝试将APK文件大小压缩至4MB以下时遇到了困难。 检查生成的即时应用程序APK后,我发现com.google.android.gms.internal占据了将近1.4MB的空间。 我无法找到这个大块的原因。必须是某种依赖关系导致的。

enter image description here

我的基本清单文件如下:

dependencies {

api "com.android.support:design:$rootProject.supportLib"
api "com.android.support:support-fragment:$rootProject.supportLib"

api "com.android.support:appcompat-v7:$rootProject.supportLib"
api "com.android.support:recyclerview-v7:$rootProject.supportLib"
api "com.android.support:cardview-v7:$rootProject.supportLib"

api 'com.android.support.constraint:constraint-layout:1.0.2'
api "com.google.code.gson:gson:$rootProject.gson"
api "com.google.firebase:firebase-core:$rootProject.googleLibs"
api "com.google.firebase:firebase-ads:$rootProject.googleLibs"
api "com.google.firebase:firebase-appindexing:$rootProject.googleLibs"
api "com.google.android.gms:play-services-auth:$rootProject.googleLibs"
api "com.android.support:multidex:$rootProject.multidex"
api "com.github.bumptech.glide:glide:$rootProject.glide"
annotationProcessor "com.github.bumptech.glide:compiler:$rootProject.glide"
api "com.loopj.android:android-async-http:$rootProject.asyncHttp"

api "org.greenrobot:eventbus:$rootProject.greenRobotEventBus"
api "com.vincentbrison.openlibraries.android:dualcache:$rootProject.dualcache"
api('com.crashlytics.sdk.android:crashlytics:2.6.8@aar') {
    transitive = true;
}

有时运行 ./gradlew <your_module>:dependencies 可以很有用,可以查看您的模块中的传递依赖关系。这可以显示您没有意识到的依赖关系,也可以显示版本不匹配的情况。 - John O'Reilly
谢谢。是的,我一直在运行那个命令来查看依赖项的来源。我已经从5MB降到了3.2MB。但我就是找不到与com.google.android.gms.internal相关的任何内容,这一定是某种谷歌库。为什么它这么大呢? - Gillis Haasnoot
你正在使用ProGuard吗?你会发现在保持Instant Apps的大小方面,你实际上需要使用它。正如你可能已经知道的那样,4MB的限制是基础和特征apk的组合限制。 - John O'Reilly
是的,完全正确。是的,Proguard正在使用中。我已经尽可能地进行了优化。资源也是如此。我认为我不能进一步优化它们了。我真的需要摆脱一些库,因此可能还需要删除一些功能。但我真的很想知道为什么那些谷歌的东西这么大。我相当确定我不需要它。 - Gillis Haasnoot
除了查看 https://developer.android.com/topic/performance/reduce-apk-size.html 以了解其他可行的方法外,kabuko 提到的配置分割可能是您下一个最佳选择。 - TWL
你能检查一下这个网址吗:https://medium.com/google-developers/enabling-proguard-in-an-android-instant-app-fbd4fc014518,或许对你有帮助。 - Prags
3个回答

5
我刚刚完成了同样的事情,将即时应用程序的大小从13MB缩小到4MB。
经过长时间的头痛和无数小时的努力,我发现以下包的大小取决于您所包含的依赖项。
  1. com.google.android.gms.internal
  2. android.support.v4.internal
  3. android.support.v7.internal
例如,如果您去除广告依赖项,则内部大小将减少至少500kb。同样,对于Android支持库,如果您不包括CardView,则支持的内部大小将缩小。
我将逐步列出我在执行非常大规模的应用程序模块的多功能即时应用程序时遇到的所有问题: 移动仅用于主应用程序的依赖项 在您的情况下,以下2个项目对即时应用程序完全无用,只能在主应用程序中使用:
api "com.google.firebase:firebase-appindexing:$rootProject.googleLibs"
api "com.android.support:multidex:$rootProject.multidex"

将它们移动到主应用程序,如果代码与视图耦合,移动AppIndexing可能会很困难,但您必须修复它。在我的情况下,我不得不从Base模块的视图中实例化AppIndexing,所以我使用了Otto(EventBus)。在Base模块中创建一个事件,触发并在Main App的AppIndexing助手类中捕获。
明确从所有软件包中排除google支持组。
这看起来可能有些荒谬,但大小说明一切,将所有Google / Android支持依赖关系更改为显式排除。
api("com.android.support:design:$rootProject.supportLib") {
    exclude group: 'com.android.support'
}
api("com.android.support:support-fragment:$rootProject.supportLib") {
    exclude group: 'com.android.support'
}
api("com.android.support:appcompat-v7:$rootProject.supportLib") {
    exclude group: 'com.android.support'
}
api("com.android.support:recyclerview-v7:$rootProject.supportLib") {
    exclude group: 'com.android.support'
}
api("com.android.support:cardview-v7:$rootProject.supportLib") {
    exclude group: 'com.android.support'
}
api('com.android.support.constraint:constraint-layout:1.0.2') {
    exclude group: 'com.android.support'
}
api("com.google.firebase:firebase-core:$rootProject.googleLibs") {
    exclude group: 'com.android.support'
}
api("com.google.firebase:firebase-ads:$rootProject.googleLibs") {
    exclude group: 'com.android.support'
}
api("com.google.firebase:firebase-appindexing:$rootProject.googleLibs") {
    exclude group: 'com.android.support'
}
api("com.google.android.gms:play-services-auth:$rootProject.googleLibs") {
    exclude group: 'com.android.support'
}

为每个模块启用Proguard

正如其他人所提到的,为每个模块启用Proguard。我们原始的13MB大小约减少了25%。

排除在Instant Apps中不需要使用的功能

登录:

对于我们而言,登录功能不需要出现在Instant App中。因此,我将所有与登录/授权相关的内容移动到主应用程序中,并使用Event Bus来触发需要的操作。例如,导航抽屉中的登录/注销操作(在Instant App中隐藏但在主应用程序中可见)存在于Base Module中。因此,我为每个事件触发一个事件,并在Main App Module中捕获它以显示登录屏幕或处理注销。

这使我可以从Base Module中排除com.google.android.gms:play-services-auth依赖项,从而进一步减小gms内部大小。

广告:

出于大小考虑,我们必须将广告从Base Module中移到主应用程序中。我们使用类似的技术(Event Bus)进行调用,以便从Base Module中呈现广告,并通过帮助类在Main App中实际进行呈现。

这使我们可以删除com.google.firebase:firebase-corecom.google.firebase:firebase-ads

附:功能排除完全取决于您的需求/想要/妥协。我们做出了这些决定,因为我们希望所有产生收入的功能都在Instant App中。因此,只要我们能赚钱,我们就不关心广告或登录。

希望这有所帮助。


1

看起来这是 com.google.firebase:firebase-ads 的依赖树:

\--- com.google.firebase:firebase-ads:11.8.0
     +--- com.google.android.gms:play-services-ads:11.8.0
     |    +--- com.google.android.gms:play-services-ads-lite:11.8.0

play-services-ads是一个庞大的库(对“com.google.android.gms.internal”中的大量代码做出了贡献),您可以尝试将其替换为较小的库以获得更好的效果。(当然,我建议提交问题以获取官方支持的“firebase-ads”的“精简”版本。)


0

我相当确定com.google.android.gms.internal包含公共gms包使用的常见代码,在您的情况下是com.google.android.gms:play-services-auth(您可能正在为智能锁使用它),并且无法删除它。如果您已经降到了3.2MB,老实说,我认为很难再缩小了。您似乎同时使用了Play Services和支持库。在这两者之间,要进一步缩小体积就比较困难了。我发现有用的另一件事是使用配置分割,特别是密度分割。


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