כיווץ APK

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

שימוש רק בתלות הנדרשת

להסתמך רק על מודולי הספרייה שבאמת נחוצים. לדוגמה, הקוד הבא יוסיף יחסי תלות במודולים של ספריות ExoPlayer,‏ DASH ו-UI, כפי שנדרש באפליקציה שמפעילה רק תוכן DASH:

Kotlin

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

מגניב

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

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

מומלץ להפעיל כיווץ של קוד ומשאבים בגרסאות ה-build של האפליקציה שמוכנות להפצה. המבנה של 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)).

מציינים אילו מחלצי נתונים נדרשים לאפליקציה

כברירת מחדל, הנגן יוצר מופעים של 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 ישירות אל ה-constructor של ExoPlayer.Builder.

Kotlin

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

Java

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

אם האפליקציה שלכם משתמשת ישירות ב-MediaSource במקום ב-MediaItem, אתם צריכים להעביר את MediaSource.Factory.UNSUPPORTED אל ה-constructor של 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));