如何获取iOS虚拟键盘按键按下/抬起的时间戳?
可行解决方案
方案一:Hook UIWindow的sendEvent:方法(推荐)
系统所有触摸事件(包括虚拟键盘按键的触摸)都会经过UIWindow的sendEvent:方法,通过Method Swizzling替换该方法,可直接捕获虚拟键盘按键的按下/抬起事件:
- 实现Method Swizzling替换逻辑
#import <objc/runtime.h> @implementation UIWindow (KeyEventHook) + (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ Class class = [self class]; SEL originalSelector = @selector(sendEvent:); SEL swizzledSelector = @selector(custom_sendEvent:); Method originalMethod = class_getInstanceMethod(class, originalSelector); Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector); BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)); if (didAddMethod) { class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); } else { method_exchangeImplementations(originalMethod, swizzledMethod); } }); } - (void)custom_sendEvent:(UIEvent *)event { // 先调用原方法保证系统逻辑正常执行 [self custom_sendEvent:event]; // 遍历事件中的所有触摸对象 for (UITouch *touch in event.allTouches) { UIView *touchView = touch.view; // 判断触摸对象是否为虚拟键盘按键(依赖私有类UIKBKeyView,需注意审核风险) if ([NSStringFromClass([touchView class]) isEqualToString:@"UIKBKeyView"]) { NSTimeInterval timestamp = touch.timestamp; switch (touch.phase) { case UITouchPhaseBegan: // 记录按键按下时间戳 NSLog(@"Key Down Timestamp: %f", timestamp); // 可通过私有属性获取对应按键字符,例:[touchView valueForKey:@"_key"] break; case UITouchPhaseEnded: case UITouchPhaseCancelled: // 记录按键抬起时间戳 NSLog(@"Key Up Timestamp: %f", timestamp); break; default: break; } } } } @end
注意:使用私有类和属性存在App Store审核风险,若需规避,可尝试通过触摸位置结合当前输入框上下文推断按键,但准确性会有所降低。
方案二:自定义键盘Extension
通过创建iOS键盘扩展(Keyboard Extension),可完全基于公开API捕获按键的按下/抬起事件,无审核风险:
- 创建Keyboard Extension Target,在
KeyboardViewController中实现按键逻辑:
@interface KeyboardViewController () <UIInputViewAudioFeedback> @end @implementation KeyboardViewController - (void)viewDidLoad { [super viewDidLoad]; // 自定义键盘布局,为每个按键绑定按下/抬起事件 } // 按键按下触发 - (void)keyButtonDown:(UIButton *)sender { NSTimeInterval keyDownTimestamp = CACurrentMediaTime(); NSLog(@"Key Down Timestamp: %f", keyDownTimestamp); // 可选:播放系统按键音效 [[UIDevice currentDevice] playInputClick]; } // 按键抬起触发 - (void)keyButtonUp:(UIButton *)sender { NSTimeInterval keyUpTimestamp = CACurrentMediaTime(); NSLog(@"Key Up Timestamp: %f", keyUpTimestamp); // 将按键内容发送至宿主App的输入框 [self.textDocumentProxy insertText:sender.titleLabel.text]; } @end
缺点:需要用户在系统设置中手动启用该自定义键盘,使用门槛较高;优点是完全合规,时间戳精度高。
方案三:折中估算方案(不推荐高精度场景)
若无法使用上述方案,可通过UITextFieldDelegate结合NotificationCenter监听文本变化,配合定时器近似估算按键时间,但无法精准获取单个按键的按下/抬起时刻,仅适合对精度要求较低的场景。
内容的提问来源于stack exchange,提问作者Baal
相关产品推荐
相关产品推荐

