ExoPlayer هي مكتبة مشغل وسائط مفتوحة المصدر لأندرويد طورتها Google كبديل لـ MediaPlayer المدمج. يوفر ExoPlayer تشغيل الصوت والفيديو بتنسيقات متعددة، بما في ذلك DASH وHLS وSmoothStreaming وملفات الوسائط العادية، من خلال واجهة برمجة تطبيقات واحدة مع دعم البث التكيفي. وفقاً لـ Google I/O (2024)، يُستخدم ExoPlayer في أكثر من 60,000 تطبيق أندرويد، بما في ذلك YouTube وGoogle TV وNetflix.
الملامح الرئيسية
ExoPlayer هي مكتبة تشغيل وسائط متعددة مفتوحة المصدر (Apache 2.0) لأندرويد، أصدرت Google أول إصدار لها في 2014. على عكس MediaPlayer المدمج، الذي يعد غلافاً رقيقاً فوق برنامج ترميز الوسائط النظامي (MediaCodec)، تم تنفيذ ExoPlayer بالكامل على مستوى Java/Kotlin، مما يمنح المطورين تحكماً كاملاً في كل مرحلة من مراحل التشغيل.
من الناحية المعمارية، تم بناء ExoPlayer على مبدأ معياري: كل جانب من جوانب التشغيل يتم تنفيذه بواسطة مكون منفصل. الوحدة الأساسية (exoplayer-core) تحتوي على المشغل والعارضين ومحددات المسارات وإدارة المخزن المؤقت. الوحدات الإضافية (exoplayer-dash, exoplayer-hls, exoplayer-rtsp, exoplayer-smoothstreaming) تضيف دعم البروتوكولات البث المقابلة. تسمح هذه البنية للتطبيقات بتضمين المكونات الضرورية فقط، مما يقلل من حجم APK.
ExoPlayer 2 (الإصدار الرئيسي الحالي) تم إصداره في 2018 وجلب إعادة صياغة جذرية لواجهة API: تقديم واجهة Player، دعم Compose عبر AndroidX Media3، تحسين معالجة الأخطاء وخوارزميات اختيار المسار التكيفي. بدءاً من الإصدار 2.19 (2024)، أصبح ExoPlayer جزءاً من مكتبة AndroidX Media، مما يبسط التكامل والتحديثات عبر مدير التبعيات القياسي لأندرويد.
في قلب ExoPlayer يوجد المكون ExoPlayerImpl، الذي يدير دورة حياة التشغيل. يحتوي على MediaSource (مصدر الوسائط)، TrackSelector (اختيار المسار)، LoadControl (إدارة التخزين المؤقت) وقائمة Renderer (عارضين للفيديو والصوت والترجمات والبيانات الوصفية). يمكن استبدال كل مكون بتطبيق مخصص من خلال Builder أو طرق المصنع.
لعرض الفيديو، يستخدم ExoPlayer SurfaceView أو TextureView أو SphericalSurfaceView (للفيديو بزاوية 360 درجة). الخيار الموصى به هو SurfaceView، لأنه يوفر تسريعاً عتادياً واستهلاكاً أدنى للطاقة. بالنسبة لـ Jetpack Compose، توفر مكتبة AndroidX Media3 المكون `AndroidView`، الذي يغلف SurfaceView، والمكون التجريبي `Media3Compose` مع تكامل أصلي لـ Compose.
ExoPlayer يوفر مجموعة واسعة من الميزات تتجاوز مشغل الوسائط العادي. تشمل القدرات الرئيسية دعم جميع بروتوكولات البث الشائعة، ونظام DRM مرن، والتبديل التكيفي لمعدل البت (ABR) وأدوات تحليل التشغيل.
| الميزة | الوصف | الوحدة |
|---|---|---|
| DASH | بث تكيفي وفقاً لمعيار MPEG | exoplayer-dash |
| HLS | بث مباشر HTTP من Apple | exoplayer-hls |
| SmoothStreaming | بث تكيفي من Microsoft | exoplayer-smoothstreaming |
| RTSP | بروتوكول البث في الوقت الفعلي للمباشر | exoplayer-rtsp |
| Widevine | حماية المحتوى بإدارة الحقوق الرقمية | exoplayer-drm |
| Concatenation | دمج ملفات وسائط متعددة | exoplayer-core |
| Ads | تكامل IMA SDK للإعلانات | exoplayer-ima |
ABR (Adaptive Bitrate) في ExoPlayer يتم تنفيذه من خلال واجهة AdaptiveTrackSelection. بشكل افتراضي، يُستخدم AdaptiveTrackSelectionFactory الذي ينشئ DefaultAdaptiveTrackSelection — خوارزمية متوازنة تراعي عرض النطاق الترددي للشبكة وحجم المخزن المؤقت. بالنسبة للسيناريوهات المحددة، يمكن توصيل تطبيقات بديلة: BOLA (تقليل التبديلات)، RandomAdaptiveTrackSelection (اختبار) أو تطبيق مخصص من خلال واجهة TrackSelection.
BandwidthMeter — مكون رئيسي آخر مسؤول عن قياس عرض النطاق الترددي للشبكة. بشكل افتراضي، يُستخدم DefaultBandwidthMeter الذي يجمع إحصائيات جميع طلبات HTTP الخاصة بالمشغل. يمكن للمطور توسيعه ليشمل عوامل إضافية: نوع الشبكة (Wi-Fi، 4G، 5G)، إشارة برج الخلوي أو تكلفة البيانات للمستخدم.
ExoPlayer يدعم Widevine (L1, L3) وPlayReady وClearKey DRM. يتم تكوين الحصول على الترخيص من خلال DrmSessionManager الذي يتفاعل مع خادم الترخيص. للفيديو المتميز (4K HDR)، يلزم دعم عتادي لـ Widevine L1، مما يوفر حماية على مستوى الشريحة ويمنع التقاط الشاشة. يعتمد اختيار نظام DRM على المنصة المستهدفة: يُستخدم Widevine على Android وChromecast، وPlayReady على Xbox وWindows، وFairPlay على iOS وApple TV. يحدد ExoPlayer نظام DRM المتاح تلقائياً بناءً على ملف MPD ولا يتطلب تكويناً يدوياً للسيناريوهات الأساسية.
يتم توصيل ExoPlayer بمشروع أندرويد من خلال تبعيات Gradle. بدءاً من الإصدار 2.19، أصبح ExoPlayer جزءاً من AndroidX Media (androidx.media3)، مما يضمن التوافق مع Jetpack Compose ومكونات AndroidX الأخرى. دعنا نلقي نظرة على التكامل خطوة بخطوة في Kotlin.
أضف وحدات ExoPlayer إلى ملف build.gradle (Module). تشمل المجموعة الدنيا core وui والوحدة النمطية لبروتوكول البث المطلوب. لتشغيل محتوى DASH، يلزم exoplayer-dash، ولـ HLS — exoplayer-hls.
dependencies {
implementation "androidx.media3:media3-exoplayer:1.5.0"
implementation "androidx.media3:media3-ui:1.5.0"
implementation "androidx.media3:media3-exoplayer-dash:1.5.0"
implementation "androidx.media3:media3-exoplayer-hls:1.5.0"
}
إنشاء وتكوين المشغل في Activity أو Fragment. يستخدم ExoPlayer PlayerView (أو StyledPlayerView للتخصيص) لعرض الفيديو وعناصر التحكم المدمجة. يشمل الحد الأدنى من التكوين إنشاء المشغل عبر ExoPlayer.Builder وتمرير MediaItem مع URI المصدر.
class PlayerActivity : AppCompatActivity() {
private var player: ExoPlayer? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_player)
player = ExoPlayer.Builder(this).build()
val playerView = findViewById<StyledPlayerView>(R.id.playerView)
playerView.player = player
val mediaItem = MediaItem
.Builder()
.setUri("https://example.com/video.mp4")
.build()
player?.setMediaItem(mediaItem)
player?.prepare()
}
override fun onDestroy() {
player?.release()
super.onDestroy()
}
}
لتطبيقات الإنتاج، من الضروري معالجة أخطاء التشغيل المحتملة: أعطال الشبكة، التنسيقات غير المدعومة، أخطاء ترخيص DRM. يوفر ExoPlayer واجهة Player.Listener مع طرق onPlayerError وonPlaybackStateChanged وonPlayWhenReadyChanged. يُنصح بعرض رسائل خطأ إعلامية للمستخدم مع خيار إعادة المحاولة.
الاختيار بين ExoPlayer و MediaPlayer المدمج هو سؤال شائع عند تطوير تطبيقات أندرويد. MediaPlayer جزء من Android SDK منذ الإصدار 1.0، بينما ExoPlayer مكتبة تتطلب تبعية Gradle. دعنا نلقي نظرة على الاختلافات بينهما وفقاً لمعايير رئيسية.
| المعيار | ExoPlayer | MediaPlayer |
|---|---|---|
| البنية | معيارية، بالكامل في Java/Kotlin | غلاف فوق مكونات C++ للنظام |
| البث | DASH, HLS, SmoothStreaming, RTSP | ملفات محلية فقط و HLS (Android 9+) |
| التخصيص | كامل (أي مكون قابل للاستبدال) | أدنى (معلمات فقط) |
| التحديثات | عبر Google Play أو APK (مستقل عن نظام التشغيل) | فقط عبر تحديث Android (OTA) |
| حجم APK | +1–3 ميغابايت (حسب الوحدات) | 0 (جزء من نظام التشغيل) |
| الحد الأدنى SDK | API 16+ (Android 4.1) | API 1+ |
| DRM | Widevine, PlayReady, ClearKey | Widevine (محدود) |
ExoPlayer يفوز في السيناريوهات التي تتطلب البث (DASH, HLS)، تخصيص واجهة المستخدم، دعم DRM والاستقلال عن إصدار Android. MediaPlayer مناسب للتطبيقات البسيطة التي تشغل ملفات وسائط محلية حيث يكون حجم APK مهماً ولا توجد متطلبات للبث التكيفي. للتطبيقات الحديثة التي تحتوي على محتوى من الشبكة، ExoPlayer هو الخيار الواضح.
استثناء — التطبيقات ذات SDK الأدنى أقل من API 16 (Android 4.1)، والتي لا توجد تقريباً في السوق. لجميع التطبيقات ذات targetSdk 33+ والحد الأدنى SDK 21+، ExoPlayer ليس فقط مفضلاً بل ضرورياً لدعم التنسيقات الحديثة مثل AV1 و Dolby Vision من خلال الإضافات المناسبة.
لتطبيقات الإنتاج، غالباً ما يتطلب التكامل الأساسي لـ ExoPlayer تكويناً إضافياً: إدارة التخزين المؤقت، تحسين المخزن المؤقت للشبكات المحمولة، التكامل مع التحليلات وتخصيص اختيار مسارات الصوت. دعنا نلقي نظرة على سيناريوهات الاستخدام المتقدمة.
CacheDataSourceFactory يسمح بتخزين المقاطع التي تم تنزيلها مؤقتاً على التخزين المحلي، مما يوفر حركة المرور عند المشاهدة المتكررة ويتيح التشغيل دون اتصال. يستخدم ExoPlayer SimpleCache من مكتبة exoplayer-cas — تخزين مؤقت قائم على الملفات مع دعم إخلاء LRU وحدود الحجم.
val cache = SimpleCache(
cacheDir,
LeastRecentlyUsedCacheEvictor(50 * 1024 * 1024),
AppDatabaseProvider(this)
)
val cacheDataSourceFactory = CacheDataSource
.Factory()
.setCache(cache)
val player = ExoPlayer.Builder(this)
.setMediaSourceFactory(
DefaultMediaSourceFactory(cacheDataSourceFactory)
)
.build()
في التطبيقات المحمولة، معالجة التبديل بين Wi-Fi والشبكة الخلوية أمر بالغ الأهمية. يوفر ExoPlayer ConnectivityManager لتتبع حالة الشبكة. عند فقدان الاتصال، يُنصح بعدم إيقاف المشغل بل تحويله إلى حالة PAUSED مع الحفاظ على الموضع. بعد استعادة الاتصال، استأنف التشغيل مع إعادة تحميل المقاطع.
مع إصدار AndroidX Media3، حصلت المكتبة على دعم تجريبي لـ Jetpack Compose. المكون `AndroidView` يغلف SurfaceView أو PlayerView، مما يضمن التوافق مع تسلسل Compose الهرمي. للتكامل الأعمق، تُستخدم مكتبة `androidx.media3:media3-ui-compose` التي توفر عناصر تحكم المشغل المتوافقة مع Compose.
@Composable
fun VideoPlayer(uri: String) {
val context = LocalContext.current
val player = remember {
ExoPlayer.Builder(context).build()
.also { it.setMediaItem(MediaItem.fromUri(uri)) }
}
DisposableEffect(key = null) {
player.prepare()
onDispose { player.release() }
}
AndroidView(
factory = { StyledPlayerView(context).also { it.player = player } }
)
}
الأسئلة الشائعة
ExoPlayer يدعم Android API 16+ (Android 4.1 Jelly Bean). ومع ذلك، لـ DASH و HLS مع مقاطع fMP4، يُوصى بـ API 21+ (Android 5.0 Lollipop). وحدات DRM (Widevine) تتطلب API 19+، وفك تشفير HEVC العتادي متاح من API 21.
نعم، ExoPlayer ممتاز لـ الصوت. للتشغيل الصوتي فقط، لا يلزم SurfaceView أو PlayerView. سيحدد ExoPlayer تلقائياً عارض الصوت ويعمل في الخلفية. للتشغيل في الخلفية، يُنصح باستخدام MediaSessionService للتكامل مع عناصر التحكم النظامية.
TrackSelector في ExoPlayer يدير اختيار المسارات الصوتية. للتبديل، استخدم player.getCurrentTracks().groups و player.setTrackSelectionParameters() مع تحديد اللغة الصوتية المفضلة. لتدفقات DASH و HLS ذات المسارات الصوتية المتعددة، يتم التبديل دون انقطاع التشغيل.
نعم، يدعم ExoPlayer الترجمة النصية المضمنة (في حاويات MP4, WebM) والخارجية بتنسيقات TTML وSRT وVTT وCEA-608. للترجمة النصية الخارجية، يُستخدم SingleSampleMediaSource أو MergingMediaSource للدمج مع تدفق الفيديو. يتم تكوين عرض الترجمة النصية المنمقة عبر CaptionStyleCompat.
للبث منخفض زمن الوصول، قم بتكوين LoadControl بقيم مخزن مؤقت مستهدفة أصغر: استخدم DefaultLoadControl.Builder().setTargetBufferBytes(1024 * 512).setBufferDurationsMs(500, 2000, 500, 1000) لـ HLS LL و DASH LL. أيضاً، حدد minPlaybackSpeed = 1.02 لتسريع ملء المخزن المؤقت عند التأخر عن البث المباشر.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.