כיווץ APK

צמצום גודל קובץ ה-APK הוא היבט חשוב בפיתוח אפליקציה טובה ל-Android. זה נכון במיוחד כשמטרגטים שווקים מתפתחים, וגם כשמפתחים אפליקציה ללא התקנה ל-Android. במקרים כאלה, כדאי לצמצם את הגודל של ספריית ExoPlayer שכלולה בקובץ ה-APK. בדף הזה מפורטים כמה שלבים פשוטים שיעזרו לכם להשיג את המטרה הזו.

שימוש רק ביחסי תלות נדרשים

להסתמך רק על המודולים של הספרייה שבאמת נחוצים לכם. לדוגמה, הקוד הבא יוסיף יחסי תלות במודולים של 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"

הפעלה של כיווץ קוד ומשאבים

מומלץ להפעיל כיווץ קוד ומשאבים ב-builds של הגרסה של האפליקציה. ExoPlayer מובנה כך שאפשר לבצע בו כיווץ קוד כדי להסיר ביעילות פונקציונליות שלא בשימוש. לדוגמה, באפליקציה שמפעילה תוכן DASH, אפשר להקטין את התרומה של ExoPlayer לגודל ה-APK בכ-40% על ידי הפעלת צמצום הקוד.

במאמר כיווץ, ערפול ואופטימיזציה של האפליקציה מוסבר איך מפעילים כיווץ של קוד ומשאבים.

ציון הרסטוררים הנדרשים לאפליקציה

כברירת מחדל, מעבדי הווידאו של הנגן ייוצרו באמצעות DefaultRenderersFactory. DefaultRenderersFactory תלויה בכל ההטמעות של Renderer שסופקו בספריית ExoPlayer, ולכן אף אחת מהן לא תוסר על ידי צמצום הקוד. אם אתם יודעים שהאפליקציה שלכם זקוקה רק לקבוצת משנה של מנועי עיבוד, תוכלו לציין 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)).

ציון הגורמים לחילוץ (extractors) הנדרשים לאפליקציה

כברירת מחדל, הנגן יוצר מכונות Extractor כדי להפעיל מדיה פרוגרסיבית באמצעות DefaultExtractorsFactory. DefaultExtractorsFactory תלויה בכל ההטמעות של Extractor שסופקו בספריית ExoPlayer, ולכן אף אחת מהן לא תוסר על ידי צמצום הקוד. אם אתם יודעים שהאפליקציה שלכם צריכה להפעיל רק מספר קטן של פורמטים של קונטיינרים, או שהיא לא מפעילה מדיה פרוגרסיבית בכלל, תוכלו לציין 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 כדי לוודא שאפשר יהיה להסיר את DefaultMediaSourceFactory ואת DefaultExtractorsFactory באמצעות צמצום קוד.

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