Detect screenshots taken in your iOS app.

Payal Kandlur
2 min readJul 14, 2024

--

Recently I came across an interesting feature where our app would notify when the user takes a screenshot.

We observe an event change, that is, whenever the user takes a screenshot we send a local notification. Here’s how we can do it.

Subscribe to the PHPhotoLibraryChangeObserver in the Photo Library.

photoLibrary.register(self)

The deinit method unregisters the instance to clean up when it's no longer needed.

deinit {
photoLibrary.unregisterChangeObserver(self)
}

The MonitorScreenshot class conforms to PHPhotoLibraryChangeObserver. photoLibraryDidChange is called when there are changes in the Photo Library.

It fetches all image assets from the Photo Library using PHFetchOptions with a predicate to filter only image media types.

The fetched results are enumerated to check if any asset is a screenshot (.photoScreenshot). If a screenshot is found, it compares its creation date with the latest known screenshot.

If it’s new, it updates latestScreenshotAsset and sends a local notification on the main thread.

If latestScreenshotAsset is nil, it means no screenshot was previously recorded, so it sets the current asset as the latest and sends a notification.

extension MonitorScreenshot: PHPhotoLibraryChangeObserver {
func photoLibraryDidChange(_ changeInstance: PHChange) {
DispatchQueue.global().async {
let fetchOptions = PHFetchOptions()
fetchOptions.predicate = NSPredicate(format: "mediaType = %d", PHAssetMediaType.image.rawValue)
let fetchResult = PHAsset.fetchAssets(with: fetchOptions)

fetchResult.enumerateObjects { asset, _, _ in
if asset.mediaSubtypes.contains(.photoScreenshot) {
if let latestAsset = self.latestScreenshotAsset,
let creationDate = asset.creationDate,
let latestCreationDate = latestAsset.creationDate,
creationDate > latestCreationDate {
self.latestScreenshotAsset = asset
DispatchQueue.main.async {
self.sendLocalNotification()
}
} else if self.latestScreenshotAsset == nil {
self.latestScreenshotAsset = asset
DispatchQueue.main.async {
self.sendLocalNotification()
}
}
}
}
}
}
}

The sendLocalNotification sends a local notification, but this happens only when the app is in the background/foreground and not in the terminated state (of course)!
Ensure that your app has the necessary permissions to send local notifications. You may need to request permission from the user.

You can check the code here.

That’s all!😊 For any questions or suggestions, drop a comment!

--

--

Responses (1)