כיווץ APK

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

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

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

Kotlin

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

מגניב

implementation "androidx.media3:media3-exoplayer:1.7.1"
implementation "androidx.media3:media3-exoplayer-dash:1.7.1"
implementation "androidx.media3:media3-ui:1.7.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 אל הבונה 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));