تقليص حزمة APK

يُعد تصغير حجم حزمة APK أحد الجوانب المهمة لتطوير تطبيق Android جيد، ويُعد ذلك صحيحًا بشكل خاص عند استهداف الأسواق النامية، وكذلك عند تطوير تطبيق Android فوري. وفي هذه الحالات، قد يكون من المستحسن تصغير حجم مكتبة ExoPlayer المضمّنة في حزمة APK. توضِّح هذه الصفحة بعض الخطوات البسيطة التي يمكن أن تساعد في تحقيق ذلك.

استخدام العناصر التابعة المطلوبة فقط

لا تعتمد إلا على وحدات المكتبة التي تحتاج إليها فعليًا. على سبيل المثال، يؤدي الإجراء التالي إلى إضافة تبعيات على وحدات مكتبة ExoPlayer وDASH وUI، وهو ما قد يكون مطلوبًا لتطبيق يشغّل محتوى DASH فقط:

Kotlin

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

رائع

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

تفعيل تصغير الرموز والموارد

يجب تفعيل ميزة تقليل حجم الرموز والموارد لإصدارات تطبيقك. تم تصميم 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 مباشرةً إلى باني 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));