Post not yet marked as solved
Hi there,
In rare cases (about 0.2% of the time?), I'm seeing calls to startMonitoring on an instance of DeviceActivityCenter throw an error with localizedDescription "couldn’t communicate with a helper application."
I am certain I am passing valid parameters to the startMonitoring call because sometimes a naive retry after a few seconds succeeds. Similarly, I am certain that FamilyControls permissions have been granted by the user.
Was hoping to get more color from the systems team on what some causes of this error are and if it is avoidable by the programmer.
Post not yet marked as solved
The functionality of authorizationStatus and requestAuthorization is completely broken. I'm using Xcode 15.3 and iOS 17.4.
Does anyone have a solution?
authorizationStatus doesn't behave as promised
Revoking authorization in the system-wide settings does not change the authorizationStatus while the app is not closed. Calls to center.authorizationStatus will still return .approved instead of .denied.
Even closing and relaunching the app after revoking authorization does not work: authorizationStatus is then .notDetermined when it should be .denied.
Tapping "Don't Allow" in the alert shown after an initial call to requestAuthorization leaves the authorizationStatus unchanged, i.e. at .notDetermined. This is contrary to the promised outcome .denied (defined as: "The user, parent, or guardian denied the request for authorization") and contrary to the definition of .notDetermined (defined as: "The app hasn’t requested authorization", when it just did).
Same issue when first tapping "Continue" followed by "Don't Allow" on the next screen.
As a consequence of authorizationStatus being broken, its publisher $authorizationStatus is worthless too.
requestAuthorization doesn't behave as promised
This is most likely a consequence of the corrupted authorizationStatus: when revoking authorization in the system-wide settings, a call to requestAuthorization opens the authorization dialogue instead of doing nothing. It is thus possible to repeatedly ask a user to authorize Family Controls.
Code sample
To reproduce, create a new SwiftUI app, add the "Family Controls" capability and a button executing the following task when tapped:
let center = AuthorizationCenter.shared
var status = center.authorizationStatus
print(status)
do {
try await center.requestAuthorization(for: .individual)
print("approved")
} catch {
print("denied")
}
status = center.authorizationStatus
print(status)
Post not yet marked as solved
If we want to un-shield category/application for particular schedule, then what is the mechanism for this, as for now we are using
ManagedSettingsStore().shield.applications = nil and ManagedSettingsStore().shield.applicationCategories = nil, which is actually un-shielding all category/applications without considering the selection of category/application for that schedule. What is the best approach to handle multiple schedules for shielding of apps?
Post not yet marked as solved
How can I add an X as close button on the FamilyActivityPicker Toolbar?
Desired effect see image
Post not yet marked as solved
Starting with iOS 17.4, the DeviceActivityEvent initializer includes a new parameter named includesPastActivity.
The default value for this parameter is set to false, whereas device activity events have behaved as though this parameter were set to true up until now.
This breaking change is a MAJOR ISSUE for developers who used device activity events in their apps before iOS 17.4 because their apps might not work the way they intended after the update. They'll have to release new app versions that specifically set includesPastActivityto true.
In my opinion, the default value for includesPastActivity should be true to avoid disrupting events scheduled on older versions of iOS.
I have filed an enhancement report (FB13573556) about this. I really hope this is changed before the official iOS 17.4 release.
Post not yet marked as solved
Hey,
is there a possibility to dynamically decrease the font size of
Label(applicationToken).labelStyle(.titleOnly) to avoid overflow of the parent view?
Under the estimation that FamilyActivityPicker uses those labels there must be a way because the font sizes decreases there.
Post not yet marked as solved
It's no secret, the Screen Time/Family Controls API is incredibly challenging to figure out.
If you want to talk with other people building on the API, join the discord here: https://discord.gg/sjxhKWgry4
I want to connect with other people building so I made a discord where we can discuss challenges, updates & questions in more depth.
Post not yet marked as solved
I'm using the Screen Time API to shield apps the user selects. The problem is, that the apps are always shielded, even outside of the schedule. Here is my function initiateMonitoring:
func initiateMonitoring(scheduleStart: DateComponents, scheduleEnd: DateComponents) {
let schedule = DeviceActivitySchedule(
intervalStart: scheduleStart,
intervalEnd: scheduleEnd,
repeats: true
)
let center = DeviceActivityCenter()
do {
try center.startMonitoring(.daily, during: schedule)
logger.log("STARTED MONITORING")
} catch {
logger.log("FAILED MONITORING: \(error.localizedDescription)")
}
}
The expected result should be that the selected Apps should be blocked during the schedule the user specified, but not outside the schedule, but it is blocked 24/7. I've experimented with the DateComponents, but the issue may be somewhere else.
What's maybe interesting is, I tried Logging the DeviceActivityMonitor and somehow it doesn't get called. The logging-output from initiateMonitoring is printed in the console, but for the DeviceActivityMonitor it's not. I implemented it as recommended as a separate Extension Target. For more context, here is my DeviceActivityMonitor:
class DeviceActivityMonitorExtension: DeviceActivityMonitor {
let store = ManagedSettingsStore()
let logger = Logger()
override func intervalDidStart(for activity: DeviceActivityName) {
super.intervalDidStart(for: activity)
logger.log("INTERVAL STARTED")
let model = ShieldManager.shared
let applications = model.selectionToDiscourage.applicationTokens
let categories = model.selectionToDiscourage.categoryTokens
let webCategories = model.selectionToDiscourage.webDomainTokens
store.shield.applications = applications.isEmpty ? nil : applications
store.shield.applicationCategories = ShieldSettings.ActivityCategoryPolicy.specific(categories, except: Set())
store.shield.webDomains = webCategories.isEmpty ? nil : webCategories
}
...
What's confusing me is that the apps are in fact shielded, so the MonitorExtension should be called, but neither the logging works nor my separate ShieldConfigurationExtension, maybe the issues are connected...
Any help would be gladly appreciated!
Post not yet marked as solved
I am currently developing an app to help people focus on their work.
I use familycontrols , managedsettings and devie activity to develop it.
I am currently facing an issue where I would like to hide the app selected by the user from the main screen and resource library.
But I did not find any relevant information in the document. Who can help me.
Post not yet marked as solved
when i watch the video (https://developer.apple.com/videos/play/wwdc2022/110336/)
i find the code
let socialStore = ManagedSettingsStore(named: .social)
let socialCategory = database.socialCategoryToken
socialStore.shield.applicationCategories = .specific([socialCategory])
i try to find ManagedSettingsStore shield and specific([socialCategory]) i Documentation , but i failed.
who can tell me wher i can find about ManagedSettingsStore shield or specific([socialCategory]) ?
thanks a lot.
Post not yet marked as solved
There is a way to allow DeviceActivityMonitor to make UI changes?
Currently I have some code in the intervalDidStart and intervalDidEnd that updates Core Data entities, and it works correctly.
However, the changes are only reflected if the app is terminated and opened again.
Thus, if the app is opened and one of the methods inside the DeviceActivityMonitor is being called, the UI won't be updated.
PS: I am using @FetchRequest to retrieve the core data entities called BlockEntity, and I have a little circle in the UI which should indicate the status of the block: active/inactive, so it would be nice to update the color in real time when intervalDidStart or intervalDidEnd are called.
I want to block specific Websites with FamilyControls in my App. To do this, I need to access the WebDomainTokens of a specific Website, without the user selecting it in the FamilyActivityPicker. I basically just want to have a button e.g. "Block Instagram" and when clicking it, the instagram website is blocked. I don't see any way in accessing the WebDomainToken without the FamilyActivityPicker. Or is there maybe another approach to this problem?
Currently I tried the following:
var selectionToDiscourage = FamilyActivitySelection() {
willSet {
let applications = newValue.applicationTokens
store.shield.applications = applications.isEmpty ? nil : applications
let webDomain: WebDomain = .init(domain: "https://www.instagram.com/")
print("TOKEN: \(webDomain.token)")
print("DOMAIN: \(webDomain.domain)")
if let webDomainToken = webDomain.token {
let webDomainTokenSet: Set<WebDomainToken> = [webDomainToken]
store.shield.webDomains = webDomainTokenSet
}
}
}
But when only giving the domain, the token always prints nil.
Hope someone can help!
Post not yet marked as solved
XCODE: 15.2
IOS: 16.0.1
Following the document about how to track the current status of AuthorizationStatus seems to be not working on my current environment.
https://developer.apple.com/documentation/familycontrols/authorizationcenter/authorizationstatus
The user authorization is .individual
Here is my sample code to identify if the status has changed after revoking the permission from the Settings > ScreenTime
@ObservedObject var center = AuthorizationCenter.shared
@Environment(\.dismiss) var dismiss
@State private var isAlert = false
var body: some View {
VStack {
Button {
dismiss()
} label: {
Text("Close")
}
.buttonStyle(GrowingButton())
}
VStack {
Button {
DispatchQueue.main.async {
if center.authorizationStatus != .approved {
Task {
do {
if #available(iOS 15.0, *) {
if #available(iOS 16.0, *) {
//let center = AuthorizationCenter.shared
try await center.requestAuthorization(for: .individual)
}
}
}
}
} else {
self.isAlert = true
}
}
} label: {
Text("Validate Screen Time Permission")
}
.buttonStyle(GrowingButton())
.alert(isPresented: $isAlert, content: {
switch center.authorizationStatus {
case .notDetermined:
Alert(title: Text("Screen Time not Determined"))
case .denied:
Alert(title: Text("Screen Time is Denied"))
case .approved:
Alert(title: Text("Screen Time is Approved"))
@unknown default:
Alert(title: Text("Unknown"))
}
})
}
}
}
It will still fallback to the APPROVED state even if the permission was already revoked from ScreenTime settings.
Highly appreciated if anybody from the community can help me figure out this thing to work.
Thank you.
Post not yet marked as solved
With "Automatically Manage Signing" enabled in Signing & Capabilities I got a message when uploading to the App Store complaining that my provisioning profile was missing Family Control capabilities.
I do have the capability enabled in XCode, and I can deploy directly to devices to see that the app works correctly (that is, it has the capability).
Further, I can see the same capability checked in the App Id under my developer profile.
Further, if I generate a profile manually it claims to include Family Controls in the info screen.
But still it won't let me upload the app.
I've tried:
deleting all automatically generated profiles and regenerating them.
adding and removing the capability in Xcode and in the App Id
generating a manual provisioning profile and downloading it (this one complains about the missing capability when I download it).
Any ideas?
Post not yet marked as solved
An app that uses screen time API.
After asking for permission and receiving them works, everything generally work, shields applications etc..
Upon new version update (manually update from testFlight old version or App Store)
I get an error message, I can then update again without any error but the permissions
are revoked and I have to ask for them again. shielding stopes.
This happens randomly on TestFlight or App Store and the permissions
Did anyone encounter this or solved this?
this seems to have started a month ago but maybe I just missed it before
Post not yet marked as solved
I am able to correctly select and store the tokens of apps and categories my users will block, but I am unable to pre-populate Picker whenever the app is rebooted with previously selected and stored tokens. Below is the selection variable I am passing to the picker...
var selectionsToBlock = FamilyActivitySelection() {
willSet {
saveSelection(selection: newValue)
blockersSelected = true
}
}
Is there any way I can provide my existing blockers (shown below) so that the user can easily edit their list of restricted apps from the Picker?
func savedBlockers() -> FamilyActivitySelection? {
let defaults = UserDefaults.standard
guard let data = defaults.data(forKey: userDefaultsKey) else {
return nil
}
return try? decoder.decode(
FamilyActivitySelection.self,
from: data
)
}
Post not yet marked as solved
At 11:37 in this video - https://developer.apple.com/videos/play/wwdc2021/10123/ - Nolan instantiates MyModel() in swiftui view file. And then at 12:02 he just uses MyModel from extension.
I have the exact same code and when I try to build my project, it fails with error that MyModel() could not be found.
I shared my MyModel.swift file between extension target and main app. Now it builds. However, it seems there are two separate instances of MyModel.
What is proper way for DeviceActivityMonitor extension to pass data to main app? I simply want to increment counter from extension every minute and let the main app to know that.
Or even better, - is there a way to use SwiftData from Device Activity Monitor extension?
Post not yet marked as solved
Hello,
I want to make a simple project that simply displays the user's current daily ScreenTime.
I believe you may be able to do the functionality I want with: FamilyControls or ScreenTime. I believe that you may need to pay for the paid developer account in order to access the FamilyControl framework.
I am having trouble finding guidance as to how I would do this as most reddit/stackoverflow posts are incomplete with answers and I cannot find demos/code examples/tutorials/sample usage anywhere on google.
I would greatly appreciate any help and guidance. If the solution requires the paid developer tier, I am fine with that. Thank you in advance
Post not yet marked as solved
I have implemented a shielding mechanism via Family Controls to prevent unauthenticated users from deleting specific shortcuts within the Shortcuts app. While this successfully secures the app, it has an unintended consequence: the Shortcuts app no longer appears in Spotlight Search and becomes inaccessible for users subject to this shielding. I understand that this is the default behavior when implementing app shielding or time limits on specific apps. Is there a way to retain the app's visibility in Spotlight Search despite it being shielded?
Post not yet marked as solved
I'm writing an app that uses Family Control. Most of the functionality has already been debugged, including in the call try deviceActivityCenter.startMonitoring(activityName, during: schedule, events: [ eventName: event ]) Works fine on my IOS17 device, but on my old IOS16 device I found that it can't be called, like intervalDidStart, intervalDidEnd, eventDidReachThreshold etc can't be called. I checked some information, https://forums.developer.apple.com/forums/thread/724243 delete the Build Settings mentioned in this link, and change the ios Deployment Target to ios16, and found that it didn't work. Don't know where the problem is?