I am developing a parent child control app using Screen time API and Family Control. I created two apps, one for parent and another for child. I want to see child device's activity report on parent app. This functionality works when there is only one parent/organiser. I am trying to add multiple parents to access device activity report using screen time API. I created a family group where I am the organiser (Dad), added another account as parent (Mom) and two child accounts. On the child's device I installed the app, authorised the app for parental approval (Dad) and screen time restrictions. When using the parent app as Mom, I am unable to fetch the child device's activity report.
Family Controls
RSS for tagPrevent access to the Screen Time API without guardian approval and provide opaque tokens that represent apps and websites.
Posts under Family Controls tag
187 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Hi,
Is there any way to force orientation = portrait when opening another shielded app?
Thanks!
I've been working with the Screen Time API for almost 6 months now.
I found out it's completely unreliable, testing on iOS 17.4, the DeviceActivityReport is not showing, the DeviceActivityMonitor more often than not does not fire intervalDidStart. It's very frustrating.
Has anyone found out a workaround?
We all know there has to be something we're doing wrong, since apps like Opal and Jono does not present those types of issues.
Let's please unite our forces and find a solution. How to use this API should not be a secret!
I'm looking to make an app using the ScreenTime API and the Managed Settings Framework. I'm experimenting with the FamilyActivityPicker, but when i open it from the simulator i see only categories with no applications.
Without being able to select applications, i cannot test properly the app.
I can't install it on a real device to test it because i do not have a paid Apple Developer account and therefore can't access the capability if i select my Free Developer Account in order to install it on my iPhone.
I am currently trying to build a prototype parental control app using the ScreenTime API.
I was just wondering if I needed to create a separate parent and child app?
Hi,
we are facing issues with the FamilyActivityPicker.
I have 2 devices in the same family, one successfully authorised as child device using AuthorizationCenter.shared.requestAuthorization(for: .child), the other one is used as parent device.
When I invoke FamilyActivityPicker on the children's device it works as expected but when invoked on the parent's device it only shows list of categories but not a single app. This behavior doesn't occur every time, on some devices it sometime works as it should.
It's very odd and I can't find any reason why it is happening. I would appreciate any tips.
Tested on app built with Xcode 15.3 an run on iOS 17.4.1 and iOS 16.7.2
I am building an app that manages ScreenTime and I would like to persist the tokens of which apps are frequently limited to CoreData locally. I attempted to do so by converting to a string but was unable to find a way to initialize an ActivityCategoryToken with a string.
Is this possible? Am I going about it the wrong way?
Thanks.
I currently have an app that is a companion app alongside the iOS app. I wonder if it is possible for me to make this app both a standalone and a companion app. Essentially if someone does not have an iphone they can still use the app. Is this possible?
I am developing a parental control app using Flutter and platform channels to integrate with the Screen Time API on iOS. The app has two interfaces - one for the parent and one for the child. I have set up Family Sharing correctly and installed the app on both the parent's and child's devices. However, I am encountering some issues with the Family Activity Selection feature.
It's worth noting that I am a Flutter developer with limited knowledge of Swift and iOS development, so if my issues stem from a mistake I made, please forgive me.
The problems I am facing are as follows:
When calling the family activity selection, the list of apps shown in the apps sheet is from the parent's device, and no apps from the child's device are displayed. I have double-checked that Family Sharing and other necessary configurations are set up correctly, including the family control capability.
Even if I select apps on the parent's device, the selected apps are not returned in the result. The returned array is empty. Additionally, there is no close or done button on the sheet, and drag-to-dismiss is not working either. This might be an issue with the way I have written the code (most of the native code was generated by AI assistants like Claude and GPT, as I am a Flutter developer with limited knowledge of Swift and iOS development).
I have tested other parental control apps that use the Screen Time API and observed the same issue, where the parent's apps are shown on the parent's device instead of the child's apps.
For more context, I have provided the relevant code snippet below:
import Flutter
import FamilyControls
import ManagedSettings
import SwiftUI
class FamilyActivityHandler: NSObject, FlutterPlugin {
// ...
private func openFamilyActivityPicker(result: @escaping FlutterResult) {
let store = ManagedSettingsStore()
let selection = FamilyActivitySelection()
// Adjusting for UIWindowScene for iOS 15 and later
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let window = windowScene.windows.first else {
result(FlutterError(code: "NO_WINDOW_SCENE", message: "No window scene found", details: nil))
return
}
let viewController = UIHostingController(rootView: FamilyActivityPicker(selection: .constant(selection)))
viewController.modalPresentationStyle = .formSheet
window.rootViewController?.present(viewController, animated: true, completion: nil)
DispatchQueue.main.async {
let applications = selection.applicationTokens
let categories = selection.categoryTokens
let webDomains = selection.webDomainTokens
store.shield.applications = applications.isEmpty ? nil : applications
store.shield.applicationCategories = ShieldSettings.ActivityCategoryPolicy.specific(categories, except: Set())
store.shield.webDomains = webDomains
// Custom method to generate descriptive strings for tokens
let applicationsDescription = applications.map { token in
// Implement a custom description method or use an identifier property
"\(token)"
}
let categoriesDescription = categories.map { token in
// Implement a custom description method or use an identifier property
"\(token)"
}
let webDomainsDescription = webDomains.map { token in
// Implement a custom description method or use an identifier property
"\(token)"
}
let resultDict: [String: Any] = [
"applications": applicationsDescription,
"categories": categoriesDescription,
"webDomains": webDomainsDescription
]
result(resultDict)
}
}
}
I would greatly appreciate any guidance or insights from the community on how to resolve these issues and properly implement the Family Activity Selection feature using the Screen Time API in a Flutter app with platform channels.
Thank you in advance for your help!
I am developing a parental control app using Flutter and platform channels to integrate with the Screen Time API on iOS. The app has two interfaces - one for the parent and one for the child. I have set up Family Sharing correctly and installed the app on both the parent's and child's devices. However, I am encountering some issues with the Family Activity Selection feature.
It's worth noting that I am a Flutter developer with limited knowledge of Swift and iOS development, so if my issues stem from a mistake I made, please forgive me.
The problems I am facing are as follows:
When calling the family activity selection, the list of apps shown in the apps sheet is from the parent's device, and no apps from the child's device are displayed. I have double-checked that Family Sharing and other necessary configurations are set up correctly, including the family control capability.
Even if I select apps on the parent's device, the selected apps are not returned in the result. The returned array is empty. Additionally, there is no close or done button on the sheet, and drag-to-dismiss is not working either. This might be an issue with the way I have written the code (most of the native code was generated by AI assistants like Claude and GPT, as I am a Flutter developer with limited knowledge of Swift and iOS development).
I have tested other parental control apps that use the Screen Time API and observed the same issue, where the parent's apps are shown on the parent's device instead of the child's apps.
For more context, I have provided the relevant code snippet below:
import Flutter
import FamilyControls
import ManagedSettings
import SwiftUI
class FamilyActivityHandler: NSObject, FlutterPlugin {
// ...
private func openFamilyActivityPicker(result: @escaping FlutterResult) {
let store = ManagedSettingsStore()
let selection = FamilyActivitySelection()
// Adjusting for UIWindowScene for iOS 15 and later
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let window = windowScene.windows.first else {
result(FlutterError(code: "NO_WINDOW_SCENE", message: "No window scene found", details: nil))
return
}
let viewController = UIHostingController(rootView: FamilyActivityPicker(selection: .constant(selection)))
viewController.modalPresentationStyle = .formSheet
window.rootViewController?.present(viewController, animated: true, completion: nil)
DispatchQueue.main.async {
let applications = selection.applicationTokens
let categories = selection.categoryTokens
let webDomains = selection.webDomainTokens
store.shield.applications = applications.isEmpty ? nil : applications
store.shield.applicationCategories = ShieldSettings.ActivityCategoryPolicy.specific(categories, except: Set())
store.shield.webDomains = webDomains
// Custom method to generate descriptive strings for tokens
let applicationsDescription = applications.map { token in
// Implement a custom description method or use an identifier property
"\(token)"
}
let categoriesDescription = categories.map { token in
// Implement a custom description method or use an identifier property
"\(token)"
}
let webDomainsDescription = webDomains.map { token in
// Implement a custom description method or use an identifier property
"\(token)"
}
let resultDict: [String: Any] = [
"applications": applicationsDescription,
"categories": categoriesDescription,
"webDomains": webDomainsDescription
]
result(resultDict)
}
}
}
I would greatly appreciate any guidance or insights from the community on how to resolve these issues and properly implement the Family Activity Selection feature using the Screen Time API in a Flutter app with platform channels.
Thank you in advance for your help!
Hey, I am trying to use Family Controls in Mac Catalyst. On the iOS app it works fine. On macOs using Mac Catalyst it builds fine but I get following console output.
Failed to get service proxy: Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.apple.FamilyControlsAgent was invalidated: failed at lookup with error 159 - Sandbox restriction." UserInfo={NSDebugDescription=The connection to service named com.apple.FamilyControlsAgent was invalidated: failed at lookup with error 159 - Sandbox restriction.}`
When i try to open the FamilyActivityPicker on the macOs app following error is displayed in the GUI.
The operation could not be completed. (FamilyControls.ActivityPickerRemoteView Error error 2.)
Do I need a familyControls capability for macOs? If yes, I only find it for iOS.
Thanks for hints and help :)
Hi All,
I submitted a Family Controls Request Form but haven't heard back. I didn't get any case id when I submitted the request, so how do you track it and know when It is approved?
I'm currently developing an app that requires the main target and also the app extension to both use Family Controls. Does this mean I need to request forms for both app bundles separately or just the main app?
This is really worrying for us as our project is almost ready and we are unable to launch it :( . Would appreciate any responses.
Thanks,
I am currently debugging an issue with DeviceActivityMonitor where the threshold is reached even though the target app (e.g. Instagram) is not being used actively.
I noticed that the device with the unexpected behavior had the instagram.com website opened in the Safari web browser (among hundreds of other tabs).
That tab was not actively used either (not in foreground, Safari app neither used).
However, I was wondering if it can happen that this website is contributing towards the threshold as well even though it is in background and not used?
Otherwise I cannot explain myself this strange behavior.
Hello, I am working on a screen time manager that can block certain apps. I want this to work by allowing a certain number of 5-minute sessions per day. For each app the user selects, I would like to store the number of sessions remaining for that app in a dictionary. Currently, I am storing them in a dictionary of type <AppToken: Int>. However, I would like to store this dictionary to UserDefaults, and it doesn't seem like it is possible to store the type AppToken to UserDefaults. I was wondering how I could go about storing the AppTokenas a String and maybe saving to UserDefaults as a <String: Int> instead? Thanks.
Here is a post to gather findings in case anyone found out what this new API does.
Apple did not include any comments or documentation and due to the generic naming we don't know what this API might does.
https://developer.apple.com/documentation/deviceactivity/deviceactivityauthorization?changes=latest_major
I am relatively new to swift, and working on an app blocker using flutter and swift. In my Xcode runner file, I used File > New > Target > ShieldConfigurationExtension and File > New > Target > ShieldActionExtension to create the extensions with all the necessary Info.plist values. However, when I try to build, I am presented with this error message:
Error (Xcode): Cycle inside Runner; building could produce unreliable results.
Cycle details:
→ Target 'Runner': CodeSign /Users/arshgupta/Documents/pledge-1/build/ios/Debug-iphoneos/Runner.app
○ That command depends on command in Target 'Runner': script phase “[CP] Copy Pods Resources”
○ That command depends on command in Target 'Runner': script phase “Thin Binary”
○ Target 'Runner' has process command with output '/Users/arshgupta/Documents/pledge-1/build/ios/Debug-iphoneos/Runner.app/Info.plist'
○ Target 'Runner' has copy command from '/Users/arshgupta/Documents/pledge-1/build/ios/Debug-iphoneos/shieldAction.appex' to '/Users/arshgupta/Documents/pledge-1/build/ios/Debug-iphoneos/Runner.app/PlugIns/shieldAction.appex'
2
Raw dependency cycle trace:
target: ->
node: <all> ->
command: <all> ->
node: /Users/arshgupta/Documents/pledge-1/build/ios/Debug-iphoneos/Runner.app/_CodeSignature ->
command: P0:target-Runner-18c1723432283e0cc55f10a6dcfd9e0288a783a885d8b0b3beb2e9f90bde3f49-:Debug:CodeSign /Users/arshgupta/Documents/pledge-1/build/ios/Debug-iphoneos/Runner.app ->
node: /Users/arshgupta/Documents/pledge-1/build/ios/Debug-iphoneos/Runner.app/GoogleSignIn.bundle/ ->
directoryTreeSignature: [ ->
directoryContents: /Users/arshgupta/Documents/pledge-1/build/ios/Debug-iphoneos/Runner.app/GoogleSignIn.bundle ->
CYCLE POINT ->
node: /Users/arshgupta/Documents/pledge-1/build/ios/Debug-iphoneos/Runner.app/GoogleSignIn.bundle ->
command: P2:target-Runner-18c1723432283e0cc55f10a6dcfd9e0288a783a885d8b0b3beb2e9f90bde3f49-:Debug:PhaseScriptExecution [CP] Copy Pods Resources /Users/arshgupta/Library/Developer/Xcode/DerivedData/Runner-gkxkhzabeikourbemhpfsdwlgfor/Build/Intermediates.noindex/Runner.build/Debug-iphoneos/Runner.build/Script-F71E8F68D8E3D1B95F11D101.sh ->
node: /Users/arshgupta/Library/Developer/Xcode/DerivedData/Runner-gkxkhzabeikourbemhpfsdwlgfor/Build/Intermediates.noindex/Runner.build/Debug-iphoneos/Runner.build/InputFileList-F71E8F68D8E3D1B95F11D101-Pods-Runner-resources-Debug-input-files-276c84640d21f41dd725929b3125799d-resolved.xcfilelist ->
command: P2:target-Runner-18c1723432283e0cc55f10a6dcfd9e0288a783a885d8b0b3beb2e9f90bde3f49-:Debug:WriteAuxiliaryFile /Users/arshgupta/Library/Developer/Xcode/DerivedData/Runner-gkxkhzabeikourbemhpfsdwlgfor/Build/Intermediates.noindex/Runner.build/Debug-iphoneos/Runner.build/InputFileList-F71E8F68D8E3D1B95F11D101-Pods-Runner-resources-Debug-input-files-276c84640d21f41dd725929b3125799d-resolved.xcfilelist ->
node: <target-Runner-18c1723432283e0cc55f10a6dcfd9e0288a783a885d8b0b3beb2e9f90bde3f49--fused-phase4-thin-binary> ->
command: P0:::Gate target-Runner-18c1723432283e0cc55f10a6dcfd9e0288a783a885d8b0b3beb2e9f90bde3f49--fused-phase4-thin-binary ->
node: <execute-shell-script-18c1723432283e0cc55f10a6dcfd9e02f1eee2015e8ff5ebcd27678f788c2826-target-Runner-18c1723432283e0cc55f10a6dcfd9e0288a783a885d8b0b3beb2e9f90bde3f49-> ->
command: P2:target-Runner-18c1723432283e0cc55f10a6dcfd9e0288a783a885d8b0b3beb2e9f90bde3f49-:Debug:PhaseScriptExecution Thin Binary /Users/arshgupta/Library/Developer/Xcode/DerivedData/Runner-gkxkhzabeikourbemhpfsdwlgfor/Build/Intermediates.noindex/Runner.build/Debug-iphoneos/Runner.build/Script-3B06AD1E1E4923F5004D2608.sh ->
node: /Users/arshgupta/Documents/pledge-1/build/ios/Debug-iphoneos/Runner.app/Info.plist/ ->
directoryTreeSignature: R ->
directoryContents: /Users/arshgupta/Documents/pledge-1/build/ios/Debug-iphoneos/Runner.app/Info.plist ->
node: /Users/arshgupta/Documents/pledge-1/build/ios/Debug-iphoneos/Runner.app/Info.plist ->
command: P0:target-Runner-18c1723432283e0cc55f10a6dcfd9e0288a783a885d8b0b3beb2e9f90bde3f49-:Debug:ProcessInfoPlistFile /Users/arshgupta/Documents/pledge-1/build/ios/Debug-iphoneos/Runner.app/Info.plist /Users/arshgupta/Documents/pledge-1/ios/Runner/Info.plist ->
node: /Users/arshgupta/Documents/pledge-1/build/ios/Debug-iphoneos/Runner.app/PlugIns/shieldAction.appex ->
command: P0:target-Runner-18c1723432283e0cc55f10a6dcfd9e0288a783a885d8b0b3beb2e9f90bde3f49-:Debug:Copy /Users/arshgupta/Documents/pledge-1/build/ios/Debug-iphoneos/Runner.app/PlugIns/shieldAction.appex /Users/arshgupta/Documents/pledge-1/build/ios/Debug-iphoneos/shieldAction.appex ->
node: <target-Runner-18c1723432283e0cc55f10a6dcfd9e0288a783a885d8b0b3beb2e9f90bde3f49--fused-phase5--cp--copy-pods-resources> ->
command: P0:::Gate target-Runner-18c1723432283e0cc55f10a6dcfd9e0288a783a885d8b0b3beb2e9f90bde3f49--fused-phase5--cp--copy-pods-resources ->
node: /Users/arshgupta/Documents/pledge-1/build/ios/Debug-iphoneos/Runner.app/GoogleSignIn.bundle
What can I do to fix this?
I have two repeating DeviceActivitySchedules running in my app and noticed a super strange behavior:
whenever I modify Screen Time API permission settings (granting an additional app permission, or removing permission for a different app (completely different unrelated screen time apps from App Store)) all my DeviceActivitySchedules are cancelled and the intervalDidEnd callbacks are called
my permission is not modified in this scenario
this is a super strange and unexpected behavior
is anyone able to reproduce this?
for me this happens 100% of the times I do this
any known workarounds?
How can I count the number of pickups for a certain application?
The docs say that there is a struct ApplicationActivity within the DeviceActivityData:
https://developer.apple.com/documentation/deviceactivity/deviceactivitydata
Using this code I receive a warning in XCode:
Value of type 'DeviceActivityData' has no member 'applicationActivity'
struct ApplicationPickupCountReport: DeviceActivityReportScene {
// Define which context your scene will represent.
let context: DeviceActivityReport.Context = .applicationPickupCount
// Define the custom configuration and the resulting view for this report.
let content: (String) -> ApplicationPickupCountView
func makeConfiguration(representing data:
DeviceActivityResults<DeviceActivityData>) async -> String {
var totalPickups = 0
let totalPickups = await data.flatMap { $0.applicationActivity }.reduce(0, {
$0 + $1.numberOfPickups
})
return "\(totalPickups)"
}
}
Hello,
I am using a DeviceActivityEvent to limit access to an app after the user has spent x minutes on it.
Sometimes it can happen that a DeviceActivitySchedule spans from 11:55pm - 12:25am (just an example).
In these cases, I have noticed, the DeviceActivityMonitorExtension’s eventDidReachThreshold is not called after the user has reached the threshold time interval in the observed app.
I assume this is because we have transitioned over midnight and something weird happens to the DeviceActivitySchedule.
I’ve tried adding the day components to the DeviceActivitySchedule as well, but then it fails completely.
Any advice how to handle this?
I could, of course, create two separate DeviceActivitySchedules: one for before midnight, and one for after. But depending on the user’s real app usage that could lead to slightly different (and unexpected) behavior.
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?