Picture-in-Picture (PiP) هو وضع تشغيل فيديو في نافذة عائمة فوق التطبيقات الأخرى، مما يسمح للمستخدم بمواصلة المشاهدة عند تصغير التطبيق أو التبديل بين البرامج. يتم وضع نافذة PiP تلقائياً في زاوية الشاشة ويمكن للمستخدم تحريكها. وفقاً لوثائق Apple AVPictureInPictureController (2026)، فإن وضع PiP مدعوم على iOS بدءاً من الإصدار 14 وعلى Android بدءاً من الإصدار 8.0.
الرئيسية
Picture-in-Picture (PiP) هو وضع عرض فيديو في نافذة عائمة صغيرة تبقى فوق جميع النوافذ والتطبيقات الأخرى. يمكن للمستخدم تحريك نافذة PiP عبر الشاشة، وتغيير حجمها (على بعض المنصات) ومواصلة مشاهدة المحتوى أثناء العمل في تطبيقات أخرى.
جاء مفهوم PiP من التلفزيون: ففي التسعينيات، كانت أجهزة التلفزيون تسمح بعرض قناة ثانية في زاوية الشاشة. على الأجهزة المحمولة، ظهر PiP لأول مرة على iPad في iOS 9 (2015) لفيديو Safari، بينما أصبح PiP النظامي الكامل للتطبيقات متاحاً في iOS 14 (2020). دعم PiP على Android جاء مبكراً — في الإصدار 8.0 Oreo (2017)، ولكن فقط للفيديو، وبدءاً من Android 12 لأنواع المحتوى المختلفة.
يختلف PiP عن التشغيل في الخلفية بأن الفيديو يستمر في الظهور على الشاشة، وليس فقط التشغيل في تدفق الصوت. التشغيل الصوتي في الخلفية متاح على كلا المنصتين، لكن PiP يمنح المستخدم تحكماً بصرياً في المحتوى: يمكنه رؤية الإطارات، والإيقاف المؤقت، والترجيع، أو إغلاق النافذة. هذا مهم بشكل خاص للدروس المرئية، والبث المباشر، ومكالمات الفيديو حيث المحتوى المرئي لا يقل أهمية عن الصوت.
معمارياً، يتم تنفيذ PiP من خلال مدير نوافذ النظام الذي ينشئ نافذة منفصلة بأولوية عرض منخفضة. يفوض التطبيق إخراج الفيديو إلى خدمة نظام تستمر في عرض الفيديو حتى بعد انتقال التطبيق إلى الخلفية أو تصغيره.
تبدأ العملية عندما يقوم المستخدم بتصغير التطبيق مع فيديو نشط أو يضغط على زر PiP (على iOS)، أو يقوم النظام تلقائياً بنقل Activity إلى وضع PiP (على Android). يقوم مدير نوافذ النظام بالتقاط تدفق الفيديو وإنشاء نافذة عائمة بنسب ثابتة. يعتمد حجم النافذة على نسبة أبعاد الفيديو الأصلي وقيود المنصة: على iOS، تشغل نافذة PiP حوالي 1/6–1/4 من عرض الشاشة؛ على Android، لا تقل عن 108 dp عرضاً و 240 dp ارتفاعاً للأجهزة المحمولة.
عندما تكون نافذة PiP نشطة، يمكن أن يكون التطبيق في واحدة من ثلاث حالات: في الخلفية (مصغر)، في الحالة النشطة (عاد المستخدم إلى التطبيق)، أو في حالة انتظار (أوقف النظام PiP بسبب نقص الموارد). عند الانتقال إلى PiP، يجب على التطبيق إيقاف عمليات واجهة المستخدم غير الضرورية (الرسوم المتحركة، عرض الواجهة) وتحرير الذاكرة، حيث يتم توزيع موارد النظام بشكل أكثر تقييداً في وضع تعدد المهام. يرسل iOS تلقائياً إشعار AVPictureInPictureControllerWillStartNotification إلى التطبيق، بينما يرسل Android استدعاء onPictureInPictureModeChanged.
نافذة PiP لها قيود كبيرة: لا يمكنها عرض عناصر تحكم واجهة المستخدم القياسية (زر الإيقاف المؤقت، شريط التقدم) — فقط تراكب نظام بحد أدنى مع عناصر أساسية: تشغيل/إيقاف مؤقت، إغلاق، توسيع إلى ملء الشاشة. واجهة PiP النظامية على iOS تتضمن زر إيقاف مؤقت وزر إغلاق، وعلى Android تتضمن نفس العناصر بالإضافة إلى زر إعدادات إضافي. التفاعل مع المحتوى داخل PiP (الترجيع، اختيار الترجمة) غير ممكن — لذلك يجب توسيع التطبيق إلى ملء الشاشة.
على iOS، يتم تنفيذ PiP من خلال إطار AVKit وفئة AVPictureInPictureController. هذه الواجهة البرمجية متاحة على iOS 14+ لـ iPhone وiPad، ولكن بمتطلبات مختلفة: على iPad، يعمل PiP عبر AVPlayerLayer؛ على iPhone، فقط عبر AVPlayerViewController.
لكي يعمل PiP على iOS، يجب استيفاء عدة شروط: يجب على التطبيق استخدام AVPlayer لتشغيل الفيديو، ويجب ضبط جلسة الصوت على الفئة .playback أو .playAndRecord، ويجب أن يكون للتطبيق صلاحيات للصوت في الخلفية (UIBackgroundModes = audio). بدون هذه الإعدادات، لن يبدأ PiP — سيرفض النظام طلب جلسة PiP لأنه لا يمكنه ضمان التشغيل الصحيح بعد الانتقال إلى الخلفية.
على iOS، تظهر نافذة PiP تلقائياً عند تصغير التطبيق إذا كان الفيديو قيد التشغيل النشط ولم يقم المستخدم بتعطيل هذه الميزة في الإعدادات. يمكن للمستخدم أيضاً تصغير الفيديو يدوياً إلى PiP عبر الزر في AVPlayerViewController. حجم نافذة PiP على iOS ثابت ويحدده النظام — لا يمكن للمطور تغييره. نسبة أبعاد نافذة PiP تتوافق مع نسبة أبعاد الفيديو الأصلي، لكن الحجم الأقصى محدود بـ 1/4 عرض الشاشة على iPhone و 1/3 على iPad.
القيود الرئيسية لـ PiP على iOS: استحالة وجود واجهة مخصصة في نافذة PiP، تدفق PiP واحد في المرة الواحدة، وشرط وجود AVPlayer نشط لعمل PiP. Multi-PiP — التشغيل المتزامن لنوافذ PiP متعددة — غير مدعوم على iOS. عند محاولة تشغيل PiP ثانٍ، يتم إغلاق الأول تلقائياً. هذا قيد أجهزة: لا يمكن لمعالج الفيديو خدمة قناتي PiP مستقلتين في وقت واحد بسبب قيود DMA وذاكرة الفيديو.
قيد مهم آخر هو مدة التشغيل في الخلفية. إذا لم يتفاعل المستخدم مع نافذة PiP، فقد يوقف النظام التشغيل بعد فترة لتوفير الطاقة. الإيقاف المؤقت التلقائي لـ PiP على iOS يحدث بعد 10–15 دقيقة من عدم النشاط إذا لم يطبق التطبيق آلية keep-alive من خلال مهمة خلفية. لمكالمات الفيديو والبث المباشر، يُوصى باستخدام PushKit وشهادات VoIP التي تتجاوز هذا القيد.
على Android، يتم تنفيذ PiP كوضع مدمج لـ Activity يتم تفعيله من خلال طريقة enterPictureInPictureMode. منذ Android 8.0 (API 26)، يمكن لأي Activity الدخول في وضع PiP، ومنذ Android 12 (API 31) ظهر دعم PiP لـ SurfaceView وTextureView دون الحاجة لاستخدام MediaCodec.
لدعم PiP في بيان Android، يجب تحديد السمة android:supportsPictureInPicture لـ Activity في قسم
في Android، نافذة PiP افتراضياً لا تحتوي على عناصر تحكم. يمكن للمطور إضافة إجراءات مخصصة عبر RemoteAction في طريقة setPictureInPictureParams. تتوفر حتى 3 إجراءات (مثل: إيقاف مؤقت/تشغيل، ترجيع/تقديم، إغلاق). يظهر كل إجراء في تراكب PiP النظامي كأيقونة. على عكس iOS حيث جميع عناصر الواجهة ثابتة بشكل صارم، يوفر Android مرونة أكبر للضوابط الأساسية.
PiP على Android له إمكانيات مختلفة حسب إصدار نظام التشغيل. على Android 8.0–8.1، PiP متاح فقط للفيديو المشغل عبر MediaPlayer أو MediaCodec مع SurfaceView. بدءاً من Android 9 يمكن استخدام PictureInPictureArgs.Builder لتكوين نسبة أبعاد نافذة PiP. أضاف Android 12 دعم PiP لـ SurfaceView وTextureView المخصصين، بالإضافة إلى انتقالات محسنة بين وضع ملء الشاشة وPiP. Android 13+ يسمح بعرض نافذة PiP حتى عند قفل الشاشة، إذا كان للتطبيق الإذن المناسب.
| إصدار Android | إمكانيات PiP | API |
|---|---|---|
| 8.0–8.1 | PiP أساسي لـ MediaPlayer/MediaCodec | 26–27 |
| 9–11 | تكوين نسبة الأبعاد، إجراءات مخصصة | 28–30 |
| 12 | دعم PiP لـ SurfaceView/TextureView | 31 |
| 13+ | PiP على شاشة القفل، رسوم متحركة محسنة | 33+ |
الفرق الرئيسي لـ PiP على Android عن iOS هو إمكانية multi-PiP. على Android 12+، يمكن للنظام عرض نوافذ PiP متعددة في وقت واحد إذا كانت التطبيقات تدعم ذلك وأداء الجهاز يسمح بذلك. لكن عملياً، multi-PiP محدود بإمكانيات SoC: معظم الأجهزة تدعم نافذة PiP واحدة فقط بسبب قيود أجهزة جهاز فك التشفير، حيث تتطلب كل نافذة PiP تدفق فيديو خاص بها وجلسة فك تشفير منفصلة.
لنلقِ نظرة على تنفيذ عملي لـ PiP على كلتا المنصتين المحمولتين، مع مراعاة أحدث تغييرات API.
import AVKit
import AVFoundation
class VideoPlayerViewController: UIViewController {
var player: AVPlayer!
var pipController: AVPictureInPictureController?
override func viewDidLoad() {
super.viewDidLoad()
let playerLayer = AVPlayerLayer(player: player)
playerLayer.videoGravity = .resizeAspect
view.layer.addSublayer(playerLayer)
guard AVPictureInPictureController.isPictureInPictureSupported()
else { return }
pipController = AVPictureInPictureController(playerLayer: playerLayer)
pipController?.delegate = self
}
@IBAction func startPiPTapped() {
pipController?.startPictureInPicture()
}
}
extension VideoPlayerViewController: AVPictureInPictureControllerDelegate {
func pictureInPictureControllerWillStart(
_ pictureInPictureController: AVPictureInPictureController
) {
// إخفاء عناصر واجهة المستخدم، تحرير الذاكرة
}
func pictureInPictureControllerDidStop(
_ pictureInPictureController: AVPictureInPictureController
) {
// استعادة الواجهة، استئناف العرض
}
}
في هذا المثال، يتم تهيئة AVPictureInPictureController مع playerLayer بعد التحقق من isPictureInPictureSupported (PiP غير مدعوم على iPhone SE الجيل الأول وبعض iPad بدون ذاكرة كافية). يقوم المفوض بإعلام التطبيق ببدء وإنهاء PiP — في هذه الاستدعاءات يجب إخفاء واستعادة عناصر واجهة المستخدم، لأن واجهة التطبيق غير مرئية في وضع PiP. عند الانتقال إلى PiP، يُوصى بإيقاف جميع الرسوم المتحركة، وإخفاء عناصر تحكم المشغل، وتحرير الذاكرة غير المستخدمة لمنع التفريغ الإجباري للتطبيق بواسطة النظام.
class PipVideoActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setupVideoPlayer()
}
private fun enterPipMode() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val aspectRatio = Rational(16, 9)
val pipParams = PictureInPictureParams.Builder()
.setAspectRatio(aspectRatio)
.setAutoEnterEnabled(true)
.build()
enterPictureInPictureMode(pipParams)
}
}
override fun onPictureInPictureModeChanged(
isInPictureInPictureMode: Boolean,
newConfig: Configuration
) {
if (isInPictureInPictureMode) {
// إخفاء الواجهة، التركيز فقط على الوسائط
binding.controlsGroup.visibility = View.GONE
} else {
// استعادة الواجهة
binding.controlsGroup.visibility = View.VISIBLE
}
}
}
المثال بلغة Kotlin يستخدم PictureInPictureParams.Builder لتكوين PiP. تحدد طريقة setAspectRatio نسبة أبعاد نافذة PiP (16:9 للفيديو النموذجي). setAutoEnterEnabled(true) يفعل الانتقال التلقائي إلى PiP عند تصغير التطبيق. يتم استدعاء onPictureInPictureModeChanged عند الدخول والخروج من PiP — هنا يجب إخفاء أو إظهار عناصر واجهة المستخدم. للفيديو على SurfaceView، يلزم معالجة إضافية للتكوين بإضافة android:configChanges="screenSize|smallestScreenSize" إلى البيان لمنع إعادة إنشاء Activity أثناء الانتقال إلى وضع PiP.
PiP أداة قوية لتحسين تجربة المستخدم في التطبيقات حيث يبقى المحتوى ملائماً حتى عند التبديل إلى مهام أخرى. لكن يجب أن يكون تنفيذ PiP مبرراً وألا يشتت المستخدم.
مكالمات الفيديو والمؤتمرات هي أحد السيناريوهات الرئيسية لـ PiP. في Zoom وFaceTime وGoogle Meet، يسمح PiP برؤية المحاور أثناء العمل في تطبيقات أخرى: قراءة الملاحظات، مشاهدة عرض تقديمي، أو التحقق من البريد الإلكتروني. PiP لمكالمات الفيديو يتطلب دعم الكاميرا في الخلفية وتكويناً صحيحاً لجلسة الصوت لمواصلة التقاط الصوت في الخلفية. على iOS، يتم ذلك باستخدام AVSampleBufferDisplayLayer بدلاً من AVPlayerLayer، لأن مكالمات الفيديو لا تستخدم AVPlayer.
خدمات البث (YouTube، Netflix، Twitch) تستخدم PiP بنشاط لمواصلة المشاهدة أثناء البحث عن محتوى جديد. YouTube Premium يقدم PiP كميزة مدفوعة، وNetflix أيضاً تقيد PiP بخطط اشتراك معينة بسبب قيود ترخيص المحتوى. لتنفيذ PiP في تطبيق بث، يلزم التكامل مع نظام DRM (FairPlay، Widevine) الذي يدعم خط أنابيب آمناً في وضع PiP.
PiP غير مناسب للتطبيقات ذات محتوى الفيديو التفاعلي الذي يتطلب تفاعل المستخدم: المنصات التعليمية مع اختبارات داخل المشغل، بث الألعاب مع الدردشة، تطبيقات التسوق مع روابط المنتجات في الفيديو. في هذه الحالات، نافذة PiP صغيرة جداً لعرض المعلومات الإضافية، والعناصر التفاعلية غير مدعومة داخل PiP. يُوصى باستخدام PiP فقط للمشاهدة السلبية عندما لا يكون التفاعل مع المحتوى مطلوباً.
لتطبيقات الموسيقى والبودكاست، PiP مبالغ فيه — يكفي الصوت في الخلفية بدون نافذة مرئية. PiP يستهلك موارد GPU إضافية لعرض الفيديو في نافذة عائمة، مما يقلل من عمر البطارية. إذا كان المحتوى سمعياً (موسيقى، بودكاست، كتب صوتية) — استخدم التشغيل في الخلفية بدون PiP. إذا كان بصرياً — قم بتنفيذ PiP لتحسين تجربة المستخدم.
الأسئلة الشائعة
PiP على iOS يتطلب iPhone 6s+ وiOS 14+ ومنطقة مدعومة (الولايات المتحدة، كندا، أستراليا، الاتحاد الأوروبي، روسيا وغيرها). يجب على التطبيق تكوين جلسة الصوت على الفئة .playback وإضافة UIBackgroundModes = audio. تحقق أيضاً من الإعدادات: الإعدادات > عام > صورة داخل صورة.
على iOS، حجم نافذة PiP يحدده النظام بالكامل ولا يمكن تكوينه من قبل المطور. على Android، يمكن تعيين نسبة الأبعاد فقط عبر setAspectRatio في PictureInPictureParams.Builder، لكن الحجم الدقيق للنافذة يحدده النظام. يمكن للمستخدم تغيير حجم نافذة PiP على Android 12+ بإيماءة القرص للتكبير.
نعم، يعمل PiP مع المحتوى المحمي بـ DRM (FairPlay على iOS، Widevine L1 على Android) بشرط أن تدعم جلسة DRM خط أنابيب آمناً في وضع PiP. Widevine L3 قد لا يدعم PiP، لأنه لا يضمن أمان المحتوى المفكوك تشفيره في نافذة عائمة. تحقق من توافق DRM مع PiP خلال مرحلة الاختبار.
على iOS — نافذة PiP واحدة فقط. على Android 12+، نظرياً يتم دعم multi-PiP، لكن عملياً معظم الأجهزة محدودة بنافذة واحدة بسبب قيود الأجهزة. الأجهزة الرائدة (Samsung Galaxy S24، Pixel 8) قد تدعم نافذتي PiP، ولكن بأداء منخفض.
نعم، معالجة دورة الحياة مهمة جداً. على iOS، عند الانتقال إلى PiP، يتلقى التطبيق إشعار willStart حيث يجب إخفاء الواجهة وتحرير الذاكرة. على Android، يتم استدعاء onPictureInPictureModeChanged عند الدخول/الخروج من PiP. بدون معالجة صحيحة لدورة الحياة، قد يقوم النظام بتفريغ التطبيق من الذاكرة، مما يقطع التشغيل.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.