使用系统广播监听截屏操作
从Android10.0开始,Intent.ACTION_SCREEN_CAPTURED_CHANGED不再被支持。因为Google在安卓10中引入了一个新的隐私限制,即限制应用在用户开启了屏幕录制功能或截屏功能时获取相应的广播。
- 创建一个BroadcastReceiver类来接收截屏广播:
public class ScreenCaptureReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Intent.ACTION_SCREEN_CAPTURES_CHANGED.equals(action)) {
// 截屏操作
Toast.makeText(context, "用户进行了截屏操作", Toast.LENGTH_SHORT).show();
}
}
}
- 在AndroidManifest.xml文件中声明截屏广播接收器:
<receiver
android:name=".ScreenCaptureReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.SCREEN_CAPTURE_CHANGED" />
</intent-filter>
</receiver>
- 注册截屏广播接收器,开始监听截屏操作:
ScreenCaptureReceiver receiver = new ScreenCaptureReceiver();
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_CAPTURE_CHANGED);
registerReceiver(receiver, filter);
- 在不需要监听时,取消注册截屏广播接收器:
unregisterReceiver(receiver);
使用ContentObserver监听截屏操作
通过ContentObserver观察MediaStore.Images.Media.EXTERNAL_CONTENT_URI或MediaStore.Images.Media.INTERNAL_CONTENT_URI来检测媒体文件(截屏)保存触发的变化事件。
public class ScreenCaptureObserver extends ContentObserver {
private static final String TAG = "ScreenCaptureObserver";
private static final String SCREENSHOTS_DIR = Environment.getExternalStorageDirectory().toString() + "/Pictures/Screenshots";
private Context mContext;
public ScreenCaptureObserver(Context context) {
super(null);
mContext = context;
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
Log.d(TAG, "Screen capture detected");
if (uri.toString().matches(MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString() + "/[0-9]+")) {
Cursor cursor = null;
try {
cursor = mContext.getContentResolver().query(uri, new String[]{MediaStore.Images.Media.DATA}, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
if (path != null && path.startsWith(SCREENSHOTS_PATH)) {
// 此处为用户截屏行为的响应逻辑
}
}
} finally {
if (cursor != null) {
cursor.close();
}
}
}
}
public void start() {
ContentResolver contentResolver = mContext.getContentResolver();
contentResolver.registerContentObserver(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true, this);
}
public void stop() {
ContentResolver contentResolver = mContext.getContentResolver();
contentResolver.unregisterContentObserver(this);
}
}
使用示例:
new ScreenCaptureObserver(this).start();
这种方法有几个限制和注意事项:
- 「不是所有截屏都会触发媒体扫描」:有些设备或应用可能会将截屏保存到一个不会触发媒体扫描的目录中。
- 「延迟」:媒体扫描器可能不会立即运行,因此可能会在截屏发生后的一段时间内才收到通知。
- 「可能收到非截屏图片的通知」:任何新添加到媒体数据库的图片都会触发你的ContentObserver。
两种方式对比
方式一的优点:
- 直接监听 Intent.ACTION_SCREENSHOT,无需处理 Uri 的变化。
- 适用于监听应用内的截屏操作。
方式一的缺点:
- 只能监听到整个屏幕的截屏操作,无法获取到具体的截屏内容。
- 从Android Q(10.0)开始,Intent.ACTION_SCREEN_CAPTURED_CHANGED字段不再被支持。
方式二的优点:
- 可以监听到截屏操作发生的具体 Uri,可以进一步获取截屏的文件路径和信息。
- 适用于监听系统级别的截屏操作。
方式二的缺点:
- 需要指定监听的 Uri,可能需要考虑兼容性问题。
- 需要在代码中处理 Uri 的变化,并解析截屏的文件路径。
「选型建议」根据需求,如果只关心截屏的发生与否,并不需要获取截屏的具体内容,方式一可以考虑。如果需要获取截屏内容的具体信息,方式二比较适合。如果只需要监听应用内的截屏操作,方式一比较方便。如果需要监听系统级别的截屏操作,需要使用方式二。