عرض الوسائط

تتيح لك واجهات برمجة التطبيقات android.media.projection التي تم تقديمها في Android 5 (المستوى 21 من واجهة برمجة التطبيقات) تسجيل محتوى شاشة جهاز كبث وسائط يمكنك تشغيله أو تسجيله أو بثه إلى أجهزة أخرى، مثل أجهزة التلفزيون.

يقدّم نظام التشغيل Android 14 (المستوى 34 من واجهة برمجة التطبيقات) ميزة مشاركة شاشة التطبيق، ما يتيح للمستخدمين مشاركة نافذة تطبيق واحدة بدلاً من شاشة الجهاز بأكملها بغض النظر عن وضع النوافذ. تستبعد ميزة "مشاركة شاشة التطبيق" شريط الحالة وشريط التنقّل والرسائل الإشعارات وعناصر واجهة المستخدم الأخرى للنظام من الشاشة المشترَكة، حتى عند استخدام ميزة "مشاركة شاشة التطبيق" لالتقاط تطبيق في وضع ملء الشاشة. تتم مشاركة محتوى التطبيق المحدّد فقط.

تضمن ميزة "مشاركة شاشة التطبيق" خصوصية المستخدم وتزيد من إنتاجيته، كما تُحسِّن من إنجاز المهام المتعددة من خلال السماح للمستخدمين بتشغيل تطبيقات متعددة مع حصر مشاركة المحتوى بتطبيق واحد فقط.

ثلاثة طرق لعرض الإعلانات

تلتقط ميزة "إلقاء الوسائط" محتوى شاشة الجهاز أو نافذة التطبيق، ثم تصوّر الصورة التي تم التقاطها على شاشة افتراضية تعرض الصورة على Surface.

شاشة الجهاز الفعلية معروضة على شاشة افتراضية محتوى
              الشاشة الافتراضية المكتوبة في Surface الذي يقدّمه التطبيق
الشكل 1. شاشة الجهاز أو نافذة التطبيق الفعلية التي يتم عرضها على الشاشة الافتراضية شاشة افتراضية مكتوبة في Surface الذي يوفّره التطبيق

يقدّم التطبيق Surface من خلال MediaRecorder أو SurfaceTexture أو ImageReader، ما يستخدِم محتوى الشاشة التي تم تسجيلها ويتيح لك إدارة الصور المعروضة على Surface في الوقت الفعلي. يمكنك حفظ الصور كتسجيل أو بثها على التلفزيون أو على جهاز آخر.

العرض الفعلي

ابدأ جلسة عرض وسائط من خلال الحصول على رمز مميّز يمنح تطبيقك إمكانية التقاط محتوى شاشة الجهاز أو نافذة التطبيق. يتم تمثيل الرمز المميّز بمثيل من فئة MediaProjection.

استخدِم طريقة getMediaProjection() لخدمة النظام MediaProjectionManager لإنشاء مثيل MediaProjection عند بدء نشاط جديد. ابدأ النشاط باستخدام نية من ‎method createScreenCaptureIntent() لتحديد عملية التقاط الشاشة:

Kotlin

val mediaProjectionManager = getSystemService(MediaProjectionManager::class.java)
var mediaProjection : MediaProjection
val startMediaProjection = registerForActivityResult( StartActivityForResult() ) { result -> if (result.resultCode == RESULT_OK) { mediaProjection = mediaProjectionManager .getMediaProjection(result.resultCode, result.data!!) } }
startMediaProjection.launch(mediaProjectionManager.createScreenCaptureIntent())

Java

final MediaProjectionManager mediaProjectionManager =
    getSystemService(MediaProjectionManager.class);
final MediaProjection[] mediaProjection = new MediaProjection[1];
ActivityResultLauncher startMediaProjection = registerForActivityResult( new StartActivityForResult(), result -> { if (result.getResultCode() == Activity.RESULT_OK) { mediaProjection[0] = mediaProjectionManager .getMediaProjection(result.getResultCode(), result.getData()); } } );
startMediaProjection.launch(mediaProjectionManager.createScreenCaptureIntent());

الشاشة الافتراضية

العنصر الرئيسي في عرض الوسائط هو الشاشة الافتراضية التي يمكنك إنشاؤها من خلال استدعاء createVirtualDisplay() على مثيل MediaProjection:

Kotlin

virtualDisplay = mediaProjection.createVirtualDisplay(
                     "ScreenCapture",
                     width,
                     height,
                     screenDensity,
                     DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                     surface,
                     null, null)

Java

