عرض الوسائط

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

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

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

ثلاثة تمثيلات للعرض

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

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

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

العرض الحقيقي

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

استخدِم طريقة getMediaProjection() في خدمة نظام MediaProjectionManager لإنشاء مثيل MediaProjection عند بدء نشاط جديد. ابدأ النشاط باستخدام هدف من طريقة 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<Intent> 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 التي تم تقديمها في Android 11 (المستوى 30 من واجهة برمجة التطبيقات). (لمعرفة التفاصيل، يُرجى الاطّلاع على قسم حجم عرض الوسائط.)

مساحات العرض

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

بدءًا من نظام Android 12L (المستوى 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 مرة واحدة فقط لإجراء المكالمة.

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

  • تمرير نسخة من Intent تم إرجاعها من createScreenCaptureIntent() إلى getMediaProjection() أكثر من مرة
  • يتم استدعاء createVirtualDisplay() أكثر من مرة على مثيل MediaProjection نفسه

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

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

الحجم المبدئي

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

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

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

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

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

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

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

التخصيص

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

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

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

  • onCapturedContentResize(): تفعيل التطبيق المضيف لتغيير حجم عرض الوسائط على شاشة العرض الافتراضية وعرض الوسائط 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();

مراجع إضافية

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