如何检测iPhone是否被使用/解锁?含后台运行场景需求
针对你遇到的「后台检测用户是否正在使用iPhone」的需求,结合iOS的合规要求和现有API限制,我给你梳理下可行的思路和方案:
先聊聊你提到的现有方案的局限
applicationProtectedDataWillBecomeUnavailable/applicationProtectedDataDidBecomeAvailable:确实只有设备设置了锁屏密码时才会触发回调,无密码设备完全不会响应,覆盖范围有限,没法满足全场景需求。- Darwin锁屏/解锁通知:这类属于私有API范畴,Apple的审核系统会直接识别并拒绝你的App,绝对不能用于上线产品。
- 距离传感器通知(
UIDeviceProximityStateDidChangeNotification):它只能检测是否有物体靠近听筒,和“用户正在使用设备”的关联度极低,而且后台状态下系统会限制传感器的触发频率,精度完全不够。
合规可行的替代方案
方案1:利用App前后台状态通知(基础场景适配)
如果你的需求是判断用户是否切换到你的App使用,可以通过监听系统提供的App活跃/非活跃通知来实现,虽然没法检测用户解锁设备但未打开你的App的情况,但属于完全合规的基础方案。
代码示例:
// 在AppDelegate或SceneDelegate中注册通知 override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { NotificationCenter.default.addObserver(self, selector: #selector(onAppBecomeActive), name: UIApplication.didBecomeActiveNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(onAppResignActive), name: UIApplication.willResignActiveNotification, object: nil) return true } @objc private func onAppBecomeActive() { // 用户正在使用你的App,设备处于活跃状态 print("用户正在使用iPhone,当前App已激活") } @objc private func onAppResignActive() { // 用户离开你的App,设备可能锁屏或切换到其他应用 print("用户停止使用当前App,设备进入非活跃状态") }
方案2:iOS 16+ 用DeviceActivityMonitor(精准合规首选)
iOS 16之后Apple推出了DeviceActivityMonitor框架,专门用于监控设备的使用状态(包括锁屏、解锁、App使用时长等),属于官方合规API,能通过App Store审核,是目前后台检测设备活跃状态的最优解。不过需要用户授权「屏幕使用时间」权限,且需遵守后台运行限制。
实现步骤:
- 在
Info.plist中添加NSFamilyUsageDescription,说明申请屏幕使用时间权限的原因(比如“为了提供个性化的使用提醒服务”); - 实现监控逻辑:
import DeviceActivity class DeviceUsageMonitor: NSObject, DeviceActivityMonitorDelegate { private let monitor = DeviceActivityMonitor() override init() { super.init() monitor.delegate = self } func requestAuthorization() { DeviceActivityAuthorizationCenter.shared.requestAuthorization { [weak self] status in guard let self = self, status == .granted else { return } // 配置监控时间段(这里设置为全天监控) let dailySchedule = DeviceActivitySchedule( intervalStart: DateComponents(hour: 0), intervalEnd: DateComponents(hour: 23, minute: 59), repeats: true ) // 开始监控 try? self.monitor.startMonitoring(dailySchedule) } } // 设备进入活跃状态(解锁后开始使用) func monitor(_ monitor: DeviceActivityMonitor, didStartActivities activities: Set<DeviceActivityName>) { print("用户正在使用iPhone,设备已解锁并处于活跃状态") } // 设备停止活跃(锁屏或长时间未操作) func monitor(_ monitor: DeviceActivityMonitor, didStopActivities activities: Set<DeviceActivityName>) { print("用户停止使用iPhone,设备已锁屏或进入非活跃状态") } }
方案3:CoreMotion运动检测(辅助判断)
如果你的App有运动相关的场景,可以借助CMMotionManager在后台监听设备的运动状态(比如拿起设备、晃动等),间接判断用户可能正在使用设备。但这只是辅助手段,不能精准对应“正在使用”,且需要配置后台运动权限。
代码示例(核心部分):
import CoreMotion class MotionDetector: NSObject { private let motionManager = CMMotionManager() func startMonitoring() { guard motionManager.isDeviceMotionAvailable else { return } // 设置更新频率 motionManager.deviceMotionUpdateInterval = 1.0 // 后台需要配置UIBackgroundModes的motion权限 motionManager.startDeviceMotionUpdates(to: .main) { [weak self] motion, error in guard let motion = motion else { return } // 通过加速度等数据判断设备是否被拿起/操作 let acceleration = motion.userAcceleration if abs(acceleration.x) > 0.1 || abs(acceleration.y) > 0.1 || abs(acceleration.z) > 0.1 { print("设备有运动,用户可能正在使用iPhone") } } } }
最后总结
- 若需精准且合规的后台检测,iOS 16+ 优先选择
DeviceActivityMonitor; - 低版本iOS只能依赖App前后台状态通知,或结合运动检测做辅助判断;
- 绝对避免使用私有API或Darwin通知,这类方案100%无法通过App Store审核;
- 所有后台检测都必须遵守iOS隐私规则,必须向用户清晰说明权限用途,不能滥用权限。
内容的提问来源于stack exchange,提问作者devdoe