virtualDisplay = mediaProjection.createVirtualDisplay(
                     "ScreenCapture",
                     width,
                     height,
                     screenDensity,
                     DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                     surface,
                     null, null);

تحدّد المَعلمتان width وheight سمات الشاشة الافتراضية. للحصول على قيم العرض والارتفاع، استخدِم واجهات برمجة تطبيقات WindowMetrics التي تم تقديمها في الإصدار 11 من Android (المستوى 30 لواجهة برمجة التطبيقات). (لمعرفة التفاصيل، يُرجى الاطّلاع على القسم حجم Proyección de medios).

السطح

حدِّد حجم سطح عرض الوسائط لإنشاء إخراج بالدقة المناسبة. اجعل السطح كبيرًا (دقة منخفضة) لبث الشاشة على أجهزة التلفزيون أو شاشات الكمبيوتر وصغيرًا (دقة عالية) لتسجيل شاشة الجهاز.

اعتبارًا من الإصدار 12L من نظام التشغيل Android (المستوى 32 لواجهة برمجة التطبيقات)، عند عرض المحتوى الذي تم التقاطه على سطح العرض، يُكبِّر النظام المحتوى بشكلٍ موحّد مع الحفاظ على نسبة العرض إلى الارتفاع، بحيث تكون أبعاد المحتوى (العرض والارتفاع) مساوية أو أقل من الأبعاد المقابلة لسطح العرض. ويتم بعد ذلك تمركز المحتوى الذي تم التقاطه على السطح.

يُحسِّن نهج التكبير/التصغير في Android 12L ميزة بث الشاشة على أجهزة التلفزيون وغيرها من الشاشات الكبيرة من خلال زيادة حجم الصورة على السطح إلى أقصى حد مع ضمان الحفاظ على نسبة العرض إلى الارتفاع المناسبة.

إذن الوصول إلى الخدمة التي تعمل في المقدّمة

إذا كان تطبيقك يستهدف الإصدار 14 من نظام التشغيل Android أو إصدارًا أحدث، يجب أن يتضمّن ملف بيان التطبيق بيانًا للإذن الخاص بنوع الخدمة التي تعمل في المقدّمة mediaProjection:

<manifest ...>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
    <application ...>
        <service
            android:name=".MyMediaProjectionService"
            android:foregroundServiceType="mediaProjection"
            android:exported="false">
        </service>
    </application>
</manifest>

ابدأ خدمة عرض الوسائط من خلال مكالمة إلى startForeground().

إذا لم تحدّد نوع الخدمة التي تعمل في المقدّمة في الطلب، سيتم تلقائيًا ضبط النوع على عدد صحيح ثنائي لأنواع الخدمات التي تعمل في المقدّمة المحدّدة في البيان. إذا لم يحدِّد البيان أي أنواع خدمات، يُرسِل النظام سوى MissingForegroundServiceTypeException.

يجب أن يطلب تطبيقك موافقة المستخدم قبل كل جلسة لعرض الوسائط. الجلسة هي مكالمة واحدة إلى createVirtualDisplay(). يجب استخدام رمز MediaProjection مرّة واحدة فقط لإجراء المكالمة.

في الإصدار 14 من نظام التشغيل Android أو الإصدارات الأحدث، تُعرِض الطريقة createVirtualDisplay() خطأ SecurityException إذا كان تطبيقك ينفّذ أيًا مما يلي:

  • تمرير مثيل Intent تم إرجاعه من createScreenCaptureIntent() إلى getMediaProjection() أكثر من مرة
  • طلبات الاتصال بـ createVirtualDisplay() أكثر من مرة في MediaProjection المثيل نفسه

حجم عرض الوسائط

يمكن لميزة "عرض الوسائط" التقاط شاشة الجهاز بالكامل أو نافذة تطبيق بغض النظر عن وضع النوافذ.

الحجم الأولي

عند عرض الوسائط بملء الشاشة، يجب أن يحدّد تطبيقك حجم شاشة الجهاز. في ميزة مشاركة الشاشة داخل التطبيق، لن يتمكّن تطبيقك من تحديد حجم الشاشة التي يتم تسجيلها إلى أن يختار المستخدم منطقة التسجيل. وبالتالي، يكون الحجم الأولي لأي بث وسائط هو حجم شاشة الجهاز.

استخدِم طريقة المنصة WindowManager getMaximumWindowMetrics() لعرض عنصر WindowMetrics على شاشة الجهاز حتى إذا كان تطبيق مضيف بث الوسائط في وضع "النوافذ المتعددة"، ولا يشغل سوى جزء من الشاشة.

