Reducción de APK

Minimizar el tamaño del APK es un aspecto importante para desarrollar una buena app para Android. Esto es particularmente cierto cuando se segmenta para mercados en desarrollo y también cuando se desarrolla una app instantánea para Android. En esos 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 requeridas

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

Kotlin

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

Groovy

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

Habilita 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 que la reducción de código quite 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 en aproximadamente un 40% si se habilita la reducción de código.

Lee Cómo reducir, ofuscar y optimizar tu app para obtener información sobre cómo habilitar la reducción de código y recursos.

Especifica qué renderizadores necesita tu app

De forma predeterminada, los renderizadores del reproductor se crearán con DefaultRenderersFactory. DefaultRenderersFactory depende de todas las implementaciones de Renderer proporcionadas en la biblioteca de ExoPlayer y, como resultado, ninguna de ellas se quitará con la reducción de código. Si sabes que tu app solo necesita un subconjunto de renderizadores, puedes especificar tu propio RenderersFactory. Por ejemplo, una app que solo reproduce audio puede definir una fábrica como esta cuando crea 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 video de ejemplo en particular, se quitan los renderizadores de texto y metadatos (lo que significa que el reproductor no procesará ni emitirá subtítulos ni metadatos in-stream (p.ej., 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, ninguna de ellas se quitará con 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 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 generar una reducción significativa de tamaño.

Si tu app no reproduce contenido progresivo, debes pasar ExtractorsFactory.EMPTY al constructor DefaultMediaSourceFactory y, luego, pasar 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 personalizadas

Si tu app usa un MediaSource.Factory personalizado y deseas que DefaultMediaSourceFactory se quite mediante la eliminación de código, debes pasar tu 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 DefaultMediaSourceFactory y DefaultExtractorsFactory se puedan quitar con 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));