需求: 防截圖,安卓可以通過系統級的禁止截圖來實現囱晴,但是iOS并不允許開發(fā)者這么做澳泵,另外实愚,這個功能本身就是一個雞肋,別人完全可以通過用別的手機拍照的形式獲取屏幕信息烹俗,更多是一種警告意味爆侣,本文實現的防截圖功能,依賴于Photos框架的performChanges方法幢妄,實現了 當用戶截圖時兔仰,提示用戶刪除,且必須刪除蕉鸳,可以多張圖片進行監(jiān)聽并刪除
- 首先是權限問題乎赴,該功能需要相冊使用權限,且必須提前進行申請潮尝,否則榕吼,第一張圖片無法獲取并刪除。
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
switch (status) {
case PHAuthorizationStatusNotDetermined:
// User has not yet made a choice with regards to this application
break;
case PHAuthorizationStatusRestricted:// This application is not authorized to access photo data.
// The user cannot change this application’s status, possibly due to active restrictions
// such as parental controls being in place.
case PHAuthorizationStatusDenied: // User has explicitly denied this application access to photos data.
{
UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"權限異常" message:@"使用此APP需要相冊使用權限,請前往設置-移動C3開啟權限" preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"確定" style:(UIAlertActionStyleDefault) handler:^(UIAlertAction * _Nonnull action) {
abort(); //強制退出
}]];
dispatch_async(dispatch_get_main_queue(), ^{
[UIApplication.sharedApplication.keyWindow.rootViewController presentViewController:alert animated:true completion:nil];
});
}
break;
case PHAuthorizationStatusAuthorized:
break;
default:
break;
}
}];
- 初始化了一些屬性來配合整個業(yè)務流轉的順序的控制
@property(nonatomic, strong)NSOperationQueue * snapshotQueue;
@property(nonatomic, assign)NSInteger snapshotCount;
@property(nonatomic, retain)dispatch_semaphore_t semaphore;
self.snapshotCount = 0;
//當做串行的queue使用
self.snapshotQueue = [[NSOperationQueue alloc]init];
self.snapshotQueue.maxConcurrentOperationCount = 1;
self.semaphore = dispatch_semaphore_create(0);
- 對系統的截屏時間進行監(jiān)聽,這里沒啥好說的
[[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(receiveScreenShotNotification:) name:UIApplicationUserDidTakeScreenshotNotification object:nil];
- 收到截屏事件后勉失,維護一個本地的統計數字
- (void)receiveScreenShotNotification:(NSNotification *)notify {
self.snapshotCount++;
}
- 統計數字改變后羹蚣,根據統計數字狀態(tài),來決定是否需要激活刪除的事件
- (void)setSnapshotCount:(NSInteger)snapshotCount {
BOOL needDelete = _snapshotCount < snapshotCount;
_snapshotCount = snapshotCount;
NSLog(@"setSnapshotCount changed: %ld",needDelete);
if (needDelete) {
[self deleteCounted];
}
}
- 激活刪除圖片, 這里乱凿,貼了兩個方法顽素,是因為,系統拍照需要處理事時間徒蟆,當我們收到拍照事件時胁出,系統相冊可能還沒有處理完成,此時獲取到的最后一張圖片是錯誤的段审,因此全蝶,我們需要盡可能的延遲代碼調用順序,這里通過彈窗來做延遲,也可以直接寫延遲執(zhí)行抑淫,但是時間不是很穩(wěn)定绷落,測試發(fā)現300毫秒可以稍微穩(wěn)定一點,1s更好始苇,但是流程上面就有了延遲嘱函。
-(void)deleteCounted {
[self.snapshotQueue cancelAllOperations];
[self.snapshotQueue addOperationWithBlock:^{
if (self.snapshotCount == 0) { //如果count==0,那么不用再刪除了
return ;
}
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"警告" message:@"我們的APP禁止截屏,請自覺刪除!" preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[self deleteAssets];
}]];
[UIApplication.sharedApplication.keyWindow.rootViewController presentViewController:alert animated:true completion:^{
}];
});
dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER);
}];
}
-(void)deleteAssets {
PHFetchOptions *options = [[PHFetchOptions alloc] init];
options.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:NO]];
PHFetchResult *assetsFetchResults = [PHAsset fetchAssetsWithOptions:options];
NSMutableArray <PHAsset *>* assets = [NSMutableArray arrayWithCapacity:self.snapshotCount];
if (self.snapshotCount >= 0) {
for (int i = 0; i < self.snapshotCount; i ++) {
PHAsset *asset = [assetsFetchResults objectAtIndex:i];
[assets addObject:asset];
}
}
__weak typeof(self) weakSelf = self;
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetChangeRequest deleteAssets:assets];
} completionHandler:^(BOOL success, NSError * _Nullable error) {
if (!success) {
[weakSelf deleteNewAssets:assets];
} else {
self.snapshotCount -= assets.count;
dispatch_semaphore_signal(self.semaphore);
}
}];
}
- 因為刪除事件是系統功能,因此存在用戶手動取消的情況埂蕊,這里采用在取消時,繼續(xù)彈出刪除來解決
- (void)deleteNewAssets:(NSArray<PHAsset *> *)assets {
if (assets) {//增加一層判斷疏唾,安全第一
__weak typeof(self) weakSelf = self;
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
[PHAssetChangeRequest deleteAssets:assets];
} completionHandler:^(BOOL success, NSError * _Nullable error) {
if (!success) {
[weakSelf deleteNewAssets:assets];
} else {
self.snapshotCount -= assets.count;
dispatch_semaphore_signal(self.semaphore);
}
}];
}
}