APK の圧縮

APK サイズを最小限に抑えることは、優れた Android アプリを開発するうえで重要なポイントです。特に発展途上市場をターゲットにする場合や、Android Instant App を開発する場合にも当てはまります。そのような場合は、APK に含まれる ExoPlayer ライブラリのサイズを最小限に抑えることをおすすめします。このページでは、これを行うのに役立つ簡単な手順の概要を説明します。

必要な依存関係のみを使用する

実際に必要なライブラリ モジュールにのみ依存します。たとえば、次のように ExoPlayer、DASH、UI ライブラリ モジュールへの依存関係が追加されます。これは、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"

コードとリソースの圧縮を有効にする

アプリのリリースビルドでコードとリソースの圧縮を有効にする必要があります。ExoPlayer は、コード圧縮で未使用の機能を効果的に削除できるように構成されています。たとえば、DASH コンテンツを再生するアプリでは、コードの圧縮を有効にすることで、APK サイズに対する ExoPlayer の貢献度を約 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 など)はプレーヤーによって処理または出力されません)。

アプリに必要なエクストラクタを指定する

デフォルトでは、プレーヤーは DefaultExtractorsFactory を使用してプログレッシブ メディアを再生する Extractor インスタンスを作成します。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.EMPTYDefaultMediaSourceFactory コンストラクタに渡し、その mediaSourceFactoryExoPlayer.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 インスタンス化

アプリでカスタム MediaSource.Factory を使用していて、コード削除によって DefaultMediaSourceFactory を削除する場合は、MediaSource.FactoryExoPlayer.Builder コンストラクタに直接渡す必要があります。

Kotlin

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

Java

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

アプリで MediaItem ではなく MediaSource を直接使用している場合は、MediaSource.Factory.UNSUPPORTEDExoPlayer.Builder コンストラクタに渡して、コード圧縮によって DefaultMediaSourceFactoryDefaultExtractorsFactory を削除できるようにする必要があります。

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