android.media.projection
API ที่เปิดตัวใน Android 5 (API ระดับ 21) จะช่วยให้คุณบันทึกเนื้อหาได้
ของอุปกรณ์จะแสดงเป็นสตรีมสื่อที่คุณสามารถเล่น บันทึก หรือแคสต์ได้
อุปกรณ์อื่นๆ เช่น ทีวี
Android 14 (API ระดับ 34) เปิดตัวการแชร์หน้าจอแอปซึ่งช่วยให้ผู้ใช้ แชร์หน้าต่างแอปเดียวแทนการแชร์ทั้งหน้าจอของอุปกรณ์ โหมดการจัดกรอบ การแชร์หน้าจอแอปไม่รวมแถบสถานะ แถบนำทาง และองค์ประกอบ UI อื่นๆ ของระบบจากจอแสดงผลที่ใช้ร่วมกัน เมื่อใช้การแชร์หน้าจอแอปเพื่อจับภาพแอปแบบเต็มหน้าจอ ระบบจะแชร์เฉพาะเนื้อหาของแอปที่เลือกเท่านั้น
การแชร์หน้าจอแอปช่วยรับประกันความเป็นส่วนตัวของผู้ใช้ เพิ่มประสิทธิภาพการทำงานของผู้ใช้ และ เพิ่มประสิทธิภาพการทำงานหลายอย่างพร้อมกันโดยให้ผู้ใช้เรียกใช้แอปหลายรายการ แต่มีข้อจำกัด การแชร์เนื้อหาไปยังแอปเดียว
จอแสดงผล 3 แบบ
การฉายภาพสื่อบันทึกเนื้อหาของการแสดงผลของอุปกรณ์หรือหน้าต่างแอป และ
จากนั้นฉายภาพที่จับภาพไปยังจอแสดงผลเสมือนที่แสดงรูปภาพบน
Surface
![จอแสดงผลของอุปกรณ์จริงฉายอยู่บนจอแสดงผลเสมือน เนื้อหาของ
การแสดงผลเสมือนที่เขียนลงใน "Surface" ที่แอปพลิเคชันมีให้](https://developer.android.com/static/media/images/grow/media-projection.png?authuser=5&hl=th)
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
API
ใน Android 11 (API ระดับ 30) (โปรดดูรายละเอียดที่
ขนาดการฉายภาพสื่อ)
แพลตฟอร์ม
ปรับขนาดพื้นผิวการฉายภาพสื่อเพื่อสร้างเอาต์พุตใน ความละเอียดสูงสุดของคุณ ทำให้พื้นผิวมีขนาดใหญ่ (ความละเอียดต่ำ) สำหรับการแคสต์หน้าจอไปยังทีวี หรือ จอคอมพิวเตอร์และขนาดเล็ก (ความละเอียดสูง) สำหรับการบันทึกการแสดงผลของอุปกรณ์
สำหรับ Android 12L (API ระดับ 32) เมื่อแสดงผลเนื้อหาที่จับภาพไว้ใน ระบบจะปรับขนาดเนื้อหา ให้เป็นแบบเดียวกัน โดยรักษาสัดส่วนการแสดงผลไว้ เพื่อให้ขนาดของเนื้อหาทั้ง 2 ด้าน (ความกว้างและความสูง) เท่ากันหรือน้อยกว่า ขนาดที่สอดคล้องกันของพื้นผิว จากนั้นเนื้อหาที่บันทึก ให้อยู่ตรงกลางพื้นผิว
แนวทางการปรับขนาดของ Android 12L ปรับปรุงการแคสต์หน้าจอไปยังทีวีและ จอแสดงผลขนาดใหญ่อื่นๆ ด้วยการเพิ่มขนาดของรูปภาพพื้นผิวให้มากที่สุด ในขณะเดียวกันก็ตรวจสอบให้แน่ใจว่า สัดส่วนภาพที่เหมาะสม
สิทธิ์สำหรับบริการที่ทำงานอยู่เบื้องหน้า
หากแอปกำหนดเป้าหมายเป็น Android 14 ขึ้นไป ไฟล์ Manifest ของแอปต้องมี
การประกาศสิทธิ์สำหรับ
ประเภทบริการที่ทำงานอยู่เบื้องหน้า 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()
หากไม่ระบุประเภทบริการที่ทำงานอยู่เบื้องหน้าในการโทร ประเภทจะเป็นค่าเริ่มต้น
เป็นจำนวนเต็มบิตของประเภทบริการที่ทำงานอยู่เบื้องหน้าที่กำหนดไว้ในไฟล์ Manifest ถ้า
ไฟล์ Manifest ไม่ได้ระบุประเภทบริการใดๆ แต่ระบบแสดงข้อผิดพลาด
MissingForegroundServiceTypeException
ความยินยอมของผู้ใช้
แอปของคุณต้องขอความยินยอมจากผู้ใช้ก่อนเซสชันการฉายภาพสื่อแต่ละเซสชัน ต
เซสชันคือการเรียก createVirtualDisplay()
ครั้งเดียว โทเค็น MediaProjection
จะต้องใช้เพียงครั้งเดียวในการโทร
ใน Android 14 ขึ้นไป เมธอด createVirtualDisplay()
จะแสดง
SecurityException
หาก
ดำเนินการอย่างใดอย่างหนึ่งต่อไปนี้
- ส่งต่ออินสแตนซ์
Intent
ที่แสดงผลจากcreateScreenCaptureIntent()
ไปยังgetMediaProjection()
มากกว่า 1 ครั้ง - โทร
createVirtualDisplay()
มากกว่า 1 ครั้งในวันMediaProjection
เดียวกัน อินสแตนซ์
ขนาดการฉายภาพสื่อ
การฉายภาพสื่อสามารถจับภาพจอแสดงผลของอุปกรณ์ทั้งเครื่องหรือหน้าต่างแอปได้ โดยไม่คำนึงถึงโหมดกรอบเวลา
ขนาดเริ่มต้น
เมื่อใช้การฉายสื่อแบบเต็มหน้าจอ แอปต้องระบุขนาดของ หน้าจออุปกรณ์ ในการแชร์หน้าจอแอป แอปของคุณจะไม่สามารถระบุ ของภาพที่ถ่ายไว้จนกว่าผู้ใช้จะเลือกพื้นที่ในการจับภาพ ดังนั้น ขนาดเริ่มต้นของการฉายภาพสื่อใดๆ ก็คือขนาดของหน้าจออุปกรณ์
ใช้แพลตฟอร์ม WindowManager
getMaximumWindowMetrics()
เพื่อแสดง
WindowMetrics
ของออบเจ็กต์
หน้าจออุปกรณ์แม้ว่าแอปโฮสต์การฉายภาพสื่อจะอยู่ในหลายหน้าต่าง
ให้ทำงานเฉพาะในจอแสดงผล
สำหรับความเข้ากันได้จนถึงระดับ API 14 ให้ใช้ WindowMetricsCalculator
computeMaximumWindowMetrics()
จากไลบรารี Jetpack WindowManager
เรียกใช้เมธอด WindowMetrics
getBounds()
เพื่อดูความกว้างและความสูงของหน้าจออุปกรณ์
การเปลี่ยนขนาด
ขนาดของการฉายภาพสื่ออาจเปลี่ยนแปลงได้เมื่อหมุนอุปกรณ์ หรือผู้ใช้เลือกหน้าต่างแอปเป็นพื้นที่จับภาพในการแชร์หน้าจอแอป การฉายภาพสื่ออาจมีแถบดำด้านบน-ล่างของภาพหากเนื้อหาที่บันทึกเป็น ขนาดต่างจากเมตริกกรอบเวลาสูงสุดที่ได้รับเมื่อสื่อ ตั้งค่าการฉายภาพแล้ว
เพื่อให้แน่ใจว่าการฉายภาพสื่ออยู่ในแนวเดียวกับขนาดของภาพที่บันทึก
เนื้อหาสำหรับพื้นที่ที่บันทึกและในการหมุนรอบอุปกรณ์ ให้ใช้
onCapturedContentResize()
Callback เพื่อปรับขนาดการบันทึก (สำหรับข้อมูลเพิ่มเติม
โปรดดูส่วนการปรับแต่ง ซึ่งจะต่อท้าย)
การปรับแต่ง
แอปของคุณสามารถปรับแต่งประสบการณ์ของผู้ใช้การฉายภาพสื่อด้วยสิ่งต่อไปนี้
MediaProjection.Callback
API:
onCapturedContentVisibilityChanged()
: เปิดใช้แอปโฮสต์ (แอปที่เริ่มการฉายภาพสื่อ) เพื่อแสดงหรือ ซ่อนเนื้อหาที่แชร์ใช้ Callback นี้เพื่อปรับแต่ง UI ของแอปโดยพิจารณาว่า ผู้ใช้มองเห็นภูมิภาค เช่น หากแอปของคุณปรากฏแก่ และแสดงเนื้อหาที่บันทึกไว้ภายใน UI ของแอป และ แอปที่บันทึกไว้ยังแสดงต่อผู้ใช้ (ตามที่ระบุไว้ผ่าน Callback) ผู้ใช้จะเห็นเนื้อหาเดียวกัน 2 ครั้ง ใช้ Callback เพื่ออัปเดต UI ของแอปเพื่อซ่อนเนื้อหาที่บันทึก และเพิ่มพื้นที่ว่างในเลย์เอาต์ใน แอปสำหรับเนื้อหาอื่น
onCapturedContentResize()
: อนุญาตให้แอปโฮสต์เปลี่ยนขนาดของการฉายภาพสื่อบนอุปกรณ์เสมือน จอแสดงผลและฉายภาพสื่อSurface
ตามขนาดของภาพ ภูมิภาคที่แสดงทริกเกอร์ทุกครั้งที่เนื้อหาที่จับภาพไว้ เช่น หน้าต่างแอปเดียวหรือเต็ม การแสดงผลของอุปกรณ์ - เปลี่ยนขนาด (เนื่องจากการหมุนของอุปกรณ์หรือ เข้าสู่โหมดหน้าต่างอื่น) ใช้ API นี้เพื่อปรับขนาด การแสดงผลเสมือนและพื้นผิวเพื่อให้แน่ใจว่าสัดส่วนภาพตรงกับภาพที่บันทึกไว้ และเนื้อหาที่บันทึกไม่ได้เป็นแถบดำด้านบน-ล่างของภาพ
การกู้คืนทรัพยากร
แอปของคุณควรลงทะเบียน MediaProjection
onStop()
Callback เพื่อรับการแจ้งเตือนเมื่อเซสชันการฉายภาพสื่อหยุดลงและ
ไม่ถูกต้อง เมื่อเซสชันหยุดลงแล้ว แอปของคุณควรปล่อยทรัพยากรที่
เช่น จอแสดงผลและพื้นผิวการฉายภาพเสมือน A หยุด
เซสชันการฉายภาพสื่อไม่สามารถสร้างจอแสดงผลเสมือนใหม่ได้อีกต่อไป แม้ว่า
แอปของคุณไม่ได้สร้างหน้าจอเสมือนสำหรับการฉายภาพสื่อดังกล่าวไว้ก่อนหน้านี้
ระบบจะเรียก Callback เมื่อการฉายภาพสื่อสิ้นสุด เนื่องจาก ผู้ใช้หยุดเซสชันนี้ด้วยตนเอง หรือเนื่องจากระบบหยุดเซสชันของ ด้วยเหตุผลบางประการ
หากแอปไม่ลงทะเบียนการติดต่อกลับ การโทรไปยัง 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();
แหล่งข้อมูลเพิ่มเติม
สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการฉายภาพสื่อ โปรดดู บันทึกการเล่นวิดีโอและเสียง