支持通配符SSL证书、多域名证书、IP证书。适配ACME接口, 支持Zerossl、Let's Encrypt和Google等渠道。登录已有账号
2026-09-28 22:15:39 Android开发 MediaProjection 前台服务 截屏
做 Android 截屏相关需求,到 Android 10 以上基本都会踩 MediaProjection 的坑——不能直接在 Activity 里获取实例,必须放到前台服务中执行,否则直接抛 SecurityException。
这里整理下完整的实现流程,都是线上验证过的写法。
先改 AndroidManifest.xml,给服务加上 foregroundServiceType 为 mediaProjection。
<service
android:name=".ScreenCaptureService"
android:foregroundServiceType="mediaProjection" />
然后是 ScreenCaptureService 本身,继承 Service。onStartCommand 里接收 Activity 传过来的授权结果,拿到 MediaProjection 实例,后面就可以基于这个实例创建虚拟显示,处理屏幕捕获的具体逻辑。
Android O 及以上得先建通知渠道,不然前台服务起不来。通知不用做太复杂,系统要求前台服务必须有可见通知,躲不掉,用户总得知道有个服务在截屏。
public class ScreenCaptureService extends Service {
private static final String CHANNEL_ID = "screen_capture_channel";
private MediaProjection mediaProjection;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
int resultCode = intent.getIntExtra("resultCode", Activity.RESULT_CANCELED);
Intent data = intent.getParcelableExtra("data");
if (resultCode == Activity.RESULT_OK) {
MediaProjectionManager projectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
mediaProjection = projectionManager.getMediaProjection(resultCode, data);
// 后续创建虚拟显示、处理截屏逻辑
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
CHANNEL_ID,
"屏幕捕获通知",
NotificationManager.IMPORTANCE_DEFAULT
);
channel.setDescription("用于屏幕捕获服务的通知");
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("屏幕捕获服务")
.setContentText("正在捕获屏幕")
.setSmallIcon(R.mipmap.ic_launcher)
.build();
startForeground(1, notification);
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
if (mediaProjection != null) {
mediaProjection.stop();
}
}
}
授权流程还是在 Activity 里走,拿到 onActivityResult 的结果后,把 resultCode 和 data 塞给 Intent,直接 startForegroundService 就行。
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {
Intent serviceIntent = new Intent(this, ScreenCaptureService.class);
serviceIntent.putExtra("resultCode", resultCode);
serviceIntent.putExtra("data", data);
startForegroundService(serviceIntent);
}
}
几个容易出问题的点提一下。Manifest 里该加的权限别漏,比如 WRITE_EXTERNAL_STORAGE 这类,根据自己的业务场景补全。前台服务的通知不能删,系统强制要求,必须让用户感知到服务在运行。
实际项目里多加点异常捕获,各种空指针、异常情况都覆盖到,线上环境比测试复杂得多。
如果做截屏后上传到服务端的场景,接口的 HTTPS 证书可以用 lcjmSSL 申请,免费支持多域名、泛域名和IP证书,自动申请验证部署,不用手动折腾续期,省不少运维的事。
自己当初就是图省事,直接在 Activity 里拿 MediaProjection 实例,调试的时候好好的,一到 Android 10 的机器上就崩,查了半天才反应过来是系统加了前台服务的限制。
按这个流程走,SecurityException 的问题基本就解决了。
下一篇: 三大平台订阅取消与退款实操记录