iOS手勢密碼實現機制

基于手勢密碼的安全性與交互性比較好,一直以來都是手機APP的標配。在接手公司項目的時候,項目已經實現了手勢密碼。但是集成在項目中的手勢密碼功能一直沒有達到老大要求和手Q一致的需求。在研究了手Q的彈出機制之后,我發現主要的差距是在app進入后臺再次點擊圖標進入程序:手勢密碼界面會滯后?(即手勢密碼彈出是在主界面出現之后再彈出)

我查看了代碼實現是寫一個基礎ViewController,在viewDidAppear監聽手勢密碼監聽事件,代碼示例如下:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(verifyGesturePwd) name:@"VerifyGesturePwd" object:nil];

我們姑且不論代碼的書寫,此代碼在不繼承這個基礎view controller的情況下,手勢密碼是彈不出的。并且實現不了直接彈出手勢密碼的要求。

中間我嘗試在這個基礎上做修改,即把監聽代碼放到viewWillAppear中,結果你肯定也猜到了,沒有用,因為這還是在界面生成之后彈出的。那怎么解決這個需求呢?我陷入了這個死胡同。難道這個問題就解決不了了嗎?答案肯定是可以解決,因為人家已經實現了這個功能。

最近剛好看到訂閱專欄里面一篇關于“萬能鑰匙”的文章,文章的主題就是不要盯著鎖頭找鑰匙,要到其他地方找鑰匙。很顯然我就是陷入了盯著問題找答案的死胡同,此時我豁然開朗。找到解題的關鍵:答案在別處。我應該在程序入口的地方來完成項目需求。下面給出我的實現。

1、在每次程序啟動時,在didFinishLaunchingWithOptions方法中判斷是否設置手勢密碼,如果有手勢密碼功能的話,直接把手勢密碼界面設置為rootViewController,沒有的話就判斷是否登錄賬號,登錄就設置MainViewController為rootViewController,否則就設置登錄界面為rootViewController。并注冊一個登錄的監聽。

if ([DBUtil objectForKey:kDB_GestureValid]) {

VertifyGesViewController *controller = [VertifyGesViewController new];

UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:controller];

self.window.rootViewController = nav;

}

else{

[self loginStateChange:nil];

[[NSNotificationCenter defaultCenter] addObserver:self

selector:@selector(loginStateChange:)

name:KNOTIFICATION_LOGINCHANGE

object:nil];

其中loginStateChange的處理邏輯如下:

- (void)loginStateChange:(NSNotification *)notification{

if (notification == nil) {

[self userLogined];

}else{

BOOL loginSuccess = [notification.object boolValue];

if (loginSuccess) {

[self userLogined];

}

else{

[self userLoginOut];

}

}

}

- (void)userLogined{

self.window.rootViewController = [MainViewController new];

}

- (void)userLoginOut{

self.window.rootViewController = [[UINavigationController alloc]initWithRootViewController:[LoginViewController new]];

}

2、 為了處理方便,我在手勢密碼驗證后把邏輯放到登錄狀態監聽里面。即在驗證后判斷如果當前手勢界面是設置的rootViewController時,發出通知。監聽處需要重新設置rootViewController。

if (self.navigationController) {

[[NSNotificationCenter defaultCenter] postNotificationName:KNOTIFICATION_LOGINCHANGE object:@YES];

}else{

[self dismissViewControllerAnimated:YES completion:^{}];

}

3、在程序進入后臺時,如果手勢密碼已設置,彈出手勢密碼即可。

if ([DBUtil boolForKey:kDB_GestureValid]) { //手勢密碼有效

[self.window.rootViewController presentViewController:[VertifyGesViewController new] animated:NO completion:nil];

}

4、在測試的時候發現有個小bug,即在殺死程序再次進入應用時,直接進入后臺發現手勢密碼界面有2個。此處只需要添加如下代碼邏輯來解決重復彈出的問題。

UIViewController *rootViewController = [[[UIApplication sharedApplication] delegate] window].rootViewController;

if ([rootViewController isKindOfClass:[UINavigationController class]]) {

return;

}

行文至此,這個功能需求被實現了出來。說一下自己的一點小感悟:1、很多你覺得不可能完成的任務,其實是你還沒有找到解決方法。2、不要盯著鎖頭找鑰匙,鑰匙一定在其他地方。

今天抽時間把手勢密碼抽離出來,https://github.com/hohua88/Gesture,歡迎交流。

#未完再續

上述實現在當前頁面有Alert或者鍵盤時,彈出的驗證手勢密碼界面會出現遮擋(既Alert或者鍵盤)。這是由于Alert/鍵盤是展示在UIWindow上的,會顯示在手勢密碼界面的上面。

有興趣的可以去Window官方文檔,這里就不展開描述了。這里為了解決遮擋問題,可以通過設置UIWindowLevel為UIWindowLevelAlert來做到手勢密碼顯示在最上層。

- (void)show {

????????self.windowLevel = UIWindowLevelAlert;

????????[self makeKeyWindow];

????????self.hidden = NO;

}

這樣做的話,想要再彈出Alert提示框就需要自己自定義添加到window上。想嘗試的可以自己實現一下。

參考鏈接:UIWindow 詳解及使用場景

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 1.自定義控件 a.繼承某個控件 b.重寫initWithFrame方法可以設置一些它的屬性 c.在layouts...
    圍繞的城閱讀 3,444評論 2 4
  • *7月8日上午 N:Block :跟一個函數塊差不多,會對里面所有的內容的引用計數+1,想要解決就用__block...
    炙冰閱讀 2,515評論 1 14
  • 2017-10-26 藍天白云白雪公主 2017-10-26 12:02 · 字數 664 · 閱讀 0 · 日記...
    藍天白云白雪公主閱讀 239評論 0 0
  • 最近,情緒上有一些波動,不知道是不是經歷過希望、失望、絕望的人都會回過頭來反思自己所經歷的一切,然后有所感悟的記錄...
    何慶華閱讀 471評論 0 1
  • 相逢在陌生時 多少光陰 相識 相認 相知 分別在熟悉后 時常回憶 曾經的點點滴滴 腦海里 一串串美好的回憶 朋友 ...
    墨客沐陽閱讀 150評論 0 1