APK の圧縮

APK サイズを最小限に抑えることは、優れた Android アプリを開発するうえで重要です。これは特に、発展途上市場を対象とする場合や Android Instant App を開発する場合に当てはまります。そのような場合は、APK に含まれる ExoPlayer ライブラリのサイズを最小限に抑えることが望ましい場合があります。このページでは、この目標を達成するために役立つ簡単な手順を説明します。

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

実際に必要なライブラリ モジュールにのみ依存します。たとえば、次のコードは、DASH コンテンツのみを再生するアプリに必要な場合がある、ExoPlayer、DASH、UI ライブラリ モジュールへの依存関係を追加します。

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"

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

アプリのリリースビルドでは、コードとリソースの圧縮を有効にする必要があります。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.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));