عرض الوسائط

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

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

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

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

يلتقط عرض الوسائط محتويات شاشة الجهاز أو نافذة التطبيق ثم عرض الصورة التي تم التقاطها على شاشة افتراضية تعرض الصورة على 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 من واجهة برمجة التطبيقات)، عند عرض المحتوى الذي تم التقاطه على يعمل النظام على قياس المحتوى بشكل موحد، مع الحفاظ على نسبة العرض إلى الارتفاع بحيث يكون كلا بُعدي المحتوى (العرض والارتفاع) متساويين أو أقل من الأبعاد المقابلة للسطح. ثم يتم تجميع المحتوى الذي تم التقاطه في منتصف السطح.

يعمل نهج توسيع نطاق الإصدار 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(). من مكتبة Jetpack WindowManager.

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

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

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

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

التخصيص

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

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

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

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

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

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

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

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

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

إيقاف

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

يمكن لتطبيقك إيقاف مشاركة شاشة التطبيق من خلال الاتصال على طريقة واحدة (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();

مصادر إضافية

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