背景
在iOS開發(fā)的一些業(yè)務場景中,可能有一些敏感信息(如付款的二維碼等)婉支,我們不希望被隨意傳播。應用內(nèi)禁止截屏澜建,可以一定程度上磅摹,提高敏感信息被傳播的門檻(可能需要另外一臺手機拍照滋迈,并手機間傳輸)。
然而户誓,由于iOS系統(tǒng)的特殊性饼灿,常規(guī)方法無法完全禁止用戶截屏落地成系統(tǒng)圖片。目前帝美,網(wǎng)上的解決方案碍彭,主要有兩種:
- 監(jiān)聽截屏后通知(
UIApplicationUserDidTakeScreenshotNotification
),并進行提示悼潭。
- 監(jiān)聽截屏后通知(
- 讓用戶安裝禁用屏幕快照和屏幕錄制的配置文件庇忌。
前者無法禁止截屏內(nèi)容落地,后者閹割了手機功能舰褪,導致其他應用也無法截屏皆疹。二者均不能滿足需求。
其他刪除本地相冊的方案在新系統(tǒng)上不能滿足需求占拍。
本文在研究了參考資料
給出的一些建議略就,使用DRM
最終實現(xiàn)了對控件的防止截屏功能。
該方案有以下特點:
- 可以做到真正意義防止敏感內(nèi)容落地晃酒。
- 沒有用到私有api表牢,是蘋果原生支持的。
- 支持主流系統(tǒng)版本贝次。
注: 本文方案只能對敏感控件進行防截屏處理崔兴,無法做到全局任何位置防截屏(全部控件加drm,代價太大)蛔翅。
使用DRM實現(xiàn)防止截屏
蘋果系統(tǒng)是支持DRM(Digital Rights Management
敲茄,數(shù)字版權(quán)管理)的。它表現(xiàn)在山析,當你播放一個加密了的hls流時折汞,你進行截屏(用手機截屏或用Xcode截屏),該視頻控件會顯示空白盖腿。
所以,我們的思路就很清晰了损同。我們可以把一個敏感信息的控件翩腐,轉(zhuǎn)化為帶DRM加密的視頻,然后播放膏燃。此后茂卦,系統(tǒng)進行截屏時,該控件就會消失组哩,達到防止敏感內(nèi)容落地的目的等龙。
你可以在敏感信息控件后放個背景处渣,用來在截屏時敏感控件消失后,做更友好的提示蛛砰。如demo所示罐栈。
演示工程的效果如下:
如demo所示,截屏截不到真實的內(nèi)容泥畅,敏感信息會被過濾荠诬。
我們的整個流程差不多如下:
1) 根據(jù)控件內(nèi)容生成mp4文件
2) 啟動webserver
3) 本地播放帶DRM加密的hls流
其中1) 不是重點,我們將放后面講位仁。我們先驗證DRM是否真的可以做到防止截屏柑贞。假設,我們已經(jīng)把一個文本內(nèi)容轉(zhuǎn)換為mp4了(demo工程中的text.mp4)聂抢。那么钧嘶,我們首先讓這個視頻可以播放起來。
啟動webserver
我們需要把該mp4拷貝到一個目錄后琳疏,啟動webServer有决,如demo中,我們把它拷到tmp目錄下(演示用轿亮,實際可以做到mp4數(shù)據(jù)也不落地)疮薇。
[_webServer addGETHandlerForBasePath:@"/" directoryPath:dir indexFilename:nil cacheAge:3600 allowRangeRequests:YES];
[_webServer startWithPort:8989 bonjourName:nil];
然后,就可以播放該mp4流了我注。
[Self.player playURL:@"http://localhost:8989/text.mp4" inView:self.labelContainer];
播放帶hls加密的流
如果你按上面播放按咒,發(fā)現(xiàn)只是單純的展示內(nèi)容,并沒有防截屏的效果但骨。我們需要加密播放流励七。
你可能需要一些AVPlayer播放視頻的基礎,可以參考[iOS]仿微博視頻邊下邊播之封裝播放器和Playing Offline HLS with AES-128 encryption iOS奔缠。
當你理解了AVAssetResourceLoaderDelegate
了后掠抬,就可以開始了。我們讓播放器去播放一個私有協(xié)議的m3u8文件校哎。
[self.player playURL:@"jedi://text.m3u8" inView:self.labelContainer];
而當它無法解析時两波,就需要走AVAssetResourceLoaderDelegate
,我們在其中闷哆,返回寫死的text.m3u8數(shù)據(jù)腰奋。
#EXTM3U
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-VERSION:5
#EXT-X-TARGETDURATION:1
#EXT-X-KEY:METHOD=SAMPLE-AES,URI="jedi://text.key"
#EXTINF:0.067,
http://localhost:8989/text.mp4
#EXT-X-ENDLIST
m3u8中寫入了mp4的url地址,同時抱怔,也通過EXT-X-KEY
來描述當前的加密key劣坊,說明當前的流是經(jīng)過加密的。
同樣屈留,這里的key的獲取也是用的私有協(xié)議局冰,同樣需要走AVAssetResourceLoaderDelegate
测蘑。所以,最終AVAssetResourceLoaderDelegate
中的方法看起來如下:
-(BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest{
NSString *url = loadingRequest.request.URL.absoluteString;
if ([url isEqualToString:@"jedi://text.m3u8"]) {
NSData *data = [[self gen_m3u8] dataUsingEncoding:NSUTF8StringEncoding];
[loadingRequest.dataRequest respondWithData:data];
[loadingRequest finishLoading];
}
else if([url isEqualToString:@"jedi://text.key"]) {
NSMutableData *data = [NSMutableData dataWithLength:16];
[data resetBytesInRange:NSMakeRange(0, [data length])];
[loadingRequest.dataRequest respondWithData:[data copy]];
[loadingRequest finishLoading];
}
return YES;
}
這里康二,我們返回的key是16字節(jié)純0的數(shù)據(jù)碳胳,其實mp4文件并沒有加密,只是讓系統(tǒng)以為加密了赠摇,好在截屏時進行保護固逗。
如果你看到此,應該已經(jīng)基本掌握了防止截屏的大致流程了藕帜。如果效果無法達到的話烫罩,可以隨時參照demo中的示例。
編碼生成mp4
這里用AVAssetWriter
和CVPixelBuffer
即可生成mp4洽故。這里參考了https://github.com/caferrara/img-to-video.git
的代碼贝攒。
VTMP4Encoder
中包含根據(jù)view生成mp4的邏輯,這里不展開时甚,感興趣的可以查看代碼隘弊。
注:要注意,AVAssetWriter要設置shouldOptimizeForNetworkUse = YES荒适,讓它支持faststart,否則在m3u8中播放不了梨熙。
生成的mp4可以在demo中試用,或在mac端啟nginx配置m3u8測試刀诬。
封裝成SDK
TODO咽扇。 目前只大概封裝了encoder,完整的封裝陕壹,敬請期待质欲。
TODO
優(yōu)化生成mp4算法
獲取mp4也用
AVAssetResourceLoaderDelegate
實現(xiàn)
目前mp4獲取主要借助GCDWebServer,下個版本考慮去掉對GCDWebServer的依賴糠馆。添加對錄屏嘶伟、投屏時的監(jiān)聽和處理
目前可以做到防止手機截屏和通過Xcode的截屏,但沒有監(jiān)控錄屏和投屏(這種監(jiān)聽很容易實現(xiàn)又碌,待補充)九昧。
參考資料
1. Prevent screen capture in an iOS app