- vừa được xem lúc

Detect Screenshot trong Android

0 0 10

Người đăng: Nguyen Huu Cong

Theo Viblo Asia

Sau một thời gian tìm hiểu thì mình biết được rằng Android không cung cấp một API chính thức nào dành cho việc phát hiện người dùng có chụp ảnh màn hình hay không. Tuy nhiên vẫn có cách để giải quyết điều đó.

Bạn đã thắc mắc tại sao các ứng dụng như Snapchat và Instagram có thể phát hiện chụp ảnh màn hình ngay khi bạn chụp chưa? Trong bài viết này, chúng ta sẽ khám phá cách thực hiện điều đó.

Cách tiếp cận đơn giản là kiểm tra các ảnh trong thiết bị của người dùng xem có ảnh chụp màn hình mới được lưu vào thư mục "Screenshots" hay chưa ?.

Code thôi

Ta sẽ sử dụng một ContentObserver để quan sát bất kỳ sự thay đổi nào về hình ảnh trên máy của người dùng. Nó cần một tham số là Handler và hàm onChange sẽ được gọi khi có sự thay đổi của URI mà ta xác định.

contentObserver = object : ContentObserver(Handler(Looper.getMainLooper())) { override fun onChange(selfChange: Boolean, uri: Uri?) { super.onChange(selfChange, uri) } }

Tiếp theo, ta cần register thằng ContentObserver, hàm registerContentObserver cần 3 tham số. Đầu tiên là URI mà ContentObserver theo dõi. Tham số thứ hai notifyForDescendants ta để là true để quan sát sự thay đổi của các URI bắt đầu bằng URI mà ta đã chỉ định. Cuối cùng là thằng ContentObserver mà ta muốn register.

 context.contentResolver.registerContentObserver( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, true, contentObserver )

Khi ta đã register ContentObserver rồi thì để xem ta sẽ nhận biết việc chụp ảnh màn hình như nào nhé. Ý tưởng đơn giản là bất cứ khi nào có sự thay đổi trong các tệp media trong khi người dùng đang sử dụng app, ta sẽ nhận được URI và sau đó ta sẽ trích xuất đường dẫn của tệp từ URI đó. Ta có thể sử dụng thuộc tính DATA của API MediaStore.Images để lấy đường dẫn tệp nhưng thuộc tính đó đã deprecated trên API 29 rồi. Trong API 29, một thuộc tính mới có tên là RELATIVE_PATH đã được thay thế. Vì vậy, đối với các thiết bị có API 29 trở lên, ta có thể sử dụng RELATIVE_PATHDISPLAY_NAME để lấy đường dẫn tệp của tệp ảnh chụp màn hình và đối với các thiết bị khác, ta vẫn có thể tiếp tục sử dụng thuộc tính DATA.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { queryRelativeDataColumn(uri)
} else { queryDataColumn(uri)
}

