paint-brush
如何通过不活动超时安全地将用户从 iOS 应用程序中注销经过@dekij
1,020 讀數
1,020 讀數

如何通过不活动超时安全地将用户从 iOS 应用程序中注销

经过 David Grigoryan3m2023/05/14
Read on Terminal Reader

太長; 讀書

许多应用程序都有一项功能,可以在一段时间不活动后自动将您注销。一些应用程序根据 API 不活动将您注销,而其他应用程序通过覆盖 UIView 控件来实现注销计时器。在本文中,我们将探索使用 hitTest 方法实现此行为的更好方法。
featured image - 如何通过不活动超时安全地将用户从 iOS 应用程序中注销
David Grigoryan HackerNoon profile picture
0-item
1-item

许多应用程序都有一项功能,可以在一段时间不活动后自动将您注销。但是,其中一些应用程序会根据 API 不活动将您注销,而其他应用程序则通过覆盖 UIView 控件来实现注销计时器。在本文中,我们将探索使用 hitTest 方法实现此行为的更好方法。有些应用程序会根据上次登录/API 调用与当前时间之间的时间差将您注销。最后一种方法的问题是,您可以通过手动将设备上的时间设置为登录时间点来保持会话持续运行。


第一种方法的问题是一些用户可能会被注销,即使他们只是滚动浏览内容而不向后端发出任何请求。想象一下,一个用户在打开之前阅读了某个银行产品的条款和条件,然后他被注销了。我们绝对想避免这种情况。


第二种方法的问题在于,很难在现有代码库中实现不活动注销功能,尤其是当应用程序具有包含自定义视图的大型代码库时。

这是 hitTest 方法非常有用的地方。

简答

我们可以对 hitTest 方法使用 hack 来解决列出的问题。


假设我们已经有一个负责跟踪用户活动时间的类的实现版本。


我们将使用以下 API 来表达它:

 protocol IUserActivity {  func resetInactiveTime() }


现在,让我们在我们的应用程序中声明一个 UIWindow 的扩展:

 extension UIWindow { open override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { userActivity.resetInactiveTime() return super.hitTest(point, with: event) } }

就是这样!现在,此方法将在用户在屏幕上进行的每个交互事件(例如点击、滚动和其他手势活动)上触发。


您还可以声明 UIWindow 的子类并在其中覆盖 hitTest 方法。

等等,它是如何工作的?🤔(长答案)

iOS中的触摸事件通常源自用户与设备触摸屏的交互。


当用户触摸屏幕时,硬件会检测触摸并生成原始触摸数据流,其中包括触摸的位置、压力和持续时间等信息。


这些原始触摸数据随后由操作系统处理,并转换为可由 UIKit 处理的高级触摸事件。操作系统根据触摸位置和视图层级确定触摸事件对应于哪个UIWindow对象,然后将触摸事件发送给该对象的UIResponder对象进行处理。


当触摸事件发生时,iOS 操作系统使用命中测试算法来确定触摸事件对应于哪个 UIView 或 UIWindow 对象。


命中测试算法从顶层 UIWindow 对象开始,递归检查视图层次结构中的每个子视图,直到找到包含触摸点的最深视图。它通过检查触摸点是否在每个子视图的框架内来实现。


命中测试使用深度优先反向预序遍历算法。换句话说,该算法首先访问根节点,然后从高索引到低索引遍历其子树。

命中测试遍历算法


这种遍历允许减少遍历迭代次数,并在找到包含接触点的第一个最深后代视图后停止搜索过程。


这是可能的,因为子视图总是呈现在其父视图的前面,而同级视图总是呈现在其同级视图的前面,其子视图数组的索引较低。当多个重叠视图包含特定点时,最右边子树中最深的视图将是最前面的视图(1)


如我们所见,遍历算法总是从 UIWindow 对象开始,无论用户与哪个视图或控件交互。


我们绝对可以通过在 UIWindow 类的 hitTest 方法中拦截这些事件来将其用于我们的目的!


就是这样!请在下面的评论中告诉我您的想法。