使用iOS11的Extension進行屏幕錄制時,當(dāng)我們鎖屏?xí)r,extension進程會停止工作,那么錄制也自然停止了,但是此時我們需要給用戶一個提醒,告知用戶錄制已經(jīng)結(jié)束,所以開始了對鎖屏的探索。主要從以下幾方面考慮:
是否有系統(tǒng)通知,可以監(jiān)聽到?
是否可以通過屏幕亮度變化監(jiān)聽到?
后臺期間截屏?
UIScreen類屬性?
是否可以通過文件處理權(quán)限導(dǎo)致的讀寫限制判斷?
- 通知
通過darwin通知監(jiān)聽"com.apple.springboard.lockstate"事件,可以在手機鎖屏?xí)r,收到系統(tǒng)通知。 但是問題是,這種方法將會在提交appstore審核時被拒。
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(),
NULL, screenLockStateChanged,
CFSTR("com.apple.springboard.lockstate"),
NULL,
CFNotificationSuspensionBehaviorDeliverImmediately);
亮度
鎖屏最直觀的現(xiàn)象就是屏幕將立刻變黑,我們可以通過獲取屏幕的亮度變化,來判斷是否已經(jīng)鎖屏,但問題是會有一種異常情況:當(dāng)屏幕達(dá)到設(shè)置的鎖屏?xí)r間,如常亮了一分鐘,沒有任何操作,手機會進入黑屏,但不鎖屏狀態(tài)。這種情況無法與正常的鎖屏情況區(qū)分。考慮app在后臺期間截屏,然后判斷image.size,但是首先截屏是獲取到GPU渲染時緩存中的內(nèi)容,需要在主線程才能操作;
另外了考慮UIScreen這個類,因為[UIScreen mainScreen].bounds可以獲取到當(dāng)前主屏幕的尺寸,官方這樣說的:
Prior to iOS 8, a screen’s bounds rectangle always reflected the screen dimensions relative to a portrait-up orientation. Rotating the device to a landscape or upside-down orientation did not change the bounds. In iOS 8 and later, a screen’s bounds property takes the interface orientation of the screen into account. This behavior means that the bounds for a device in a portrait orientation may not be the same as the bounds for the device in a landscape orientation.
遺憾的是當(dāng)app到后臺時,這里的尺寸并未更新,返回的結(jié)果仍然是上一次app在前臺時的值。
- 文件權(quán)限
記得之前對DDLog的解析文章 中,我們分析過文件創(chuàng)建時,可以設(shè)置操作權(quán)限,分為以下幾種:
//文件未受保護,隨時可以訪問 (Default)
NSFileProtectionNone
//文件受到保護,而且只有在設(shè)備未被鎖定時才可訪問
NSFileProtectionComplete
//文件收到保護,直到設(shè)備啟動且用戶第一次輸入密碼
NSFileProtectionCompleteUntilFirstUserAuthentication
//文件受到保護,而且只有在設(shè)備未被鎖定時才可打開,不過即便在設(shè)備被鎖定時,已經(jīng)打開的文件還是可以繼續(xù)使用和寫入
NSFileProtectionCompleteUnlessOpen
既然這樣,我們可以利用文件的這個特性,在app進入前臺時,創(chuàng)建一個文件,使用NSFileProtectionComplete權(quán)限設(shè)置這個文件,
NSString *documentsPath =[self getDocumentsPath];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *iOSPath = [documentsPath stringByAppendingPathComponent:@"iOS4.txt"];
NSDictionary *attributes = [NSDictionary dictionaryWithObject:NSFileProtectionComplete
forKey:NSFileProtectionKey];
BOOL isSuccess = [fileManager createFileAtPath:iOSPath contents:nil attributes:attributes];
if (isSuccess)
{
NSLog(@"success");
}
else
{
NSLog(@"fail");
}
當(dāng)app進入后臺時,我們來對文件進行讀寫,如果報錯或者讀寫失敗,則說明此時處于鎖屏,如果讀寫成功,說明此時只是到后臺并未鎖屏。
但是,遺憾的是,當(dāng)鎖屏?xí)r,我們對文件讀寫并未如預(yù)料那樣失敗,而是成功了?。?在分析可能出錯的地方時 ,我首先考慮是不是鎖屏之后權(quán)限還沒有立即生效? 是否有相關(guān)回調(diào)表示已經(jīng)生效?
果然,搜索一番,發(fā)現(xiàn),果然存在一個這樣的回調(diào)。
- (void)applicationProtectedDataWillBecomeUnavailable:(UIApplication *)application
{
}
- (void)applicationProtectedDataDidBecomeAvailable:(UIApplication *)application
{
}
經(jīng)驗證,在我們不創(chuàng)建具有NSFileProtectionComplete權(quán)限的文件情況下,沒有任何創(chuàng)建、讀寫操作情況,系統(tǒng)也會有這兩個回調(diào)。所以總結(jié)下:
判斷鎖屏狀態(tài),我們直接在appdelegate文件中覆寫這兩個方法,并在方法中發(fā)出相關(guān)通知即可。