API android.media.projection
được giới thiệu trong phiên bản Android 5 (API cấp 21) cho phép bạn chụp lại nội dung của màn hình thiết bị dưới dạng luồng nội dung đa phương tiện mà bạn có thể phát lại, quay hoặc truyền sang các thiết bị khác như TV.
Android 14 (API cấp 34) ra mắt tính năng chia sẻ màn hình ứng dụng, cho phép người dùng chia sẻ một cửa sổ ứng dụng thay vì toàn bộ màn hình thiết bị, bất kể chế độ cửa sổ. Tính năng chia sẻ màn hình ứng dụng sẽ loại trừ thanh trạng thái, thanh điều hướng, thông báo và các thành phần giao diện người dùng hệ thống khác khỏi màn hình được chia sẻ, ngay cả khi tính năng chia sẻ màn hình ứng dụng được dùng để chụp một ứng dụng ở chế độ toàn màn hình. Chỉ nội dung của ứng dụng đã chọn mới được chia sẻ.
Tính năng chia sẻ màn hình ứng dụng đảm bảo quyền riêng tư của người dùng, tăng năng suất và cải thiện khả năng làm nhiều việc cùng lúc bằng cách cho phép người dùng chạy nhiều ứng dụng nhưng chỉ cho phép chia sẻ nội dung với một ứng dụng duy nhất.
Ba cách thể hiện màn hình
Tính năng chiếu nội dung đa phương tiện sẽ chụp lại nội dung của màn hình thiết bị hoặc cửa sổ ứng dụng, sau đó chiếu hình ảnh được chụp lên màn hình ảo để kết xuất hình ảnh đó trên Surface
.
Ứng dụng này cung cấp Surface
thông qua MediaRecorder
, SurfaceTexture
hoặc ImageReader
. Các thành phần này sẽ sử dụng nội dung của màn hình được chụp và cho phép bạn quản lý hình ảnh được kết xuất trên Surface
theo thời gian thực. Bạn có thể lưu hình ảnh dưới dạng bản ghi hoặc truyền vào TV hoặc thiết bị khác.
Màn hình thực
Bắt đầu phiên chiếu nội dung đa phương tiện bằng cách lấy mã thông báo giúp ứng dụng của bạn có thể chụp lại nội dung của màn hình thiết bị hoặc cửa sổ ứng dụng. Mã thông báo này được biểu thị bằng một thực thể của lớp MediaProjection
.
Sử dụng phương thức getMediaProjection()
của dịch vụ hệ thống MediaProjectionManager
để tạo một thực thể MediaProjection
khi bạn bắt đầu một hoạt động mới. Bắt đầu hoạt động bằng một ý định từ phương thức createScreenCaptureIntent()
để chỉ định thao tác chụp màn hình:
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];
ActivityResultLauncherstartMediaProjection = registerForActivityResult( new StartActivityForResult(), result -> { if (result.getResultCode() == Activity.RESULT_OK) { mediaProjection[0] = mediaProjectionManager .getMediaProjection(result.getResultCode(), result.getData()); } } );
startMediaProjection.launch(mediaProjectionManager.createScreenCaptureIntent());
Màn hình ảo
Tâm điểm của tính năng chiếu nội dung đa phương tiện là màn hình ảo mà bạn tạo bằng cách gọi createVirtualDisplay()
cho thực thể 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);
Các tham số width
và height
chỉ định kích thước của màn hình ảo. Để lấy các giá trị cho chiều rộng và chiều cao, hãy sử dụng các API WindowMetrics
được giới thiệu trong Android 11 (API cấp 30). (Để biết thông tin chi tiết, hãy xem phần Kích thước chiếu nội dung đa phương tiện.)
Bề mặt
Định kích thước bề mặt chiếu nội dung đa phương tiện để có đầu ra ở độ phân giải thích hợp. Đặt kích thước lớn (độ phân giải thấp) để truyền màn hình sang TV hoặc màn hình máy tính và kích thước nhỏ (độ phân giải cao) để quay màn hình thiết bị.
Kể từ Android 12L (API cấp 32), khi kết xuất nội dung đã chụp trên bề mặt, hệ thống sẽ điều chỉnh tỷ lệ nội dung một cách đồng nhất, duy trì tỷ lệ khung hình, sao cho cả hai kích thước của nội dung (chiều rộng và chiều cao) bằng hoặc nhỏ hơn kích thước tương ứng của bề mặt. Sau đó, nội dung đã chụp sẽ được căn giữa trên nền tảng.
Phương pháp điều chỉnh tỷ lệ của Android 12L cải thiện tính năng truyền màn hình sang TV và các màn hình lớn khác bằng cách tối đa hoá kích thước của hình ảnh bề mặt trong khi vẫn đảm bảo tỷ lệ khung hình phù hợp.
Quyền sử dụng dịch vụ trên nền trước
Nếu ứng dụng của bạn nhắm đến Android 14 trở lên, thì tệp kê khai ứng dụng phải bao gồm nội dung khai báo quyền cho loại dịch vụ trên nền trước 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>
Bắt đầu dịch vụ chiếu nội dung đa phương tiện bằng lệnh gọi đến startForeground()
.
Nếu bạn không chỉ định loại dịch vụ trên nền trước trong lệnh gọi, thì loại này sẽ mặc định là số nguyên theo bit của các loại dịch vụ trên nền trước được xác định trong tệp kê khai. Nếu tệp kê khai không chỉ định bất kỳ loại dịch vụ nào, thì hệ thống sẽ gửi MissingForegroundServiceTypeException
.
Sự đồng ý của người dùng
Ứng dụng của bạn phải yêu cầu người dùng đồng ý trước mỗi phiên chiếu nội dung đa phương tiện. Phiên là một lệnh gọi duy nhất đến createVirtualDisplay()
. Bạn chỉ được sử dụng mã thông báo MediaProjection
một lần để thực hiện lệnh gọi.
Trên Android 14 trở lên, phương thức createVirtualDisplay()
sẽ gửi một SecurityException
nếu ứng dụng của bạn thực hiện một trong những thao tác sau:
- Truyền một thực thể
Intent
được trả về từcreateScreenCaptureIntent()
đếngetMediaProjection()
nhiều lần - Gọi
createVirtualDisplay()
nhiều lần trên cùng một thực thểMediaProjection
Kích thước chiếu nội dung nghe nhìn
Phép chiếu nội dung đa phương tiện có thể chụp toàn bộ màn hình thiết bị hoặc cửa sổ ứng dụng bất kể chế độ cửa sổ.
Kích thước ban đầu
Với tính năng chiếu nội dung đa phương tiện toàn màn hình, ứng dụng của bạn phải xác định kích thước màn hình thiết bị. Trong tính năng chia sẻ màn hình ứng dụng, ứng dụng của bạn sẽ không thể xác định kích thước của màn hình đã chụp cho đến khi người dùng chọn vùng chụp. Do đó, kích thước ban đầu của mọi phép chiếu nội dung nghe nhìn là kích thước màn hình thiết bị.
Sử dụng phương thức WindowManager
getMaximumWindowMetrics()
của nền tảng để trả về đối tượng WindowMetrics
cho màn hình thiết bị ngay cả khi ứng dụng lưu trữ phép chiếu nội dung đa phương tiện ở chế độ nhiều cửa sổ, chỉ chiếm một phần màn hình.
Để tương thích xuống đến API cấp 14, hãy sử dụng phương thức WindowMetricsCalculator
computeMaximumWindowMetrics()
từ thư viện WindowManager
của Jetpack.
Gọi phương thức WindowMetrics
getBounds()
để lấy chiều rộng và chiều cao của màn hình thiết bị.
Thay đổi kích thước
Kích thước của hình chiếu nội dung nghe nhìn có thể thay đổi khi thiết bị được xoay hoặc người dùng chọn một cửa sổ ứng dụng làm vùng chụp trong tính năng chia sẻ màn hình ứng dụng. Hình chiếu nội dung nghe nhìn có thể được tạo dạng hòm thư nếu nội dung được chụp có kích thước khác với các chỉ số cửa sổ tối đa thu được khi thiết lập hình chiếu nội dung nghe nhìn.
Để đảm bảo phép chiếu nội dung đa phương tiện khớp chính xác với kích thước của nội dung đã chụp cho bất kỳ vùng nào đã chụp và trên các chế độ xoay thiết bị, hãy sử dụng lệnh gọi lại onCapturedContentResize()
để đổi kích thước nội dung đã chụp. (Để biết thêm thông tin, hãy xem phần Tuỳ chỉnh ở phần sau).
Tuỳ chỉnh
Ứng dụng của bạn có thể tuỳ chỉnh trải nghiệm người dùng khi chiếu nội dung đa phương tiện bằng các API MediaProjection.Callback
sau:
onCapturedContentVisibilityChanged()
: Cho phép ứng dụng lưu trữ (ứng dụng đã bắt đầu chiếu nội dung đa phương tiện) hiển thị hoặc ẩn nội dung được chia sẻ.Sử dụng lệnh gọi lại này để tuỳ chỉnh giao diện người dùng của ứng dụng dựa trên việc người dùng có nhìn thấy vùng đã chụp hay không. Ví dụ: nếu người dùng nhìn thấy ứng dụng của bạn và đang hiển thị nội dung đã chụp trong giao diện người dùng của ứng dụng, đồng thời người dùng cũng nhìn thấy ứng dụng đã chụp (như được chỉ báo thông qua lệnh gọi lại này), thì người dùng sẽ thấy cùng một nội dung hai lần. Sử dụng lệnh gọi lại để cập nhật giao diện người dùng của ứng dụng nhằm ẩn nội dung đã chụp và giải phóng không gian bố cục trong ứng dụng cho nội dung khác.
onCapturedContentResize()
: Cho phép ứng dụng lưu trữ thay đổi kích thước của hình chiếu nội dung đa phương tiện trên màn hình ảo và hình chiếu nội dung đa phương tiệnSurface
dựa trên kích thước của vùng hiển thị được chụp.Được kích hoạt bất cứ khi nào nội dung được chụp (một cửa sổ ứng dụng hoặc màn hình thiết bị đầy đủ) thay đổi kích thước (do xoay thiết bị hoặc ứng dụng được chụp chuyển sang chế độ cửa sổ khác). Sử dụng API này để đổi kích thước cả màn hình ảo và bề mặt để đảm bảo tỷ lệ khung hình khớp với nội dung đã chụp và nội dung chụp không bị hòm thư.
Khôi phục tài nguyên
Ứng dụng của bạn phải đăng ký lệnh gọi lại MediaProjection
onStop()
để được thông báo khi phiên chiếu nội dung nghe nhìn bị dừng và trở nên không hợp lệ. Khi phiên bị dừng, ứng dụng của bạn sẽ giải phóng các tài nguyên mà ứng dụng đó lưu giữ, chẳng hạn như màn hình ảo và bề mặt chiếu. Phiên chiếu nội dung đa phương tiện đã dừng không thể tạo màn hình ảo mới nữa, ngay cả khi ứng dụng của bạn trước đó chưa tạo màn hình ảo cho phiên chiếu nội dung đa phương tiện đó.
Hệ thống sẽ gọi lệnh gọi lại khi quá trình chiếu nội dung nghe nhìn kết thúc. Việc chấm dứt này có thể xảy ra vì một số lý do, chẳng hạn như:
- người dùng dừng phiên bằng giao diện người dùng của ứng dụng hoặc khối thanh trạng thái chiếu nội dung đa phương tiện của hệ thống
- màn hình đang được khoá
- một phiên chiếu nội dung đa phương tiện khác bắt đầu
- quá trình của ứng dụng bị tắt
Nếu ứng dụng của bạn không đăng ký lệnh gọi lại, thì mọi lệnh gọi đến createVirtualDisplay()
sẽ gửi IllegalStateException
.
Ngừng
Android 14 trở lên bật tính năng chia sẻ màn hình ứng dụng theo mặc định. Mỗi phiên chiếu nội dung đa phương tiện cho phép người dùng chia sẻ một cửa sổ ứng dụng hoặc toàn bộ màn hình.
Ứng dụng của bạn có thể chọn không chia sẻ màn hình ứng dụng bằng cách gọi phương thức createScreenCaptureIntent(MediaProjectionConfig)
với đối số MediaProjectionConfig
được trả về từ lệnh gọi đến createConfigForDefaultDisplay()
.
Lệnh gọi đến createScreenCaptureIntent(MediaProjectionConfig)
với đối số MediaProjectionConfig
được trả về từ lệnh gọi đến createConfigForUserChoice()
giống với hành vi mặc định, tức là lệnh gọi đến createScreenCaptureIntent()
.
Ứng dụng có thể thay đổi kích thước
Luôn đảm bảo ứng dụng chiếu nội dung đa phương tiện có thể đổi kích thước (resizeableActivity="true"
). Các ứng dụng có thể đổi kích thước hỗ trợ thay đổi cấu hình thiết bị và chế độ nhiều cửa sổ (xem phần Hỗ trợ nhiều cửa sổ).
Nếu ứng dụng không thể thay đổi kích thước thì nó phải truy vấn các ranh giới hiển thị của cửa sổ và sử dụng getMaximumWindowMetrics()
để truy xuất WindowMetrics
của khu vực hiển thị tối đa có sẵn cho ứng dụng :
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();
Khối thanh trạng thái và tính năng tự động dừng
Các lỗ hổng liên quan đến tính năng chiếu màn hình làm lộ dữ liệu riêng tư của người dùng, chẳng hạn như thông tin tài chính, vì người dùng không nhận ra màn hình thiết bị của họ đang được chia sẻ.
Android 15 (API cấp 35) trở lên hiển thị một khối thanh trạng thái lớn và nổi bật để cảnh báo người dùng về mọi hoạt động chiếu màn hình đang diễn ra. Người dùng có thể nhấn vào khối này để ngừng chia sẻ, truyền hoặc ghi lại màn hình của họ. Ngoài ra, tính năng chiếu màn hình sẽ tự động dừng khi màn hình thiết bị bị khoá.
Kiểm tra xem có thể sử dụng khối thanh trạng thái chiếu nội dung đa phương tiện hay không bằng cách bắt đầu chia sẻ, truyền hoặc ghi màn hình. Khối sẽ xuất hiện trong thanh trạng thái.
Để đảm bảo ứng dụng của bạn giải phóng tài nguyên và cập nhật giao diện người dùng khi tính năng chiếu màn hình bị dừng do người dùng tương tác với khối thanh trạng thái hoặc do kích hoạt màn hình khoá, hãy làm như sau:
Tạo một thực thể của
MediaProjection.Callback
.Triển khai phương thức gọi lại
onStop()
. Phương thức này được gọi khi quá trình chiếu màn hình dừng lại. Giải phóng mọi tài nguyên mà ứng dụng của bạn đang giữ và cập nhật giao diện người dùng của ứng dụng nếu cần.
Để kiểm thử lệnh gọi lại, hãy nhấn vào khối thanh trạng thái hoặc khoá màn hình thiết bị để dừng tính năng chiếu màn hình. Xác minh rằng phương thức onStop()
được gọi và ứng dụng của bạn phản hồi như dự kiến.
Tài nguyên khác
Để biết thêm thông tin về phép chiếu nội dung đa phương tiện, vui lòng xem nội dung Quay video và phát lại âm thanh.