APK 縮減

縮減 APK 大小是開發優質 Android 應用程式的重要環節,特別是在開發目標為開發中國家時,以及開發 Android 免安裝應用程式時。在這種情況下,建議您盡可能縮減 APK 中所含 ExoPlayer 程式庫的大小。本頁面將概述一些簡單的步驟,協助您達成這項目標。

僅使用必要的依附元件

只依附於您實際需要的程式庫模組。舉例來說,以下會新增 ExoPlayer、DASH 和 UI 程式庫模組的依附元件,因為僅播放 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"

啟用程式碼和資源縮減功能

您應為應用程式的發布子版本啟用程式碼和資源縮減功能。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 例項化

如果應用程式使用自訂 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 建構函式,確保 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));