返回

DeviceActivityMonitorExtension 不被调用?排查指南

IOS

DeviceActivityMonitorExtension 不被调用的排查指南

DeviceActivityMonitorExtension 用于监控设备活动并执行相应的操作。当此扩展不被调用时,通常是由几个关键配置或实现错误导致的。 下文将针对此问题,剖析可能的原因,并提供相应的解决方案。

常见问题与分析

最常见的现象是:虽然你在代码中调用了 DeviceActivityCenter().startMonitoring(),期望扩展内的 intervalDidStart, intervalDidEndeventDidReachThreshold 等方法被触发,实际却没有任何反应,如同石沉大海。

根本原因往往在于以下几个方面:

  1. 配置问题 : DeviceActivityMonitorExtension 的配置不完整或者不正确。例如,缺少必要的功能声明、Info.plist 文件配置错误或权限不足。
  2. 代码逻辑问题 : DeviceActivityMonitor 的调度配置或 DeviceActivityEvent 定义存在问题。 监控启动、事件定义,乃至时间配置的不当,都会导致扩展程序无法正常工作。
  3. 模拟器/真机环境 : 某些测试行为在模拟器上可能与真机存在差异。因此需要切换环境,尝试解决某些由于模拟器特殊环境而引起的问题。
  4. 进程间通信问题 : DeviceActivity 机制运行在不同的进程中,因此任何可能阻碍进程间通信的问题都可能影响到 Extension 的正常执行。例如,app group设置或者证书签名错误都有可能会出现这类问题。
  5. 代码错误 : 例如:使用 Notification 相关函数时权限申请不及时或使用错误可能造成相关行为没有生效。

解决方案

以下提供几种解决 DeviceActivityMonitorExtension 不被调用的方法,并给出代码示例和步骤说明。

方案一: 确保 Info.plist 文件配置正确

DeviceActivityMonitorExtension 需要在 Info.plist 文件中正确声明其身份和所需的权限。

步骤:

  1. 检查你的 DeviceActivityMonitorExtension 的 Info.plist 文件:
*  `NSExtension`  字典中必须有 `NSExtensionPointIdentifier` 键,且值必须为 `com.apple.deviceactivity-monitor`。
*   `NSExtensionPrincipalClass` 键值必须匹配你的  `DeviceActivityMonitorExtension` 类名 (如 `DeviceActivityMonitorExtension`)。

方案二: 检查 App Groups 配置

使用 FamilyControlsDeviceActivity 时,应用和扩展必须共享同一个 App Group。
步骤:

  1. 打开Xcode,选中应用和 Extension target。在Signing & Capabilities 添加App Groups。确认两者使用了相同的App Group Identifier。如果还不存在 App Group Identifier ,点击+号,新建即可。
  2. 代码示例 (仅示例检查,代码一般无需修改):
    // 在您的扩展中
  let sharedUserDefaults = UserDefaults(suiteName: "你的 App Group Identifier")

确保应用的 bundle id 存在与 app group identifier 相对应的prefix。 例如你的应用的 bundle idcom.example.app。 如果app group identifiergroup.example.share 那么此app group prefixgroup.example。 请注意,即使应用之间没有相互依赖,多个应用的app group identifier 前缀都应该相同。 确保这些在你的 Provisioning profile文件中都得到了体现。

方案三:仔细检查 DeviceActivityCenter().startMonitoring() 参数

正确的调用 startMonitoringDeviceActivityMonitorExtension 工作的基石。
步骤:

  1. 确认你声明 DeviceActivityName 的地方(static let daily = Self("daily"))和 startMonitoring() 里使用的name相同。
  2. 核查intervalStartintervalEnd是否按预期设置。 错误的开始和结束时间设置会导致监控无法正常进行。如以下代码中,时间被设置为零点至晚上的 11点 59,因此任何时候你测试这个设置, DeviceActivityMonitorExtension 都应该能监听到事件。
  3. 确保 DeviceActivityEvent 被正确的初始化。你的示例代码中初始化代码没有问题,但请记住applicationTokens 一定要有值。并且该 applicationTokens 需要是符合 FamilyControls 要求。
   let schedule = DeviceActivitySchedule(
      intervalStart: DateComponents(hour: 0, minute: 0),
      intervalEnd: DateComponents(hour: 23, minute: 59),
      repeats: true
    )
   
    let dailyEvent = DeviceActivityEvent(
      applications: GlobalSelection.shared.selection.applicationTokens, threshold: threshold
    )
  do {
    try DeviceActivityCenter().startMonitoring(.daily, during: schedule, events: ["dailyLimitEvent": dailyEvent])
  }catch {
     print("监控启动错误 \(error)")
  }

此外确保事件的key 和事件名相同 (如 dailyLimitEvent):

代码示例:

      let eventName = DeviceActivityEvent.Name("dailyLimitEvent") //确保声明时key 和 startMonitoring 中事件名称相同。
    
     do {
         try DeviceActivityCenter().startMonitoring(.daily, during: schedule, events: [eventName: dailyEvent])
          print("监控已启动")
    }catch{
         print("启动失败 \(error)")
    }

确保传给 events 的参数为一个字典类型,key 为事件名字 DeviceActivityEvent.Name 结构的值, value为你的 DeviceActivityEvent 结构。 如果你需要监听多个事件,将对应的事件加到字典中即可。

方案四:Notification 配置与权限

如 `DeviceActivityMonitorExtension` 中需要展示本地通知,需要确认已向用户申请授权。并需要合理初始化本地通知配置。

步骤:

  1. 确保你在初始化通知之前进行了用户授权,以及对通知注册成功的回调做了合适的异常处理,示例代码如下所示。

代码示例:


 func scheduleNotification(with title: String) {
        let center = UNUserNotificationCenter.current()
        center.requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
            if granted {
               // 构建通知 content
                let request = UNNotificationRequest(identifier: "MyNotification", content: content, trigger: trigger)

                center.add(request) { error in
                  if let error = error{
                      print("注册本地通知失败 \(error.localizedDescription)")
                   }else {
                      print("注册本地通知成功")
                  }

                }
            } else {
               print("无通知授权: \(error?.localizedDescription ?? "")")

           }
         }

}

方案五:模拟器与真机测试对比
某些测试和模拟效果在模拟器中表现的可能与真实环境有差异。 例如一些测试方法, 可能会因为没有在真机安装证书或者 profile 而出现不生效情况。 在你的 debug 或者release 版本中使用真机进行测试,往往会提供给你更多有用信息。

额外建议:

  • 在 debug 时开启控制台,将 debug 信息打印到 console, 便于排错。
  • 可以考虑在 App 和 Extension 中引入同样的 Log 方法,更方便跟踪和问题排查。
  • 合理使用断点调试 (breakpoint),并熟悉其调试方法,可以极大提高你寻找问题的效率。

通过系统排查这些方面的问题,通常能有效地定位并解决 DeviceActivityMonitorExtension 不被调用的问题。 如果你仍旧遇到难题,欢迎把错误代码和具体环境信息,贴到社区请求帮助,以便其他开发者能够更好的帮你解决问题。