للتوافق مع المستوى 14 من واجهة برمجة التطبيقات أو الإصدارات الأقدم، استخدِم طريقة WindowMetricsCalculator computeMaximumWindowMetrics() من مكتبة WindowManager Jetpack.

استخدِم طريقة WindowMetrics getBounds() للحصول على عرض شاشة الجهاز وارتفاعها.

تغييرات الحجم

يمكن أن يتغيّر حجم عرض الوسائط عند تدوير الجهاز أو عندما يختار المستخدم نافذة تطبيق كمنطقة الالتقاط في ميزة "مشاركة شاشة التطبيق". قد يتم عرض محتوىprojected media بتنسيق شاشة عريضة أفقيًا إذا كان حجم المحتوى الذي تم تسجيله مختلفًا عن الحد الأقصى لمقاييس النافذة التي تم الحصول عليها عند إعدادprojected media.

لضمان محاذاة عرض الوسائط بدقة مع حجم المحتوى الذي تم التقاطه لأي منطقة تم التقاطها وعلى مستوى عمليات تدوير الجهاز، استخدِم callback onCapturedContentResize() لتغيير حجم المحتوى الذي تم التقاطه. (لمزيد من المعلومات، يُرجى الاطّلاع على قسم التخصيص التالي).

التخصيص

يمكن لتطبيقك تخصيص تجربة المستخدم في عرض الوسائط باستخدام واجهات برمجة التطبيقات التالية MediaProjection.Callback:

  • onCapturedContentVisibilityChanged(): يتيح للتطبيق المضيف (التطبيق الذي بدأ عرض الوسائط) عرض المحتوى المشترَك أو إخفائه.

    استخدِم هذا المرجع لتعديل واجهة مستخدم تطبيقك استنادًا إلى ما إذا كانت المنطقة التي تم التقاطها مرئية للمستخدم. على سبيل المثال، إذا كان تطبيقك مرئيًا للمستخدم ويعرض المحتوى الذي تم التقاطه داخل واجهة مستخدم التطبيق، وكان التطبيق الذي تم التقاطه مرئيًا للمستخدم أيضًا (كما هو موضّح من خلال أسلوب الاستدعاء هذا)، سيرى المستخدم المحتوى نفسه مرّتين. استخدِم دالة الاستدعاء لتعديل واجهة مستخدم تطبيقك من أجل إخفاء المحتوى الذي تم التقاطه وإخلاء مساحة في تنسيق تطبيقك للمحتوى الآخر.

  • onCapturedContentResize(): يتيح للتطبيق المضيف تغيير حجم Proyección de medios (عرض الوسائط) على الشاشة الافتراضية وProyección de medios (عرض الوسائط)Surface استنادًا إلى حجم منطقة الشاشة التي تم التقاطها.

    يتم تشغيله عندما يتغيّر حجم المحتوى الذي تم التقاطه، وهو نافذة تطبيق واحدة أو شاشة الجهاز بالكامل (بسبب تدوير الجهاز أو دخول التطبيق الذي تم التقاطه إلى وضع نافذة مختلف). استخدِم واجهة برمجة التطبيقات هذه لتغيير حجم كلّ من الشاشة الافتراضية والسطح لضمان تطابق نسبة العرض إلى الارتفاع مع المحتوى الذي تم تسجيله وعدم اقتصاص المحتوى.

استرداد الموارد

يجب أن يسجِّل تطبيقك طلب الاستدعاء MediaProjection onStop() للاطّلاع على المعلومات عند إيقاف جلسة عرض الوسائط وتصبح غير صالحة. عند إيقاف الجلسة، من المفترض أن يُفرِج تطبيقك عن الموارد التي يحتفظ بها، مثل الشاشة الافتراضية وسطح العرض. إذا توقّفت جلسة بث الوسائط، لن تتمكّن من إنشاء شاشة افتراضية جديدة، حتى إذا لم يسبق لتطبيقك إنشاء شاشة افتراضية لبث الوسائط هذا.

يستدعي النظام دالة الاستدعاء عند انتهاء عرض الوسائط. يمكن أن يحدث هذا الإيقاف لعدة أسباب، مثل:

  • يوقف المستخدم الجلسة باستخدام واجهة مستخدم التطبيق أو شريحة شريط حالة العروض المعروضة في النظام.
  • يتم قفل الشاشة
  • بدء جلسة عرض وسائط أخرى
  • إيقاف عملية التطبيق نهائيًا

