探秘Android應(yīng)用如何監(jiān)聽屏幕截圖操作,從系統(tǒng)廣播到ContentObserver方法
使用系統(tǒng)廣播監(jiān)聽截屏操作
從Android10.0開始,Intent.ACTION_SCREEN_CAPTURED_CHANGED不再被支持。因為Google在安卓10中引入了一個新的隱私限制,即限制應(yīng)用在用戶開啟了屏幕錄制功能或截屏功能時獲取相應(yīng)的廣播。
- 創(chuàng)建一個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>
- 注冊截屏廣播接收器,開始監(jiān)聽截屏操作:
ScreenCaptureReceiver receiver = new ScreenCaptureReceiver();
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_CAPTURE_CHANGED);
registerReceiver(receiver, filter);
- 在不需要監(jiān)聽時,取消注冊截屏廣播接收器:
unregisterReceiver(receiver);
使用ContentObserver監(jiān)聽截屏操作
通過ContentObserver觀察MediaStore.Images.Media.EXTERNAL_CONTENT_URI或MediaStore.Images.Media.INTERNAL_CONTENT_URI來檢測媒體文件(截屏)保存觸發(fā)的變化事件。
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)) {
// 此處為用戶截屏行為的響應(yīng)邏輯
}
}
} 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();
這種方法有幾個限制和注意事項:
- 「不是所有截屏都會觸發(fā)媒體掃描」:有些設(shè)備或應(yīng)用可能會將截屏保存到一個不會觸發(fā)媒體掃描的目錄中。
- 「延遲」:媒體掃描器可能不會立即運行,因此可能會在截屏發(fā)生后的一段時間內(nèi)才收到通知。
- 「可能收到非截屏圖片的通知」:任何新添加到媒體數(shù)據(jù)庫的圖片都會觸發(fā)你的ContentObserver。
兩種方式對比
方式一的優(yōu)點:
- 直接監(jiān)聽 Intent.ACTION_SCREENSHOT,無需處理 Uri 的變化。
- 適用于監(jiān)聽?wèi)?yīng)用內(nèi)的截屏操作。
方式一的缺點:
- 只能監(jiān)聽到整個屏幕的截屏操作,無法獲取到具體的截屏內(nèi)容。
- 從Android Q(10.0)開始,Intent.ACTION_SCREEN_CAPTURED_CHANGED字段不再被支持。
方式二的優(yōu)點:
- 可以監(jiān)聽到截屏操作發(fā)生的具體 Uri,可以進一步獲取截屏的文件路徑和信息。
- 適用于監(jiān)聽系統(tǒng)級別的截屏操作。
方式二的缺點:
- 需要指定監(jiān)聽的 Uri,可能需要考慮兼容性問題。
- 需要在代碼中處理 Uri 的變化,并解析截屏的文件路徑。
「選型建議」根據(jù)需求,如果只關(guān)心截屏的發(fā)生與否,并不需要獲取截屏的具體內(nèi)容,方式一可以考慮。如果需要獲取截屏內(nèi)容的具體信息,方式二比較適合。如果只需要監(jiān)聽?wèi)?yīng)用內(nèi)的截屏操作,方式一比較方便。如果需要監(jiān)聽系統(tǒng)級別的截屏操作,需要使用方式二。