You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS后台模式下基于Screen Time API实现定时应用锁定方案咨询

iOS Screen Time倒计时自动激活应用限制解决方案

问题背景

我开发了一款Flutter应用,通过iOS的Screen Time API实现选定应用锁定功能,该应用已在Family Control中注册,目前在模拟器和TestFlight测试设备上均可成功执行应用限制。我计划添加倒计时功能,使应用限制在倒计时结束时自动激活,但遇到的问题是:iOS系统中应用进入后台模式后,包括倒计时在内的所有进程都会停止,导致限制功能无法生效。我已尝试以下几种机制:

  • DeviceActivityMonitor扩展:已设置调度但未触发
  • Cron:进入后台后停止运行
  • 本地通知(闹钟):仅在用户与通知交互时触发,无法在后台自动执行函数

核心解决方案:正确配置并使用DeviceActivityMonitor扩展

DeviceActivityMonitor是Apple官方为Screen Time功能设计的后台触发机制,专门用于在指定时间执行应用限制操作,不受App后台挂起影响。之前未触发的问题大概率是配置或代码逻辑错误,以下是修正步骤:

1. 创建并配置DeviceActivityMonitor扩展

  • 在Xcode项目中添加新Target,选择Device Activity Monitor模板
  • 配置扩展的Info.plist:
    展开NSExtension -> NSExtensionAttributes,确保DeviceActivityReportExtension下的DeviceActivityName与主App中定义的一致(即代码中的restrictAppActivityName对应的字符串"restrictApp")
  • 为主App和扩展配置相同的App Group:
    在主App和扩展的Target配置中,找到Signing & Capabilities -> 添加App Groups,创建或选择同一个Group(比如group.com.yourdomain.yourapp),用于共享选中的应用列表数据

2. 修正主App中的DeviceActivitySchedule逻辑

之前的代码中DeviceActivitySchedule配置有误,倒计时场景需要创建一次性的时间触发规则,而非重复时间段。修改MyModel中的schedulingRestrictions方法:

func schedulingRestrictions() {
    print("Start scheduling restriction")
    
    // 设置倒计时结束时间(示例为15分钟后)
    let now = Date()
    let countdownEndTime = Calendar.current.date(byAdding: .minute, value: 15, to: now)!
    let endDateComponents = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute], from: countdownEndTime)
    
    // 创建一次性触发的Schedule:开始和结束时间设为同一个点,仅触发一次
    let schedule = DeviceActivitySchedule(
        intervalStart: endDateComponents,
        intervalEnd: endDateComponents,
        repeats: false,
        warningTime: nil
    )

    let center = DeviceActivityCenter()
    
    do {
        try center.startMonitoring(.restrictAppActivityName, during: schedule)
        print("Success scheduling restriction")
        
        // 将选中的应用列表保存到App Group,供扩展读取
        let sharedDefaults = UserDefaults(suiteName: "group.com.yourdomain.yourapp")!
        let encoder = JSONEncoder()
        if let data = try? encoder.encode(familyActivitySelection) {
            sharedDefaults.set(data, forKey: "SelectedApps")
        }
    } catch {
        print("Error scheduling restriction: \(error.localizedDescription)")
    }
}

3. 在DeviceActivityMonitor扩展中实现触发逻辑

扩展是独立运行的进程,需要在其中监听时间触发并设置应用限制:

import DeviceActivity
import ManagedSettings
import FamilyControls

class DeviceActivityMonitor: DeviceActivityMonitorProtocol {
    let store = ManagedSettingsStore()
    let sharedDefaults = UserDefaults(suiteName: "group.com.yourdomain.yourapp")!
    
    func intervalDidStart(_ interval: DateInterval, activity: DeviceActivityName) {
        guard activity == .restrictAppActivityName else { return }
        
        // 从App Group读取选中的应用列表
        let decoder = JSONDecoder()
        if let data = sharedDefaults.data(forKey: "SelectedApps"),
           let selection = try? decoder.decode(FamilyActivitySelection.self, from: data) {
            
            // 应用限制规则,和主App的startAppRestrictions逻辑一致
            store.shield.applications = selection.applicationTokens.isEmpty ? nil : selection.applicationTokens
            store.shield.applicationCategories = selection.categoryTokens.isEmpty ? nil : ShieldSettings.ActivityCategoryPolicy.specific(selection.categoryTokens)
            store.media.denyExplicitContent = true
            store.application.denyAppRemoval = true
            store.dateAndTime.requireAutomaticDateAndTime = true
            
            print("Restriction activated automatically")
        }
    }
}

4. 关键注意事项

  • 确保主App已获得Family Controls的授权(代码中已处理,但需确认用户已授予权限)
  • 优先用真机测试,模拟器对后台扩展的支持有限
  • 不要依赖主App后台进程执行倒计时逻辑,iOS会严格限制普通App的后台运行时间

为什么其他方法不可行

  • Cron/后台Timer:iOS后台执行机制严格,普通App后台无法长期运行定时任务,会被系统挂起
  • 本地通知:必须用户点击通知才能触发代码执行,无法自动在后台完成限制操作
  • DeviceActivityMonitor:是Apple专为Screen Time设计的系统级扩展,不受App后台状态影响,是实现该需求的唯一可靠方案

内容的提问来源于stack exchange,提问作者Yusuf Fachroni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 15:39:57