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?

Answered by vova085 in 700568022

."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

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.

Accepted Answer

."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

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.

FamilyControls DeviceActivityMonitor extension can't change shields
 
 
Q