Reducción de APK

Minimizar el tamaño del APK es un aspecto importante para desarrollar una buena app para Android. Esto es así especialmente cuando se orienta a mercados en desarrollo y también cuando se desarrolla una app instantánea Android. En estos casos, puede ser conveniente minimizar el tamaño de la biblioteca de ExoPlayer que se incluye en el APK. En esta página, se describen algunos pasos simples que pueden ayudarte a lograrlo.

Usa solo las dependencias necesarias

Depende solo de los módulos de biblioteca que realmente necesites. Por ejemplo, lo siguiente agregará dependencias en los módulos de biblioteca de ExoPlayer, DASH y de IU, como podría ser necesario para una app que solo reproduce contenido DASH:

Kotlin

implementation("androidx.media3:media3-exoplayer:1.3.1")
implementation("androidx.media3:media3-exoplayer-dash:1.3.1")
implementation("androidx.media3:media3-ui:1.3.1")

Groovy

implementation "androidx.media3:media3-exoplayer:1.3.1"
implementation "androidx.media3:media3-exoplayer-dash:1.3.1"
implementation "androidx.media3:media3-ui:1.3.1"

Habilitar la reducción de código y recursos

Debes habilitar la reducción de código y recursos para las compilaciones de lanzamiento de tu app. ExoPlayer está estructurado de una manera que permite la reducción de código para quitar de manera eficaz la funcionalidad que no se usa. Por ejemplo, en el caso de una app que reproduce contenido DASH, la contribución de ExoPlayer al tamaño del APK se puede reducir aproximadamente un 40% si se habilita la reducción de código.

Consulta el artículo Cómo reducir, ofuscar y optimizar tu app para obtener información sobre cómo habilitar la reducción de código y recursos.

Cómo especificar los procesadores que necesita tu app

De forma predeterminada, los procesadores del reproductor se crearán con DefaultRenderersFactory. DefaultRenderersFactory depende de todas las implementaciones de Renderer proporcionadas en la biblioteca de ExoPlayer y, como resultado, no se quitará ninguna de ellas mediante la reducción de código. Si sabes que tu app solo necesita un subconjunto de procesadores, puedes especificar tu propio RenderersFactory en su lugar. Por ejemplo, una app que solo reproduce audio puede definir una fábrica como esta cuando se crean instancias de 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();

Esto permitirá que se quiten otras implementaciones de Renderer mediante la reducción de código. En este ejemplo específico de video, se quitan los procesadores de texto y metadatos (lo que significa que el reproductor no procesará ni emitirá los subtítulos ni los metadatos in-stream, como ICY).

Especifica qué extractores necesita tu app

De forma predeterminada, el reproductor crea instancias de Extractor para reproducir contenido multimedia progresivo con DefaultExtractorsFactory. DefaultExtractorsFactory depende de todas las implementaciones de Extractor proporcionadas en la biblioteca de ExoPlayer y, como resultado, no se quitará ninguna de ellas mediante la reducción de código. Si sabes que tu app solo necesita reproducir una pequeña cantidad de formatos de contenedor o no reproduce contenido multimedia progresivo, puedes especificar tu propio ExtractorsFactory. Por ejemplo, una app que solo necesita reproducir archivos mp4 puede proporcionar una configuración de fábrica como la siguiente:

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();

Esto permitirá que se quiten otras implementaciones de Extractor mediante la reducción de código, lo que puede reducir significativamente el tamaño.

Si tu app no reproduce contenido progresivo en absoluto, debes pasar ExtractorsFactory.EMPTY al constructor DefaultMediaSourceFactory y, luego, ese mediaSourceFactory al constructor 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();

Creación de instancias de MediaSource personalizada

Si tu app usa un MediaSource.Factory personalizado y quieres que se quite DefaultMediaSourceFactory mediante la eliminación de código, debes pasar el MediaSource.Factory directamente al constructor ExoPlayer.Builder.

Kotlin

val player = ExoPlayer.Builder(context, customMediaSourceFactory).build()

Java

ExoPlayer player = new ExoPlayer.Builder(context, mediaSourceFactory).build();

Si tu app usa MediaSource directamente en lugar de MediaItem, debes pasar MediaSource.Factory.UNSUPPORTED al constructor ExoPlayer.Builder para asegurarte de que se puedan quitar DefaultMediaSourceFactory y DefaultExtractorsFactory mediante la reducción de código.

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