APP从后台模式进入前台后打开指定页面
需求:前段时间在开发项目的时候,有一个需求,因为APP的一些信息比较敏感,所以如果用户在操作APP的过程中按下home键退到后台,超过指定的时间然后再切换到前台时,需要验证用户设置过的指纹或者是手势来对用户进行身份验证
方案一:
当APP进入前台的时候将
rootViewController
设置为指定的校验界面.
但是有一个问题:当用户验证成功之后呢? 如何回到用户之前操作过的界面呢? 暂时我没有好的解决方案, 如果你想到了好的idea,咱们可以一起探讨下~
方案二:
当APP进入前台的时候在当前界面上覆盖一个
UIWindow
,并设置UIWindowLevel
,当用户验证成功之后在将该Window
对象隐藏或者是移除即可
代码如下:
func applicationDidEnterBackground(_ application: UIApplication) {
leaveTime = Date()
}
func applicationWillEnterForeground(_ application: UIApplication) {
let interval = Int(Date().timeIntervalSince(leaveTime))
//这里假如超过20秒后就让用户去验证
if interval > 20
{
let validateVC = ValidationVC()
//当用户验证成功之后重新设置下windowLevel即可;
validateVC.closeCallBack = {
self.gestureWindow?.windowLevel = -1
}
let window = UIWindow(frame: UIScreen.main.bounds)
window.windowLevel = UIWindowLevelAlert + 1
window.rootViewController = validateVC
window.makeKeyAndVisible()
self.gestureWindow = window
}
}
UIWindowLevel
关于 UIWindowLevel
我想多说几句, UIWindow
在显示的时候会根据 UIWindowLevel
进行排序的,即 Level
高的将排在最前面.默认是 0
open var windowLevel: UIWindowLevel // default = 0.0
系统为我们定义了三个window
层级,即:
public let UIWindowLevelNormal: UIWindowLevel
public let UIWindowLevelAlert: UIWindowLevel
public let UIWindowLevelStatusBar: UIWindowLevel
我们打印输出这三个level的值查看下:
STWLog("UIWindowLevelNormal: \(UIWindowLevelNormal)")
STWLog("UIWindowLevelStatusBar: \(UIWindowLevelStatusBar)")
STWLog("UIWindowLevelAlert: \(UIWindowLevelAlert)")
打印结果:
AppDelegate.swift:(43)----------UIWindowLevelNormal: 0.0
AppDelegate.swift:(44)----------UIWindowLevelStatusBar: 1000.0
AppDelegate.swift:(45)----------UIWindowLevelAlert: 2000.0
所以对于他们的级别我们也就一目了然了;
下面我们写个小Demo测试一下:
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var normalWindow: UIWindow!
var alertLevelWindow: UIWindow!
var statusLevelWindow: UIWindow!
var alertLevelWindow2: UIWindow!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
window?.tag = 10
window?.backgroundColor = .red
window?.rootViewController = ViewController()
window?.makeKeyAndVisible()
//自定义Window,设置windowLevel为UIWindowLevelNormal
normalWindow = UIWindow(frame: CGRect(x: 50, y: 50, width: 100, height: 100))
normalWindow?.tag = 100
normalWindow.backgroundColor = .green
normalWindow.windowLevel = UIWindowLevelNormal
normalWindow.rootViewController = ViewController()
normalWindow.makeKeyAndVisible()
//自定义Window,设置windowLevel为UIWindowLevelNormal
alertLevelWindow = UIWindow(frame: CGRect(x: 150, y: 150, width: 100, height: 100))
alertLevelWindow?.tag = 10000
alertLevelWindow.backgroundColor = .blue
alertLevelWindow.windowLevel = UIWindowLevelAlert
alertLevelWindow.rootViewController = ViewController()
alertLevelWindow.makeKeyAndVisible()
//自定义Window,设置windowLevel为UIWindowLevelStatusBar
statusLevelWindow = UIWindow(frame: CGRect(x: 100, y: 100, width: 100, height: 100))
statusLevelWindow?.tag = 1000
statusLevelWindow.backgroundColor = .yellow
statusLevelWindow.windowLevel = UIWindowLevelStatusBar
statusLevelWindow.rootViewController = ViewController()
statusLevelWindow.makeKeyAndVisible()
//自定义Window,设置windowLevel为UIWindowLevelStatusBar
alertLevelWindow2 = UIWindow(frame: CGRect(x: 200, y: 200, width: 100, height: 100))
alertLevelWindow2?.tag = 100000
alertLevelWindow2.backgroundColor = .white
alertLevelWindow2.windowLevel = UIWindowLevelAlert + 10 //随意设置一个Level
alertLevelWindow2.rootViewController = ViewController()
alertLevelWindow2.makeKeyAndVisible()
print("当前keyWindow: \(String(describing: UIApplication.shared.keyWindow!.tag))")
return true
}
func applicationWillEnterForeground(_ application: UIApplication) {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 2.0, execute: {
self.alertLevelWindow2 = nil
})
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 4.0, execute: {
print("此时keyWindow: \(String(describing: UIApplication.shared.keyWindow!.tag))")
for window in UIApplication.shared.windows
{
print("当前window的tag值为:\(window.tag)")
}
})
}
}
运行结果如下图所示:
打印结果显示:
当前keyWindow: 100000
此时keyWindow: 10000
当前window的tag值为:0
当前window的tag值为:10
当前window的tag值为:100
当前window的tag值为:1000
当前window的tag值为:10000
什么是 keWindow
? 我们来查看下官方文档是怎么描述的:
也就是说在 windows
数组中,最近时间调用了 makeKeyAndVisible
方法的就是 keyWindow
了;
总结:
UIWindowLevel
的值不仅仅只有UIWindowLevelNormal
、UIWindowLevelAlert
、UIWindowLevelStatusBar
这三个,可以是自定义的随意值,哪怕是负数UIWindow
的显示的确可以通过UIWindowLevel
来区分优先级,所有的window都会被加在界面上,只不过会通过优先级罗列起来,UIWindowLevel
大的在上面显示,UIWindowLevel
小的在下面显示。UIWindowLevel
优先级相等的情况下,看谁后实例化了,谁后实例化谁先显示- 如果将当前
KeyWindow
对象设置为nil
则该对象会从Windows
数组中移除,并且最后实例化的Window对象将成为KeyWindow
,但是依然遵循总结2中的描述,UIWindowLevel
大的在上面显示,UIWindowLevel
小的在下面显示。
参考:
http://www.jianshu.com/p/f60471a7d935