Quan sát đoạn code dưới đây, ta đang truy vấn thuộc tính DATA bằng cách sử dụng URI đã được trả về từ ContentObserver. Nếu đường dẫn đó chứa chuỗi “screenshot” ở bất kỳ đâu, ta có thể kết luận rằng người dùng đã chụp ảnh màn hình.

 private fun queryDataColumn(uri: Uri) { val projection = arrayOf( MediaStore.Images.Media.DATA ) context.contentResolver.query( uri, projection, null, null, null )?.use { cursor -> val dataColumn = cursor.getColumnIndex(MediaStore.Images.Media.DATA) while (cursor.moveToNext()) { val path = cursor.getString(dataColumn) if (path.contains("screenshot", true)) { // do something } } } }

Tương tự, ta có thể được thực hiện cho API 29 với việc sử dụng DISPLAY_NAMERELATIVE_PATH như sau:

private fun queryRelativeDataColumn(uri: Uri) { val projection = arrayOf( MediaStore.Images.Media.DISPLAY_NAME, MediaStore.Images.Media.RELATIVE_PATH ) context.contentResolver.query( uri, projection, null, null, null )?.use { cursor -> val relativePathColumn = cursor.getColumnIndex(MediaStore.Images.Media.RELATIVE_PATH) val displayNameColumn = cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME) while (cursor.moveToNext()) { val name = cursor.getString(displayNameColumn) val relativePath = cursor.getString(relativePathColumn) if (name.contains("screenshot", true) or relativePath.contains("screenshot", true) ) { // do something } } } }

Đừng quên unregister ContentObserver khi người dùng không còn sử dụng app nữa. Ta đưa nó vào onStop.

context.contentResolver.unregisterContentObserver(contentObserver)

Vì ta đang truy cập vào các tệp media nên sẽ cần thêm permission này trong file AndroidManifest.xml

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

Từ đây, nếu bạn biết bất kỳ ứng dụng nào theo dõi ảnh chụp màn hình trong khi đang sử dụng ứng dụng đó, bạn chỉ cần thu hồi quyền này và ứng dụng sẽ không thể theo dõi khi bạn chụp ảnh màn hình nữa, mình đã thử làm điều này trong ứng dụng Instagram và họ không thể phát hiện được khi mình chụp ảnh màn hình. Nếu thử bên Snapchat, họ sẽ không cho phép bạn sử dụng ứng dụng.

Tuy nhiên, giải pháp này sẽ chỉ hoạt động đối với các thiết bị lưu trữ ảnh chụp màn hình trong thư mục "Screenshots" hoặc tên tệp có chứa chuỗi "screenshot". Một số device sẽ thay đổi cacsh lưu trữ này, nhưng dù sao nếu bạn tìm thấy một ngoại lệ như thế, bạn vẫn có thể dễ dàng kiểm tra cho thư mục đó vì ta đã có đường dẫn của tệp khi nó được trả về từ ContentObserver.

Source

https://proandroiddev.com/detect-screenshots-in-android-7bc4343ddce1

Bình luận

Bài viết tương tự

- vừa được xem lúc

Học Flutter từ cơ bản đến nâng cao. Phần 1: Làm quen cô nàng Flutter

Lời mở đầu. Gần đây, Flutter nổi lên và được Google PR như một xu thế của lập trình di động vậy.

0 0 281

- vừa được xem lúc

Học Flutter từ cơ bản đến nâng cao. Phần 3: Lột trần cô nàng Flutter, BuildContext là gì?

Lời mở đầu. Màn làm quen cô nàng FLutter ở Phần 1 đã gieo rắc vào đầu chúng ta quá nhiều điều bí ẩn về nàng Flutter.

0 0 206

- vừa được xem lúc

[Android] Hiển thị Activity trên màn hình khóa - Show Activity over lock screen

Xin chào các bạn, Hôm nay là 30 tết rồi, ngồi ngắm trời chờ đón giao thừa, trong lúc rảnh rỗi mình quyết định ngồi viết bài sau 1 thời gian vắng bóng. .

0 0 107

- vừa được xem lúc

Tìm hiểu Proguard trong Android

1. Proguard là gì . Cụ thể nó giúp ứng dụng của chúng ta:. .

0 0 100

- vừa được xem lúc

Làm ứng dụng học toán đơn giản với React Native - Phần 6

Chào các bạn một năm mới an khang thịnh vượng, dồi dào sức khỏe. Lại là mình đây Đây là link app mà các bạn đang theo dõi :3 https://play.google.com/store/apps/details?id=com.

0 0 68

- vừa được xem lúc

20 Plugin hữu ích cho Android Studio

1. CodeGlance. Plugin này sẽ nhúng một minimap vào editor cùng với thanh cuộn cũng khá là lớn. Nó sẽ giúp chúng ta xem trước bộ khung của code và cho phép điều hướng đến đoạn code mà ta mong muốn một cách nhanh chóng.

0 0 315