تقليص حزمة APK
تنظيم صفحاتك في مجموعات
يمكنك حفظ المحتوى وتصنيفه حسب إعداداتك المفضّلة.
يُعد تقليل حجم حزمة APK أحد الجوانب المهمة في تطوير تطبيق Android جيد، وينطبق ذلك بشكل خاص عند استهداف الأسواق النامية، وكذلك عند تطوير تطبيق فوري على Android. وفي مثل هذه الحالات، قد يكون من المستحسن تقليل حجم مكتبة ExoPlayer المضمّنة في حزمة APK. توضّح هذه الصفحة بعض الخطوات البسيطة التي يمكن أن تساعد في تحقيق ذلك.
استخدام العناصر التابعة المطلوبة فقط
استخدِم وحدات المكتبة التي تحتاج إليها فقط. على سبيل المثال، سيؤدي ما يلي إلى إضافة تبعيات على وحدات مكتبة ExoPlayer وDASH وواجهة المستخدم، كما قد يكون مطلوبًا لتطبيق يعرض محتوى DASH فقط:
Kotlin
implementation("androidx.media3:media3-exoplayer:1.8.0")
implementation("androidx.media3:media3-exoplayer-dash:1.8.0")
implementation("androidx.media3:media3-ui:1.8.0")
Groovy
implementation "androidx.media3:media3-exoplayer:1.8.0"
implementation "androidx.media3:media3-exoplayer-dash:1.8.0"
implementation "androidx.media3:media3-ui:1.8.0"
تفعيل تصغير الرموز والموارد
يجب تفعيل تخفيض حجم الرموز والموارد في إصدارات تطبيقك. تم تصميم 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.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));
يخضع كل من المحتوى وعيّنات التعليمات البرمجية في هذه الصفحة للتراخيص الموضحّة في ترخيص استخدام المحتوى. إنّ Java وOpenJDK هما علامتان تجاريتان مسجَّلتان لشركة Oracle و/أو الشركات التابعة لها.
تاريخ التعديل الأخير: 2025-08-27 (حسب التوقيت العالمي المتفَّق عليه)
[[["يسهُل فهم المحتوى.","easyToUnderstand","thumb-up"],["ساعَدني المحتوى في حلّ مشكلتي.","solvedMyProblem","thumb-up"],["غير ذلك","otherUp","thumb-up"]],[["لا يحتوي على المعلومات التي أحتاج إليها.","missingTheInformationINeed","thumb-down"],["الخطوات معقدة للغاية / كثيرة جدًا.","tooComplicatedTooManySteps","thumb-down"],["المحتوى قديم.","outOfDate","thumb-down"],["ثمة مشكلة في الترجمة.","translationIssue","thumb-down"],["مشكلة في العيّنات / التعليمات البرمجية","samplesCodeIssue","thumb-down"],["غير ذلك","otherDown","thumb-down"]],["تاريخ التعديل الأخير: 2025-08-27 (حسب التوقيت العالمي المتفَّق عليه)"],[],[],null,["# APK shrinking\n\nMinimizing APK size is an important aspect of developing a good Android\napp. This is particularly true when targeting developing markets, and\nalso when developing an Android Instant App. For such cases, it may be desirable\nto minimize the size of the ExoPlayer library that's included in the APK. This\npage outlines some simple steps that can help to achieve this.\n\nUse only required dependencies\n------------------------------\n\nDepend only on the library modules that you actually need. For example, the\nfollowing will add dependencies on the ExoPlayer, DASH, and UI library modules,\nas might be required for an app that only plays DASH content: \n\n### Kotlin\n\n```kotlin\nimplementation(\"androidx.media3:media3-exoplayer:1.8.0\")\nimplementation(\"androidx.media3:media3-exoplayer-dash:1.8.0\")\nimplementation(\"androidx.media3:media3-ui:1.8.0\")\n```\n\n### Groovy\n\n```groovy\nimplementation \"androidx.media3:media3-exoplayer:1.8.0\"\nimplementation \"androidx.media3:media3-exoplayer-dash:1.8.0\"\nimplementation \"androidx.media3:media3-ui:1.8.0\"\n```\n\nEnable code and resource shrinking\n----------------------------------\n\nYou should enable code and resource shrinking for your app's release\nbuilds. ExoPlayer is structured in a way that allows code shrinking to\neffectively remove unused functionality. For example, for an app that\nplays DASH content, ExoPlayer's contribution to APK size can be reduced by\napproximately 40% by enabling code shrinking.\n\nRead [Shrink, obfuscate, and optimize your app](/studio/build/shrink-code) to learn how to enable\ncode and resource shrinking.\n\nSpecify which renderers your app needs\n--------------------------------------\n\nBy default, the player's renderers will be created using\n`DefaultRenderersFactory`. `DefaultRenderersFactory` depends on all of the\n`Renderer` implementations provided in the ExoPlayer library, and as a result\nnone of them will be removed by code shrinking. If you know that your app only\nneeds a subset of renderers, you can specify your own `RenderersFactory`\ninstead. For example, an app that only plays audio can define a factory like\nthis when instantiating `ExoPlayer` instances: \n\n### Kotlin\n\n```kotlin\nval audioOnlyRenderersFactory =\n RenderersFactory {\n handler: Handler,\n videoListener: VideoRendererEventListener,\n audioListener: AudioRendererEventListener,\n textOutput: TextOutput,\n metadataOutput: MetadataOutput,\n -\u003e\n arrayOf\u003cRenderer\u003e(\n MediaCodecAudioRenderer(context, MediaCodecSelector.DEFAULT, handler, audioListener)\n )\n}\nval player = ExoPlayer.Builder(context, audioOnlyRenderersFactory).build()\n```\n\n### Java\n\n```java\nRenderersFactory audioOnlyRenderersFactory =\n (handler, videoListener, audioListener, textOutput, metadataOutput) -\u003e\n new Renderer[] {\n new MediaCodecAudioRenderer(\n context, MediaCodecSelector.DEFAULT, handler, audioListener)\n };\nExoPlayer player = new ExoPlayer.Builder(context, audioOnlyRenderersFactory).build();\n```\n\n\u003cbr /\u003e\n\nThis will allow other `Renderer` implementations to be removed by code\nshrinking. In this particular example video, text and metadata renderers are\nremoved (which means any subtitles or in-stream metadata (e.g.\n[ICY](https://cast.readme.io/docs/icy)) won't be processed or emitted by the\nplayer).\n\nSpecify which extractors your app needs\n---------------------------------------\n\nBy default, the player creates `Extractor` instances to play progressive media using\n`DefaultExtractorsFactory`. `DefaultExtractorsFactory` depends on all of the\n`Extractor` implementations provided in the ExoPlayer library, and as a result\nnone of them will be removed by code shrinking. If you know that your app only\nneeds to play a small number of container formats, or doesn't play progressive\nmedia at all, you can specify your own `ExtractorsFactory` instead. For example,\nan app that only needs to play mp4 files can provide a factory like: \n\n### Kotlin\n\n```kotlin\nval mp4ExtractorFactory = ExtractorsFactory {\n arrayOf\u003cExtractor\u003e(Mp4Extractor(DefaultSubtitleParserFactory()))\n}\nval player =\n ExoPlayer.Builder(context, DefaultMediaSourceFactory(context, mp4ExtractorFactory)).build()\n```\n\n### Java\n\n```java\nExtractorsFactory mp4ExtractorFactory =\n () -\u003e new Extractor[] {new Mp4Extractor(new DefaultSubtitleParserFactory())};\nExoPlayer player =\n new ExoPlayer.Builder(context, new DefaultMediaSourceFactory(context, mp4ExtractorFactory))\n .build();\n```\n\n\u003cbr /\u003e\n\nThis will allow other `Extractor` implementations to be removed by code\nshrinking, which can result in a significant reduction in size.\n\nIf your app is not playing progressive content at all, you should pass\n`ExtractorsFactory.EMPTY` to the `DefaultMediaSourceFactory` constructor, then\npass that `mediaSourceFactory` to the `ExoPlayer.Builder` constructor. \n\n### Kotlin\n\n```kotlin\nval player =\n ExoPlayer.Builder(context, DefaultMediaSourceFactory(context, ExtractorsFactory.EMPTY)).build()\n```\n\n### Java\n\n```java\nExoPlayer player =\n new ExoPlayer.Builder(\n context, new DefaultMediaSourceFactory(context, ExtractorsFactory.EMPTY))\n .build();\n```\n\n\u003cbr /\u003e\n\nCustom MediaSource instantiation\n--------------------------------\n\nIf your app is using a custom `MediaSource.Factory` and you want\n`DefaultMediaSourceFactory` to be removed by code stripping, you should pass\nyour `MediaSource.Factory` directly to the `ExoPlayer.Builder` constructor. \n\n### Kotlin\n\n```kotlin\nval player = ExoPlayer.Builder(context, customMediaSourceFactory).build()\n```\n\n### Java\n\n```java\nExoPlayer player = new ExoPlayer.Builder(context, mediaSourceFactory).build();\n```\n\n\u003cbr /\u003e\n\nIf your app is using `MediaSource` directly instead of `MediaItem` you should\npass `MediaSource.Factory.UNSUPPORTED` to the `ExoPlayer.Builder` constructor,\nto ensure `DefaultMediaSourceFactory` and `DefaultExtractorsFactory` can be\nstripped by code shrinking. \n\n### Kotlin\n\n```kotlin\nval player = ExoPlayer.Builder(context, MediaSource.Factory.UNSUPPORTED).build()\nval mediaSource =\n ProgressiveMediaSource.Factory(dataSourceFactory, customExtractorsFactory)\n .createMediaSource(MediaItem.fromUri(uri))\n```\n\n### Java\n\n```java\nExoPlayer player = new ExoPlayer.Builder(context, MediaSource.Factory.UNSUPPORTED).build();\nProgressiveMediaSource mediaSource =\n new ProgressiveMediaSource.Factory(dataSourceFactory, customExtractorsFactory)\n .createMediaSource(MediaItem.fromUri(uri));\n```\n\n\u003cbr /\u003e"]]