إذا لم يسجِّل تطبيقك طلب إعادة الاتصال، سيؤدي أي طلب إلى createVirtualDisplay() IllegalStateException.

إيقاف

يفعّل نظام التشغيل Android 14 أو الإصدارات الأحدث ميزة مشاركة شاشة التطبيق تلقائيًا. توفّر كل جلسة تصويب وسائط للمستخدمين خيار مشاركة نافذة تطبيق أو الشاشة بالكامل.

يمكن لتطبيقك إيقاف مشاركة شاشة التطبيق من خلال استدعاء الأسلوب createScreenCaptureIntent(MediaProjectionConfig) مع وسيطة MediaProjectionConfig يتم إرجاعها من طلب إلى createConfigForDefaultDisplay().

إنّ استدعاء createScreenCaptureIntent(MediaProjectionConfig) مع وسيطة MediaProjectionConfig التي تم إرجاعها من استدعاء createConfigForUserChoice() هو نفسه السلوك التلقائي، أي استدعاء createScreenCaptureIntent().

التطبيقات التي يمكن تغيير حجمها

احرص دائمًا على أن تكون تطبيقات عرض الوسائط قابلة للتغيير (resizeableActivity="true"). تتيح التطبيقات القابلة للتغيير تغييرات في إعدادات الجهاز ووضع "النوافذ المتعددة" (راجِع التوافق مع وضع "النوافذ المتعددة").

إذا لم يكن بإمكانك تغيير حجم تطبيقك، يجب أن يطلب التطبيق حدود العرض من سياق النافذة ويستخدم getMaximumWindowMetrics() لاسترداد WindowMetrics الحد الأقصى لمساحة العرض المتاحة للتطبيق :

Kotlin

val windowContext = context.createWindowContext(context.display!!,
      WindowManager.LayoutParams.TYPE_APPLICATION, null)
val projectionMetrics = windowContext.getSystemService(WindowManager::class.java)
      .maximumWindowMetrics

Java

Context windowContext = context.createWindowContext(context.getDisplay(),
      WindowManager.LayoutParams.TYPE_APPLICATION, null);
WindowMetrics projectionMetrics = windowContext.getSystemService(WindowManager.class)
      .getMaximumWindowMetrics();

شريحة شريط الحالة والإيقاف التلقائي

تؤدي إساءة استخدام ميزة "إلقاء الشاشة" إلى تعريض بيانات المستخدمين الخاصة، مثل معلوماتهم المالية، لأنّ المستخدمين لا يدركون أنّه تتم مشاركة شاشة أجهزتهم.

يعرض نظام التشغيل Android 15 (المستوى 35 لواجهة برمجة التطبيقات) والإصدارات الأحدث شريحة كبيرة ومرموقة في شريط الحالة لتنبيه المستخدمين إلى أي عملية إسقاط شاشة جارية. يمكن للمستخدمين النقر على الشريحة لإيقاف مشاركة الشاشة أو بثها أو تسجيلها. بالإضافة إلى ذلك، يتوقف عرض الشاشة تلقائيًا عند قفل شاشة الجهاز.

الشكل 2. شريحة في شريط الحالة لمشاركة الشاشة وبث المحتوى وتسجيله

اختبِر توفُّر شريحة شريط حالة عرض الوسائط من خلال بدء مشاركة الشاشة أو بثها أو تسجيلها. من المفترض أن تظهر الشريحة في شريط الحالة.

لضمان أن يُطلق تطبيقك الموارد ويُحدِّث واجهة المستخدم عندما يتم إيقاف ميزة "إلقاء المحتوى على الشاشة" بسبب تفاعل المستخدم مع شريحة شريط الحالة أو عند تفعيل شاشة القفل، عليك اتّباع الخطوات التالية:

  • أنشئ مثيلًا من MediaProjection.Callback.

  • نفِّذ طريقة ردّ الاتصال onStop(). يتمّ استدعاء الطريقة عند إيقاف عرض الشاشة. عليك تحرير أي موارد يحتفظ بها تطبيقك وتعديل واجهة مستخدم التطبيق حسب الحاجة.

لاختبار طلب إعادة الاتصال، انقر على شريحة شريط الحالة أو قفل شاشة الجهاز لإيقاف إلقاء الشاشة. تأكَّد من استدعاء طريقة onStop() وأنّ تطبيقك يستجيب على النحو المطلوب.

مصادر إضافية

لمزيد من المعلومات عن عرض الوسائط، يُرجى الاطّلاع على مقالة تسجيل الفيديو والصوت وتشغيلهما.