FamilyControls DeviceActivityMonitor extension can't change shields

I've been working on a small app using the new FamilyControls API, and I can't get the extension to make any visible changes to shields (or anything else).

  • I can get the main app to authorize and set and remove shields reliably.

  • I can also get the extension to run reliably in the background on a schedule (confirmed with Console).

But even if I try only setting the restricted apps to nil or the empty set the apps remain shielded until I run the same code from the main app.

  • I do have the Family Controls entitlement set on both the app and the extension, and I've tried having it off on the extension.

  • I have tried putting both of them into an App Group to no effect.

I've wrapped up the most basic working example I can think of into a project:

https://github.com/dpowers/ScreenPact

Any ideas about what stupid thing I'm missing?

  • Some debugging results that feel like they matter:

    If the extension doesn't have the Family Controls entitlement then any attempt to access values returned by ManageSettingsStore() fails with a sandbox error. This seems as it should be.

    However, if you have the entitlement, this code:

    logger.debug("num apps blocked before reset: \((store.shield.applications ?? Set()).count)")

    will accurately return the number of blocked apps when run from the app. But if this same code is run from the extension it always prints that 0 apps are blocked.

    So we are left with a weird world where ManagedSettingsStore returns something that allows for some kind of access, but the returned store doesn't reflect the same state available in the main app.

  • This still appears to be broken as of 15.3

  • As of at least Xcode 13.2.1 I can at least add the extension in the normal way with a template (Device Activity Monitor Extension) and I get a target setup for me with sample code. Previously I had to use another extension template and modify the build by hand to give it the correct entitlement and NSExtensionPointIdentifier.

    The downside is that the running behavior is exactly the same. From a fresh install onto a device I can get the extension to run, but it can't correctly retrieve the current set of shields and setting the shields to null using the same code that works in the main app does nothing.

    So far as the extension seems to be concerned ManagedSettingsStore().shield.applications is always nil.

Add a Comment

Accepted Reply

."But even if I try only setting the restricted apps to nil or the empty set the apps remain shielded until I run the same code from the main app." - you need to remember that app and an app extension doesn't share data so it's likely that the store instance you are using isn't the same. what you need to do is to manage the selected apps list you want to shield or block using user defaults or core data or some other persistence storage that will be shared between your app and app extension. and block or unblock according to the data you are managing between them.

try to keep the blocking or unblocking on the app or on the app extension so only one of the will use the store. i chose to do this on the extension using the events that correspond with start and stop monitoring

  • That would explain the behavior I'm seeing... but it's awfully confusing in the context of Parental Controls. So far as I understand, only one app can be authorized to set and remove shields on any given device, so I expected the ManagedSettingsStore to return something more like a system-wide singleton than something that is tied to the app. For instance, you authorize the app and not the extension because it requires user input, but I still expect the extension to be allowed to change shields.

    I'll try either calling back into the main app (somehow) from the extension or moving all the blocking into the extension itself and I'll report back.

Add a Comment

Replies

."But even if I try only setting the restricted apps to nil or the empty set the apps remain shielded until I run the same code from the main app." - you need to remember that app and an app extension doesn't share data so it's likely that the store instance you are using isn't the same. what you need to do is to manage the selected apps list you want to shield or block using user defaults or core data or some other persistence storage that will be shared between your app and app extension. and block or unblock according to the data you are managing between them.

try to keep the blocking or unblocking on the app or on the app extension so only one of the will use the store. i chose to do this on the extension using the events that correspond with start and stop monitoring

  • That would explain the behavior I'm seeing... but it's awfully confusing in the context of Parental Controls. So far as I understand, only one app can be authorized to set and remove shields on any given device, so I expected the ManagedSettingsStore to return something more like a system-wide singleton than something that is tied to the app. For instance, you authorize the app and not the extension because it requires user input, but I still expect the extension to be allowed to change shields.

    I'll try either calling back into the main app (somehow) from the extension or moving all the blocking into the extension itself and I'll report back.

Add a Comment

vova085 was right. I was trying to do some of the blocking/unblocking from within the app and some of the blocking/unblocking from the extension and that... doesn't work. I claim that it probably ought to work given that you can't have more than one app with permission to modify shields/blocks on any given device, but it doesn't.

Changing my code to only communicate changes to the extension via CoreData/CloudKit and making all permission changes from callbacks there fixed the issue.

  • powers can you please share your code. How did you manage to store the info using CoreData/CloudKit?

  • powers I would gladly pay you if you have code that uses DeviceActivityMonitor to implement changes based on the schedule and the event. I'm going to implement this tip that Vova had but given how my work's been going I think it might be better to ask someone else for help. If you know how to unblock an app after a certain amount of time has been accrued on another app, that would be a godsend.

Add a Comment