APK 缩减
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
最大限度地减小 APK 大小是开发优质 Android 应用的一个重要方面。在面向发展中市场进行开发时,以及在开发 Android 免安装应用时,这一点尤其重要。在这些情况下,最好尽可能减小 APK 中包含的 ExoPlayer 库的大小。本页简要介绍了一些有助于实现此目标的简单步骤。
仅使用必需的依赖项
仅依赖于您实际需要的库模块。例如,以下代码将添加对 ExoPlayer、DASH 和界面库模块的依赖项,这可能是一个仅播放 DASH 内容的应用所需要的:
Kotlin
implementation("androidx.media3:media3-exoplayer:1.8.0")
implementation("androidx.media3:media3-exoplayer-dash:1.8.0")
implementation("androidx.media3:media3-ui:1.8.0")
Groovy
implementation "androidx.media3:media3-exoplayer:1.8.0"
implementation "androidx.media3:media3-exoplayer-dash:1.8.0"
implementation "androidx.media3:media3-ui:1.8.0"
启用代码和资源缩减功能
您应为应用的发布 build 启用代码和资源缩减功能。ExoPlayer 的结构可让代码缩减功能有效地移除未使用的功能。例如,对于播放 DASH 内容的应用,启用代码缩减功能后,ExoPlayer 对 APK 大小的贡献可减少约 40%。
请参阅缩减、混淆处理和优化应用,了解如何启用代码和资源缩减功能。
指定应用所需的渲染器
默认情况下,播放器的渲染器将使用 DefaultRenderersFactory
创建。DefaultRenderersFactory
依赖于 ExoPlayer 库中提供的所有 Renderer
实现,因此代码缩减不会移除任何一个实现。如果您知道自己的应用只需要一部分渲染器,则可以改为指定自己的 RenderersFactory
。例如,仅播放音频的应用在实例化 ExoPlayer
实例时可以定义如下工厂:
Kotlin
val audioOnlyRenderersFactory =
RenderersFactory {
handler: Handler,
videoListener: VideoRendererEventListener,
audioListener: AudioRendererEventListener,
textOutput: TextOutput,
metadataOutput: MetadataOutput,
->
arrayOf<Renderer>(
MediaCodecAudioRenderer(context, MediaCodecSelector.DEFAULT, handler, audioListener)
)
}
val player = ExoPlayer.Builder(context, audioOnlyRenderersFactory).build()
Java
RenderersFactory audioOnlyRenderersFactory =
(handler, videoListener, audioListener, textOutput, metadataOutput) ->
new Renderer[] {
new MediaCodecAudioRenderer(
context, MediaCodecSelector.DEFAULT, handler, audioListener)
};
ExoPlayer player = new ExoPlayer.Builder(context, audioOnlyRenderersFactory).build();
这样,代码缩减便可移除其他 Renderer
实现。在此特定示例视频中,文本和元数据渲染器会被移除(这意味着播放器不会处理或发出任何字幕或插播元数据(例如 ICY))。
默认情况下,播放器会创建 Extractor
实例,以使用 DefaultExtractorsFactory
播放渐进式媒体。DefaultExtractorsFactory
依赖于 ExoPlayer 库中提供的所有 Extractor
实现,因此代码缩减不会移除任何一个实现。如果您知道自己的应用只需要播放少量容器格式,或者根本不播放渐进式媒体,则可以指定自己的 ExtractorsFactory
。例如,只需要播放 mp4 文件的应用可以提供如下工厂:
Kotlin
val mp4ExtractorFactory = ExtractorsFactory {
arrayOf<Extractor>(Mp4Extractor(DefaultSubtitleParserFactory()))
}
val player =
ExoPlayer.Builder(context, DefaultMediaSourceFactory(context, mp4ExtractorFactory)).build()
Java
ExtractorsFactory mp4ExtractorFactory =
() -> new Extractor[] {new Mp4Extractor(new DefaultSubtitleParserFactory())};
ExoPlayer player =
new ExoPlayer.Builder(context, new DefaultMediaSourceFactory(context, mp4ExtractorFactory))
.build();
这样一来,代码缩减功能便可移除其他 Extractor
实现,从而大幅缩减大小。
如果您的应用根本不播放渐进式内容,您应将 ExtractorsFactory.EMPTY
传递给 DefaultMediaSourceFactory
构造函数,然后将该 mediaSourceFactory
传递给 ExoPlayer.Builder
构造函数。
Kotlin
val player =
ExoPlayer.Builder(context, DefaultMediaSourceFactory(context, ExtractorsFactory.EMPTY)).build()
Java
ExoPlayer player =
new ExoPlayer.Builder(
context, new DefaultMediaSourceFactory(context, ExtractorsFactory.EMPTY))
.build();
如果您的应用使用的是自定义 MediaSource.Factory
,并且您希望通过代码剥离移除 DefaultMediaSourceFactory
,则应将 MediaSource.Factory
直接传递给 ExoPlayer.Builder
构造函数。
Kotlin
val player = ExoPlayer.Builder(context, customMediaSourceFactory).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context, mediaSourceFactory).build();
如果您的应用直接使用 MediaSource
而不是 MediaItem
,您应将 MediaSource.Factory.UNSUPPORTED
传递给 ExoPlayer.Builder
构造函数,以确保 DefaultMediaSourceFactory
和 DefaultExtractorsFactory
可以通过代码缩减功能进行剥离。
Kotlin
val player = ExoPlayer.Builder(context, MediaSource.Factory.UNSUPPORTED).build()
val mediaSource =
ProgressiveMediaSource.Factory(dataSourceFactory, customExtractorsFactory)
.createMediaSource(MediaItem.fromUri(uri))
Java
ExoPlayer player = new ExoPlayer.Builder(context, MediaSource.Factory.UNSUPPORTED).build();
ProgressiveMediaSource mediaSource =
new ProgressiveMediaSource.Factory(dataSourceFactory, customExtractorsFactory)
.createMediaSource(MediaItem.fromUri(uri));
本页面上的内容和代码示例受内容许可部分所述许可的限制。Java 和 OpenJDK 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):2025-08-27。
[[["易于理解","easyToUnderstand","thumb-up"],["解决了我的问题","solvedMyProblem","thumb-up"],["其他","otherUp","thumb-up"]],[["没有我需要的信息","missingTheInformationINeed","thumb-down"],["太复杂/步骤太多","tooComplicatedTooManySteps","thumb-down"],["内容需要更新","outOfDate","thumb-down"],["翻译问题","translationIssue","thumb-down"],["示例/代码问题","samplesCodeIssue","thumb-down"],["其他","otherDown","thumb-down"]],["最后更新时间 (UTC):2025-08-27。"],[],[],null,["# APK shrinking\n\nMinimizing APK size is an important aspect of developing a good Android\napp. This is particularly true when targeting developing markets, and\nalso when developing an Android Instant App. For such cases, it may be desirable\nto minimize the size of the ExoPlayer library that's included in the APK. This\npage outlines some simple steps that can help to achieve this.\n\nUse only required dependencies\n------------------------------\n\nDepend only on the library modules that you actually need. For example, the\nfollowing will add dependencies on the ExoPlayer, DASH, and UI library modules,\nas might be required for an app that only plays DASH content: \n\n### Kotlin\n\n```kotlin\nimplementation(\"androidx.media3:media3-exoplayer:1.8.0\")\nimplementation(\"androidx.media3:media3-exoplayer-dash:1.8.0\")\nimplementation(\"androidx.media3:media3-ui:1.8.0\")\n```\n\n### Groovy\n\n```groovy\nimplementation \"androidx.media3:media3-exoplayer:1.8.0\"\nimplementation \"androidx.media3:media3-exoplayer-dash:1.8.0\"\nimplementation \"androidx.media3:media3-ui:1.8.0\"\n```\n\nEnable code and resource shrinking\n----------------------------------\n\nYou should enable code and resource shrinking for your app's release\nbuilds. ExoPlayer is structured in a way that allows code shrinking to\neffectively remove unused functionality. For example, for an app that\nplays DASH content, ExoPlayer's contribution to APK size can be reduced by\napproximately 40% by enabling code shrinking.\n\nRead [Shrink, obfuscate, and optimize your app](/studio/build/shrink-code) to learn how to enable\ncode and resource shrinking.\n\nSpecify which renderers your app needs\n--------------------------------------\n\nBy default, the player's renderers will be created using\n`DefaultRenderersFactory`. `DefaultRenderersFactory` depends on all of the\n`Renderer` implementations provided in the ExoPlayer library, and as a result\nnone of them will be removed by code shrinking. If you know that your app only\nneeds a subset of renderers, you can specify your own `RenderersFactory`\ninstead. For example, an app that only plays audio can define a factory like\nthis when instantiating `ExoPlayer` instances: \n\n### Kotlin\n\n```kotlin\nval audioOnlyRenderersFactory =\n RenderersFactory {\n handler: Handler,\n videoListener: VideoRendererEventListener,\n audioListener: AudioRendererEventListener,\n textOutput: TextOutput,\n metadataOutput: MetadataOutput,\n -\u003e\n arrayOf\u003cRenderer\u003e(\n MediaCodecAudioRenderer(context, MediaCodecSelector.DEFAULT, handler, audioListener)\n )\n}\nval player = ExoPlayer.Builder(context, audioOnlyRenderersFactory).build()\n```\n\n### Java\n\n```java\nRenderersFactory audioOnlyRenderersFactory =\n (handler, videoListener, audioListener, textOutput, metadataOutput) -\u003e\n new Renderer[] {\n new MediaCodecAudioRenderer(\n context, MediaCodecSelector.DEFAULT, handler, audioListener)\n };\nExoPlayer player = new ExoPlayer.Builder(context, audioOnlyRenderersFactory).build();\n```\n\n\u003cbr /\u003e\n\nThis will allow other `Renderer` implementations to be removed by code\nshrinking. In this particular example video, text and metadata renderers are\nremoved (which means any subtitles or in-stream metadata (e.g.\n[ICY](https://cast.readme.io/docs/icy)) won't be processed or emitted by the\nplayer).\n\nSpecify which extractors your app needs\n---------------------------------------\n\nBy default, the player creates `Extractor` instances to play progressive media using\n`DefaultExtractorsFactory`. `DefaultExtractorsFactory` depends on all of the\n`Extractor` implementations provided in the ExoPlayer library, and as a result\nnone of them will be removed by code shrinking. If you know that your app only\nneeds to play a small number of container formats, or doesn't play progressive\nmedia at all, you can specify your own `ExtractorsFactory` instead. For example,\nan app that only needs to play mp4 files can provide a factory like: \n\n### Kotlin\n\n```kotlin\nval mp4ExtractorFactory = ExtractorsFactory {\n arrayOf\u003cExtractor\u003e(Mp4Extractor(DefaultSubtitleParserFactory()))\n}\nval player =\n ExoPlayer.Builder(context, DefaultMediaSourceFactory(context, mp4ExtractorFactory)).build()\n```\n\n### Java\n\n```java\nExtractorsFactory mp4ExtractorFactory =\n () -\u003e new Extractor[] {new Mp4Extractor(new DefaultSubtitleParserFactory())};\nExoPlayer player =\n new ExoPlayer.Builder(context, new DefaultMediaSourceFactory(context, mp4ExtractorFactory))\n .build();\n```\n\n\u003cbr /\u003e\n\nThis will allow other `Extractor` implementations to be removed by code\nshrinking, which can result in a significant reduction in size.\n\nIf your app is not playing progressive content at all, you should pass\n`ExtractorsFactory.EMPTY` to the `DefaultMediaSourceFactory` constructor, then\npass that `mediaSourceFactory` to the `ExoPlayer.Builder` constructor. \n\n### Kotlin\n\n```kotlin\nval player =\n ExoPlayer.Builder(context, DefaultMediaSourceFactory(context, ExtractorsFactory.EMPTY)).build()\n```\n\n### Java\n\n```java\nExoPlayer player =\n new ExoPlayer.Builder(\n context, new DefaultMediaSourceFactory(context, ExtractorsFactory.EMPTY))\n .build();\n```\n\n\u003cbr /\u003e\n\nCustom MediaSource instantiation\n--------------------------------\n\nIf your app is using a custom `MediaSource.Factory` and you want\n`DefaultMediaSourceFactory` to be removed by code stripping, you should pass\nyour `MediaSource.Factory` directly to the `ExoPlayer.Builder` constructor. \n\n### Kotlin\n\n```kotlin\nval player = ExoPlayer.Builder(context, customMediaSourceFactory).build()\n```\n\n### Java\n\n```java\nExoPlayer player = new ExoPlayer.Builder(context, mediaSourceFactory).build();\n```\n\n\u003cbr /\u003e\n\nIf your app is using `MediaSource` directly instead of `MediaItem` you should\npass `MediaSource.Factory.UNSUPPORTED` to the `ExoPlayer.Builder` constructor,\nto ensure `DefaultMediaSourceFactory` and `DefaultExtractorsFactory` can be\nstripped by code shrinking. \n\n### Kotlin\n\n```kotlin\nval player = ExoPlayer.Builder(context, MediaSource.Factory.UNSUPPORTED).build()\nval mediaSource =\n ProgressiveMediaSource.Factory(dataSourceFactory, customExtractorsFactory)\n .createMediaSource(MediaItem.fromUri(uri))\n```\n\n### Java\n\n```java\nExoPlayer player = new ExoPlayer.Builder(context, MediaSource.Factory.UNSUPPORTED).build();\nProgressiveMediaSource mediaSource =\n new ProgressiveMediaSource.Factory(dataSourceFactory, customExtractorsFactory)\n .createMediaSource(MediaItem.fromUri(uri));\n```\n\n\u003cbr /\u003e"]]