Managed Settings

RSS for tag

Set restrictions for certain settings, such as locking accounts in place, preventing password modification, filtering web traffic, and shielding apps.

Posts under Managed Settings tag

200 Posts

Post

Replies

Boosts

Views

Activity

ShieldActionDelegate uses a different webDomain than the one I shielded
I shield a web domain picked by users like this (discouragedSelections is an instance of FamilyActivitySelection() btw) : let webDomainTokens = discouragedSelections.webDomainTokens store.shield.webDomains = webDomainTokens The domain is correcly shielded and I can see the restricted screen when I access it via Safari. When I tap on the main button of that restricted view, I receive a different token than the one I got from .webDomainTokens from the code above. Why? override func handle(action: ShieldAction, for webDomain: WebDomainToken, completionHandler: @escaping (ShieldActionResponse) -> Void) { // webDomain here is different from the one in store.shield.webDomains }
2
3
749
Aug ’24
Application Tokens from Bundle Identifier
Hello! I've been doing a lot of work with ApplicationTokens, but there is very little documentation. While Apple gives you the FamilyAcitvitiesPicker to get tokens of apps on an iPhone, I need to get the tokens of apps that aren't on the phone. Example: Someone can select Instagram even though they don't have it downloaded. Then the application token will get sent to a server. Then a different person who does have Instagram on their phone will receive the token and it will do something with that application. Because FamilyActivitiesPicker can only select apps on the iPhone that it is running on, FamilyActivitiesPicker is useless to me, leading to my problem: Creating an ApplicationToken without FamilyActivitiesPicker This documentation says that I can create an Application (and thus an ApplicationToken) from the bundle identifier init(bundleIdentifier: String) Creates an object that represents the app with the specified bundle identifier. However, when I try to use this to get instagrams(or any apps) token, it returns nil every time! So, finally, my questions: How do I correctly use this initializer to create an ApplicationToken? Or, if this won't work for my purposes Are the ApplicationTokens created by FamilyActivitiesPicker the same across all devices no matter what?
2
0
1.2k
Aug ’24
Shield Customisation Not Applying
Hi, I've been attempting to implement a customised shield based on the WWDC contents and documentation; however, while my configuration appears correct only the default "Restricted - You cannot use X app because it's restricted" ever displays. A quick summary of what I have done: Created a ShieldConfigurationExtension Ensured suitable Info.plist values - below Defined custom Shield within the configuration() methods - application example below Any suggestions on what might not be implemented correctly? Info.plist <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>NSExtension</key> <dict> <key>NSExtensionPointIdentifier</key> <string>com.apple.ManagedSettingsUI.shield-configuration-service</string> <key>NSExtensionPrincipalClass</key> <string>$(PRODUCT_MODULE_NAME).ShieldConfigurationExtension</string> </dict> </dict> </plist> Configuration import ManagedSettings import ManagedSettingsUI import UIKit class ShieldConfigurationExtension: ShieldConfigurationDataSource {       override func configuration(shielding application: Application) -> ShieldConfiguration {     // Customize the shield as needed for applications.     return ShieldConfiguration(       backgroundBlurStyle: UIBlurEffect.Style.systemThickMaterial,       backgroundColor: UIColor.white,       icon: UIImage(systemName: "stopwatch"),       title: ShieldConfiguration.Label(text: "No app for you", color: .yellow),       subtitle: ShieldConfiguration.Label(text: "Sorry, no apps for you", color: .white),       primaryButtonLabel: ShieldConfiguration.Label(text: "Ask for a break?", color: .white),       secondaryButtonLabel: ShieldConfiguration.Label(text: "Quick Quick", color: .white)     )   } }
5
0
2.8k
Aug ’24
Using core data in ShieldConfigurationExtension
Hi there, In short, I'm trying to use CoreData in my ShieldConfigurationDataSource extension. Trying to fetch from core data at all seems to cause the shield to render it's default look. I already added the extension to an app group + configured my persistence store to use the app group. Below is my code, any help is appreciated: // Shield extension override func configuration(shielding application: Application) -> ShieldConfiguration { do { let appSelectionId = "XXX" let blockedItemReq = ... blockedItemReq.predicate = ... let moc = PersistenceController.shared.container.viewContext // Commenting this and the bottom out makes it work, but I need the data! let blockedItemRes = try moc.fetch(blockedItemReq) let shieldTitle = ShieldConfiguration.Label(text: "Hello there", color: .red) return ShieldConfiguration(backgroundColor: .black, title: shieldTitle) } catch { let shieldTitle = ShieldConfiguration.Label(text: "ERROR \(error.localizedDescription)", color: .white) return ShieldConfiguration(backgroundColor: .black, title: shieldTitle) } } // Persistence Controller init(inMemory: Bool = false) { container = NSPersistentContainer(name: "AppBlockerOne") if inMemory { container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null") } else { let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.appblockerone")! let storeURL = containerURL.appendingPathComponent("AppBlockerOne.sqlite") let description = NSPersistentStoreDescription(url: storeURL) container.persistentStoreDescriptions = [description] } container.loadPersistentStores(completionHandler: { (storeDescription, error) in if let error = error as NSError? { fatalError("Unresolved error \(error), \(error.userInfo)") } }) container.viewContext.automaticallyMergesChangesFromParent = true }
2
0
800
Aug ’24
How does the threshold in DeviceActivityEvent work
Hey everyone, I'm working on implementing an AppLimit, where after accumulating x minutes of Screen Time for an app, it should be blocked. It works fine on the first day, but stops functioning correctly on subsequent days. What I'm Doing I start a 24/7 schedule with a DeviceActivityEvent that has a specified Screen Time threshold. In my DeviceActivityMonitor, I'm reacting to the eventDidReachThreshold. Once the accumulated time is reached, the app is blocked. This works as expected on the first day. Issues I'm Experiencing / Questions Second Day Issue: On the second day, the app is no longer blocked after the Screen Time threshold is reached, even though it worked on the first day. This leads me to suspect that a DeviceActivityEvent is "consumable". Is this correct? Pre-existing Screen Time Issue: If a user has already surpassed the Screen Time threshold before monitoring starts, the app isn't blocked once the schedule is set up. This leads to 2 issues: I would expect that the accumulated amount of time after starting the schedule would result in the call of eventDidReachThreshold. But it is never called It could also be the case that the previously accumulated time is being kept in mind, but that would mean the apps should be blocked, which isn't the case. Does the threshold account for accumulated Screen Time before the schedule begins? I haven't tested setting a limit of 10 minutes, accumulating 3 minutes of Screen Time, then starting the schedule and accumulating the remaining time, but I'm curious if anyone has encountered this behavior. Does anyone have an explanation for this behavior? Any help would be greatly appreciated!
2
0
1.1k
Aug ’24
FamilyActivityPicker on Simulator not populating apps.
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.
1
1
810
Aug ’24
Best way to pause DeviceActivitySchedule
Hi everyone, I'm currently working with the Screen Time API, specifically trying to figure out the best way to pause an active, repeating schedule without disrupting future schedules. Here's the scenario: I have a repeating schedule set from 10:00 AM to 8:00 PM daily. If I need to pause the schedule temporarily, my current approach involves stopping monitoring, clearing all restrictions, and then setting a new schedule for the remaining time after the pause. However, this method cancels the repeating schedule entirely, which causes issues when the schedule is supposed to restart the next day at 10:00 AM. Instead, it starts after the pause time, which isn’t what I want. Challenges I'm Facing: Maintaining Repeating Schedules: How can I pause the schedule in a way that ensures it resumes correctly the next day at the intended time (10:00 AM)? DeviceActivityMonitor Logic: Is there a way to deactivate and reactivate the schedule through the DeviceActivityMonitor without fully stopping the monitoring? Ideally, I'd like to retain the original schedule, pause it, and then resume it seamlessly after the pause. What I’ve Tried So Far: I’ve attempted to store the necessary data in the App Groups shared container as a local file. In the DeviceActivityMonitor, I used the schedule's name to identify and retrieve the saved object, planning to use this data to reapply the shielding after the pause. Unfortunately, this approach exceeds the 6MB memory limit of the extension, which is another roadblock. Given these issues, I’m unsure how to move forward. Are there any best practices or alternative approaches that could help manage this situation more effectively? Any insights or suggestions would be greatly appreciated! Thanks in advance for your help.
1
0
1k
Aug ’24
Seeking help for MDM activation lock issue
We have encountered an issue while developing our own Apple MDM solution. The issue occurs in the activation lock scenario. We have implemented the activation and deactivation of the activation lock feature in accordance with the following documentation. 1:https://developer.apple.com/documentation/devicemanagement/activation_lock_a_device 2:https://developer.apple.com/documentation/devicemanagement/device_assignment/activation_lock_a_device/creating_and_using_bypass_codes#3734453 Activationlock Request URI : https://mdmenrollment.apple.com/device/activationlock Request Method : POST Request Headers : [Accept:"text/plain, application/json, application/*+json, /", X-ADM-Auth-Session:"1723449441118O1O649496FAD285FDC77565EC075E770547O90695212BB76419F8E43B2F68BE7A6C6O67033512O11Op1OA0EA85747E70D2D6941C4F6662166CAF22C2193COC298C61ECC7B9E9C14EB2A20305F7E41", X-Server-Protocol-Version:"3", Content-Type:"application/json", Content-Length:"133"] Request Body : {"device":"K2LP4HQXJ4","escrow_key":"QRV7D-JPPMQ-Z90N-1VN8-L1PN-45Q2","lost_message":"xxxxx"} Response : {"serial_number":"K2LP4HQXJ4","response_status":"SUCCESS"} escrowKeyUnlock Request URI : https://deviceservices-external.apple.com/deviceservicesworkers/escrowKeyUnlock?serial=K2LP4HQXJ4&imei=357174298879232&meid=35717429887923&productType=iPhone14,2 Request Method : POST Request Headers : [Accept:"text/plain, application/json, application/*+json, /", Content-Type:"application/x-www-form-urlencoded", Content-Length:"189"] Request Body : orgName=xxxxx&guid=xxxxx&escrowKey=QRV7D-JPPMQ-Z90N-1VN8-L1PN-45Q2 Response : 404 <ns:escrowKeyDeviceServicesResponse version="1" xmlns:ns="http://www.apple.com/cds/mdmescrowKeyDeviceServices/xml"></ns:escrowKeyDeviceServicesResponse> Who can help me check if there are any errors in the way I'm calling these two APIs, and how to correct them?
1
0
815
Aug ’24
Integrating Two Separate Apps for Parental Control: Queries on Family Picker, Filtering, and Screen Time Permissions
Hello Apple Developer Community, We have developed two totally separate apps for parental control: one for parents (xyz/parent.com) and one for children (abc/child.com). These are not two sides of the same app, but rather distinct applications. Recently, we integrated these two apps and encountered a few challenges and questions that we hope the community can help with. Family Picker Behavior: We noticed that only the parent app on the current device is displayed in the Family Activity Picker. Is this the intended behavior? Our expectation was that the Family Activity Picker would show both the parent and child apps available on the device. Is there a way to ensure that both types of apps are listed? Filtering Apps in Family Picker: Is it possible to filter the apps displayed in the Family Activity Picker to show only the child’s app and exclude the parent app? Our goal is to streamline the selection process for users by removing irrelevant apps from the picker. If direct filtering is not possible, are there any recommended workarounds or best practices to achieve a similar result? Screen Time Permission Requirements: We’ve successfully implemented screen time permissions using the Authorization Center for the child app. However, do we also need to request screen time permissions from within the parent app? If so, are there any specific guidelines or best practices for managing screen time permissions across two interconnected apps? Triggering Child Managed Settings from Multiple Apps: Is it feasible to trigger managed settings (e.g., enabling restrictions) for the child app from both the parent and child apps? We want to ensure consistent enforcement of settings regardless of which app initiates the change. Are there any limitations or conflicts we should be aware of when managing settings from two different apps? We appreciate any guidance or insights you can provide on these issues. We’ve referred to the Family Controls and Screen Time documentation, but we're seeking more specific advice related to the integration of two separate apps in this context. Thank you in advance for your help!
0
0
627
Aug ’24
USB drive invisible to our app on supervised iPad
We have an iPad app which can write to user-specified locations on USB-connected storage devices. On unmanaged devices, this works just fine. However, when the device is under MDM, although the Files app can see the external USB storage device, it does not show up in the file browser in our own app. There's a restriction called "allowFilesUSBDriveAccess" which is set to true (the default), but there's no restriction called "allowOtherAppsUSBDriveAccess". Are MDM-managed iPads simply not allowed to access USB drives (except through the Files app)?
2
0
1.2k
Aug ’24
How to get all ManagedSettingStore objects
Using the Screen Time API, I can create multiple ManagedSettingStore objects with different names. Is there a way to retrieve these later by name? For example, if I create them dynamically from a configuration managed by the user of my app, and the app crashes or its data gets corrupted, how can I get rid of "stale" ManagedSettingStore objects that I no longer know? Or, if I somehow lose the name of a ManagedSettingStore I created, how long does the store stay active? Forever? How can I get rid of the "stale" store?
1
1
495
Jul ’24
iOS 18 screen time crashing bug
i just downloaded the iOS 18 beta yesterday and now my phones (iPhone 15 pro) screen time keeps crashing. when I reach my limit and input the screen time code it won’t respond and keeps me locked out. when I went into the settings to just turn off screen time the entire settings app just freezes and then crashes entirely. I’ve tried restarting the phone several times and nothing has any impact and can’t find anything online except a lot of other people having the same issue without a fix.
1
2
1.2k
Jul ’24
Password prompt for CardDAV policy on re-installing the same profile
Enrol Supervised iOS device. Push an CardDAV policy for the above device, the contacts gets synced in the native Contacts app as expected. (https://developer.apple.com/documentation/devicemanagement/carddav) When the above same profile is re-installed in the above device, the synced contacts are lost and password prompt is shown to enter the password - even though the installed profile contains password for the CardDAV policy. Password prompt from the device Re-Installed configuration <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>PayloadVersion</key> <integer>1</integer> <key>PayloadUUID</key> <string>35ee541b-fec0-46b0-bd48-bcc0702ab60b</string> <key>PayloadType</key> <string>Configuration</string> <key>PayloadOrganization</key> <string>MDM</string> <key>PayloadIdentifier</key> <string>com.mdm.ec89620f-2905-4c14-b09d-7e9f17944468.CardDAV</string> <key>PayloadDisplayName</key> <string>CardDAV</string> <key>PayloadRemovalDisallowed</key> <true/> <key>PayloadContent</key> <array> <dict> <key>PayloadVersion</key> <integer>1</integer> <key>PayloadUUID</key> <string>07c423b5-8ae2-4e6e-9336-aa9ca850d6c9</string> <key>PayloadType</key> <string>com.apple.carddav.account</string> <key>PayloadOrganization</key> <string>MDM</string> <key>PayloadIdentifier</key> <string>07cV423b5-8ae2-4e6e-9336-aa9ca850d6c9</string> <key>PayloadDisplayName</key> <string>CardDAV Policy</string> <key>CardDAVAccountDescription</key> <string>****</string> <key>CardDAVHostName</key> <string>www.googleapis.com</string> <key>CardDAVPassword</key> <string>****</string> <key>CardDAVPort</key> <integer>443</integer> <key>CardDAVPrincipalURL</key> <string></string> <key>CardDAVUseSSL</key> <true/> <key>CardDAVUsername</key> <string>****</string> </dict> </array> </dict> </plist> Feedback ID : FB14250521
0
1
1.1k
Jul ’24
Screentime restriction interfering with MDM passcode policy
Enrol Supervised iOS device Turn ON screen time restriction by opening Settings app -> Content & Privacy restrictions -> Passcode & Face ID -> Don’t Allow. Now install a Passcode policy profile via MDM with the key “forcePIN” set to “true”, such that the device is needed to change the passcode in device. By following above steps, the profile fails. The failure response from the device states that passcode restriction is applied in the device, “The profile ‘Profilename’ may require a passcode change but the passcode cannot be modified.” This is an incorrect behaviour as MDM should have more control over the screen-time restriction as well. Error response from the device <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CommandUUID</key> <string>InstallProfile</string> <key>ErrorChain</key> <array> <dict> <key>ErrorCode</key> <integer>4001</integer> <key>ErrorDomain</key> <string>MCInstallationErrorDomain</string> <key>LocalizedDescription</key> <string>Profile Installation Failed</string> <key>USEnglishDescription</key> <string>Profile Installation Failed</string> </dict> <dict> <key>ErrorCode</key> <integer>4026</integer> <key>ErrorDomain</key> <string>MCInstallationErrorDomain</string> <key>LocalizedDescription</key> <string>The profile **** may require a passcode change but the passcode cannot be modified.</string> <key>USEnglishDescription</key> <string>The profile **** may require a passcode change but the passcode cannot be modified.</string> </dict> </array> <key>Status</key> <string>Error</string> <key>UDID</key> <string>****</string> </dict> </plist> Feedback ID : FB14249704
0
0
943
Jul ’24
Usage time tracking is being killed by jetsam
Brief & History Since iOS 17.4 and up we experience a lot of flakyness when it comes to DeviceActivity event thresholds. After a lot of testing and investigations inside system logs and filing countless bug reports we found a reproducible way why the event thresholds are not getting properly called. Findings Apparently when the device reaches near to max memory something called jetsamkills processes left and right. This means that the UsageTrackingAgent that (we think) is responsible for tracking the usage time of the device gets killed and doesn't recover until significant memory is freeing up on the device. How to test it yourself Use a slightly older device with ~ 3 or 4 GB of RAM Open a game or two that is meomry intensive (like Fishing Clash, yes..) and observe In the console logs you see something that only happens then: Process UsageTrackingAgent [39307] killed by jetsam reason highwater This happens often but recovers itself when the UsageTrackingAgent exceeds their 6MB memory limit. Yet the log looks like this: Process UsageTrackingAgent [39307] killed by jetsam reason per-process limit Once you kick the game, the memory is free and sometimes the event thresholds are calling in again. Defeating the purpose However this defeats the purpose of tracking usage time and shielding perhaps the playing app from being played after a certain amount of time! Feedback Assistant Ticket Here is the ticket with sysdiagnose, step by step and more information: FB13884981 Please fix this ASAP, this is such a pain for production users and their kids EVERY DAY.
1
15
2.3k
Jul ’24
[iOS 18 Beta 2] Already monitored device activities need to be manually stopped before being restarted
Since iOS 18 Seed 2, I've noticed an issue. When calling startMonitoring(_:during:events:) with an already monitored activity, intervalDidStart in the Device Activity Monitor extension isn't triggered as it should be. I have to manually call stopMonitoring(_:) BEFORE restarting the activity for intervalDidStart to be called. This is 100% reproducible. This is different from how it worked before iOS 18 Seed 2 and contradicts the official documentation, which says, “If the app already monitored the activity, this method overwrites the previous schedule and events.” IMO, this suggests we shouldn't have to stop the activity manually; the startMonitoring(_:during:events:) method should handle it automatically. Is this a mistake or intended behavior? If intended: Could you give us the reason? The documentation should be updated to reflect this change. I've already filed a feedback about this issue (FB14110789).
2
4
1.1k
Jul ’24
The DeviceActivityMonitor did not trigger a callback
The listening callbacks were not triggered for intervalDidStart and intervalDidEnd after successfully starting center.startMonitoring when I attempted to set a schedule with DeviceActivitySchedule at 20-minute intervals Is there anyone who can assist me? Thank you. Below you will find my code. let intervalLengthInSeconds = 20 * 60 let intervalEnd = Date(timeIntervalSinceNow: TimeInterval(intervalLengthInSeconds)) let intervalStart = Date() let schedule = DeviceActivitySchedule(intervalStart: Calendar.current.dateComponents([.hour, .minute], from: intervalStart), intervalEnd: Calendar.current.dateComponents([.hour, .minute], from: intervalEnd), repeats: false, warningTime: DateComponents(minute: 1)) let newActivity = DeviceActivityName(rawValue: "20minuteUse") Log("😯 \(String(describing: schedule.nextInterval))") do { try center.startMonitoring(newActivity, during: schedule) } catch { print("failed to start session: \(error.localizedDescription)") } class MyMonitorExtension: DeviceActivityMonitor { let store = ManagedSettingsStore() // You can use the `store` property to shield apps when an interval starts, ends, or meets a threshold. override func intervalDidStart(for activity: DeviceActivityName) { super.intervalDidStart(for: activity) // Shield selected applications. Log("😓 start-------") } override func intervalDidEnd(for activity: DeviceActivityName) { super.intervalDidEnd(for: activity) Log("😓 end-------") } override func intervalWillStartWarning(for activity: DeviceActivityName) { super.intervalWillStartWarning(for: activity) Log("😓 StartWarning-------") } override func intervalWillEndWarning(for activity: DeviceActivityName) { super.intervalWillEndWarning(for: activity) Log("😓 EndWarning-------") } } schedule.nextInterval ------ print: 😯 Optional(2024-06-21 08:34:00 +0000 to 2024-06-21 08:54:00 +0000)
2
0
873
Jul ’24
Canceling request to […].DeviceActivityMonitorExtension because it exceeded its allowed time.
Hello, I am working on an app that schedules a device activity monitor from the screen time API. I noticed that sometimes scheduling an activity monitor won’t work and instead I see this log: Canceling request to […].DeviceActivityMonitorExtension because it exceeded its allowed time. What does this mean? What exactly is exceeding its allowed time? Would love to get some feedback on this so I can prevent this from happening. Thanks a lot for any help and have a nice day!
0
1
796
Jun ’24
ShieldActionDelegate uses a different webDomain than the one I shielded
I shield a web domain picked by users like this (discouragedSelections is an instance of FamilyActivitySelection() btw) : let webDomainTokens = discouragedSelections.webDomainTokens store.shield.webDomains = webDomainTokens The domain is correcly shielded and I can see the restricted screen when I access it via Safari. When I tap on the main button of that restricted view, I receive a different token than the one I got from .webDomainTokens from the code above. Why? override func handle(action: ShieldAction, for webDomain: WebDomainToken, completionHandler: @escaping (ShieldActionResponse) -> Void) { // webDomain here is different from the one in store.shield.webDomains }
Replies
2
Boosts
3
Views
749
Activity
Aug ’24
Application Tokens from Bundle Identifier
Hello! I've been doing a lot of work with ApplicationTokens, but there is very little documentation. While Apple gives you the FamilyAcitvitiesPicker to get tokens of apps on an iPhone, I need to get the tokens of apps that aren't on the phone. Example: Someone can select Instagram even though they don't have it downloaded. Then the application token will get sent to a server. Then a different person who does have Instagram on their phone will receive the token and it will do something with that application. Because FamilyActivitiesPicker can only select apps on the iPhone that it is running on, FamilyActivitiesPicker is useless to me, leading to my problem: Creating an ApplicationToken without FamilyActivitiesPicker This documentation says that I can create an Application (and thus an ApplicationToken) from the bundle identifier init(bundleIdentifier: String) Creates an object that represents the app with the specified bundle identifier. However, when I try to use this to get instagrams(or any apps) token, it returns nil every time! So, finally, my questions: How do I correctly use this initializer to create an ApplicationToken? Or, if this won't work for my purposes Are the ApplicationTokens created by FamilyActivitiesPicker the same across all devices no matter what?
Replies
2
Boosts
0
Views
1.2k
Activity
Aug ’24
ShieldConfiguration not applied for some users
My app correctly applies the ShieldConfiguration template that I chose (icon, text, CTA, etc), but some users reported seeing the following default shield: With the default shield text that reads, "You cannot use AppName because it is restricted." Any idea why?
Replies
1
Boosts
0
Views
712
Activity
Aug ’24
Shield Customisation Not Applying
Hi, I've been attempting to implement a customised shield based on the WWDC contents and documentation; however, while my configuration appears correct only the default "Restricted - You cannot use X app because it's restricted" ever displays. A quick summary of what I have done: Created a ShieldConfigurationExtension Ensured suitable Info.plist values - below Defined custom Shield within the configuration() methods - application example below Any suggestions on what might not be implemented correctly? Info.plist <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>NSExtension</key> <dict> <key>NSExtensionPointIdentifier</key> <string>com.apple.ManagedSettingsUI.shield-configuration-service</string> <key>NSExtensionPrincipalClass</key> <string>$(PRODUCT_MODULE_NAME).ShieldConfigurationExtension</string> </dict> </dict> </plist> Configuration import ManagedSettings import ManagedSettingsUI import UIKit class ShieldConfigurationExtension: ShieldConfigurationDataSource {       override func configuration(shielding application: Application) -> ShieldConfiguration {     // Customize the shield as needed for applications.     return ShieldConfiguration(       backgroundBlurStyle: UIBlurEffect.Style.systemThickMaterial,       backgroundColor: UIColor.white,       icon: UIImage(systemName: "stopwatch"),       title: ShieldConfiguration.Label(text: "No app for you", color: .yellow),       subtitle: ShieldConfiguration.Label(text: "Sorry, no apps for you", color: .white),       primaryButtonLabel: ShieldConfiguration.Label(text: "Ask for a break?", color: .white),       secondaryButtonLabel: ShieldConfiguration.Label(text: "Quick Quick", color: .white)     )   } }
Replies
5
Boosts
0
Views
2.8k
Activity
Aug ’24
Using core data in ShieldConfigurationExtension
Hi there, In short, I'm trying to use CoreData in my ShieldConfigurationDataSource extension. Trying to fetch from core data at all seems to cause the shield to render it's default look. I already added the extension to an app group + configured my persistence store to use the app group. Below is my code, any help is appreciated: // Shield extension override func configuration(shielding application: Application) -> ShieldConfiguration { do { let appSelectionId = "XXX" let blockedItemReq = ... blockedItemReq.predicate = ... let moc = PersistenceController.shared.container.viewContext // Commenting this and the bottom out makes it work, but I need the data! let blockedItemRes = try moc.fetch(blockedItemReq) let shieldTitle = ShieldConfiguration.Label(text: "Hello there", color: .red) return ShieldConfiguration(backgroundColor: .black, title: shieldTitle) } catch { let shieldTitle = ShieldConfiguration.Label(text: "ERROR \(error.localizedDescription)", color: .white) return ShieldConfiguration(backgroundColor: .black, title: shieldTitle) } } // Persistence Controller init(inMemory: Bool = false) { container = NSPersistentContainer(name: "AppBlockerOne") if inMemory { container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null") } else { let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.appblockerone")! let storeURL = containerURL.appendingPathComponent("AppBlockerOne.sqlite") let description = NSPersistentStoreDescription(url: storeURL) container.persistentStoreDescriptions = [description] } container.loadPersistentStores(completionHandler: { (storeDescription, error) in if let error = error as NSError? { fatalError("Unresolved error \(error), \(error.userInfo)") } }) container.viewContext.automaticallyMergesChangesFromParent = true }
Replies
2
Boosts
0
Views
800
Activity
Aug ’24
How does the threshold in DeviceActivityEvent work
Hey everyone, I'm working on implementing an AppLimit, where after accumulating x minutes of Screen Time for an app, it should be blocked. It works fine on the first day, but stops functioning correctly on subsequent days. What I'm Doing I start a 24/7 schedule with a DeviceActivityEvent that has a specified Screen Time threshold. In my DeviceActivityMonitor, I'm reacting to the eventDidReachThreshold. Once the accumulated time is reached, the app is blocked. This works as expected on the first day. Issues I'm Experiencing / Questions Second Day Issue: On the second day, the app is no longer blocked after the Screen Time threshold is reached, even though it worked on the first day. This leads me to suspect that a DeviceActivityEvent is "consumable". Is this correct? Pre-existing Screen Time Issue: If a user has already surpassed the Screen Time threshold before monitoring starts, the app isn't blocked once the schedule is set up. This leads to 2 issues: I would expect that the accumulated amount of time after starting the schedule would result in the call of eventDidReachThreshold. But it is never called It could also be the case that the previously accumulated time is being kept in mind, but that would mean the apps should be blocked, which isn't the case. Does the threshold account for accumulated Screen Time before the schedule begins? I haven't tested setting a limit of 10 minutes, accumulating 3 minutes of Screen Time, then starting the schedule and accumulating the remaining time, but I'm curious if anyone has encountered this behavior. Does anyone have an explanation for this behavior? Any help would be greatly appreciated!
Replies
2
Boosts
0
Views
1.1k
Activity
Aug ’24
FamilyActivityPicker on Simulator not populating apps.
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.
Replies
1
Boosts
1
Views
810
Activity
Aug ’24
Best way to pause DeviceActivitySchedule
Hi everyone, I'm currently working with the Screen Time API, specifically trying to figure out the best way to pause an active, repeating schedule without disrupting future schedules. Here's the scenario: I have a repeating schedule set from 10:00 AM to 8:00 PM daily. If I need to pause the schedule temporarily, my current approach involves stopping monitoring, clearing all restrictions, and then setting a new schedule for the remaining time after the pause. However, this method cancels the repeating schedule entirely, which causes issues when the schedule is supposed to restart the next day at 10:00 AM. Instead, it starts after the pause time, which isn’t what I want. Challenges I'm Facing: Maintaining Repeating Schedules: How can I pause the schedule in a way that ensures it resumes correctly the next day at the intended time (10:00 AM)? DeviceActivityMonitor Logic: Is there a way to deactivate and reactivate the schedule through the DeviceActivityMonitor without fully stopping the monitoring? Ideally, I'd like to retain the original schedule, pause it, and then resume it seamlessly after the pause. What I’ve Tried So Far: I’ve attempted to store the necessary data in the App Groups shared container as a local file. In the DeviceActivityMonitor, I used the schedule's name to identify and retrieve the saved object, planning to use this data to reapply the shielding after the pause. Unfortunately, this approach exceeds the 6MB memory limit of the extension, which is another roadblock. Given these issues, I’m unsure how to move forward. Are there any best practices or alternative approaches that could help manage this situation more effectively? Any insights or suggestions would be greatly appreciated! Thanks in advance for your help.
Replies
1
Boosts
0
Views
1k
Activity
Aug ’24
Seeking help for MDM activation lock issue
We have encountered an issue while developing our own Apple MDM solution. The issue occurs in the activation lock scenario. We have implemented the activation and deactivation of the activation lock feature in accordance with the following documentation. 1:https://developer.apple.com/documentation/devicemanagement/activation_lock_a_device 2:https://developer.apple.com/documentation/devicemanagement/device_assignment/activation_lock_a_device/creating_and_using_bypass_codes#3734453 Activationlock Request URI : https://mdmenrollment.apple.com/device/activationlock Request Method : POST Request Headers : [Accept:"text/plain, application/json, application/*+json, /", X-ADM-Auth-Session:"1723449441118O1O649496FAD285FDC77565EC075E770547O90695212BB76419F8E43B2F68BE7A6C6O67033512O11Op1OA0EA85747E70D2D6941C4F6662166CAF22C2193COC298C61ECC7B9E9C14EB2A20305F7E41", X-Server-Protocol-Version:"3", Content-Type:"application/json", Content-Length:"133"] Request Body : {"device":"K2LP4HQXJ4","escrow_key":"QRV7D-JPPMQ-Z90N-1VN8-L1PN-45Q2","lost_message":"xxxxx"} Response : {"serial_number":"K2LP4HQXJ4","response_status":"SUCCESS"} escrowKeyUnlock Request URI : https://deviceservices-external.apple.com/deviceservicesworkers/escrowKeyUnlock?serial=K2LP4HQXJ4&imei=357174298879232&meid=35717429887923&productType=iPhone14,2 Request Method : POST Request Headers : [Accept:"text/plain, application/json, application/*+json, /", Content-Type:"application/x-www-form-urlencoded", Content-Length:"189"] Request Body : orgName=xxxxx&guid=xxxxx&escrowKey=QRV7D-JPPMQ-Z90N-1VN8-L1PN-45Q2 Response : 404 <ns:escrowKeyDeviceServicesResponse version="1" xmlns:ns="http://www.apple.com/cds/mdmescrowKeyDeviceServices/xml"></ns:escrowKeyDeviceServicesResponse> Who can help me check if there are any errors in the way I'm calling these two APIs, and how to correct them?
Replies
1
Boosts
0
Views
815
Activity
Aug ’24
Integrating Two Separate Apps for Parental Control: Queries on Family Picker, Filtering, and Screen Time Permissions
Hello Apple Developer Community, We have developed two totally separate apps for parental control: one for parents (xyz/parent.com) and one for children (abc/child.com). These are not two sides of the same app, but rather distinct applications. Recently, we integrated these two apps and encountered a few challenges and questions that we hope the community can help with. Family Picker Behavior: We noticed that only the parent app on the current device is displayed in the Family Activity Picker. Is this the intended behavior? Our expectation was that the Family Activity Picker would show both the parent and child apps available on the device. Is there a way to ensure that both types of apps are listed? Filtering Apps in Family Picker: Is it possible to filter the apps displayed in the Family Activity Picker to show only the child’s app and exclude the parent app? Our goal is to streamline the selection process for users by removing irrelevant apps from the picker. If direct filtering is not possible, are there any recommended workarounds or best practices to achieve a similar result? Screen Time Permission Requirements: We’ve successfully implemented screen time permissions using the Authorization Center for the child app. However, do we also need to request screen time permissions from within the parent app? If so, are there any specific guidelines or best practices for managing screen time permissions across two interconnected apps? Triggering Child Managed Settings from Multiple Apps: Is it feasible to trigger managed settings (e.g., enabling restrictions) for the child app from both the parent and child apps? We want to ensure consistent enforcement of settings regardless of which app initiates the change. Are there any limitations or conflicts we should be aware of when managing settings from two different apps? We appreciate any guidance or insights you can provide on these issues. We’ve referred to the Family Controls and Screen Time documentation, but we're seeking more specific advice related to the integration of two separate apps in this context. Thank you in advance for your help!
Replies
0
Boosts
0
Views
627
Activity
Aug ’24
USB drive invisible to our app on supervised iPad
We have an iPad app which can write to user-specified locations on USB-connected storage devices. On unmanaged devices, this works just fine. However, when the device is under MDM, although the Files app can see the external USB storage device, it does not show up in the file browser in our own app. There's a restriction called "allowFilesUSBDriveAccess" which is set to true (the default), but there's no restriction called "allowOtherAppsUSBDriveAccess". Are MDM-managed iPads simply not allowed to access USB drives (except through the Files app)?
Replies
2
Boosts
0
Views
1.2k
Activity
Aug ’24
How to get all ManagedSettingStore objects
Using the Screen Time API, I can create multiple ManagedSettingStore objects with different names. Is there a way to retrieve these later by name? For example, if I create them dynamically from a configuration managed by the user of my app, and the app crashes or its data gets corrupted, how can I get rid of "stale" ManagedSettingStore objects that I no longer know? Or, if I somehow lose the name of a ManagedSettingStore I created, how long does the store stay active? Forever? How can I get rid of the "stale" store?
Replies
1
Boosts
1
Views
495
Activity
Jul ’24
Can ManagedSettingsStore and DeviceActivityCenter be used from a background thread?
Can ManagedSettingsStore and DeviceActivityCenter be used from a background thread, or do I need to access them from the main thread/queue only?
Replies
0
Boosts
1
Views
484
Activity
Jul ’24
iOS 18 screen time crashing bug
i just downloaded the iOS 18 beta yesterday and now my phones (iPhone 15 pro) screen time keeps crashing. when I reach my limit and input the screen time code it won’t respond and keeps me locked out. when I went into the settings to just turn off screen time the entire settings app just freezes and then crashes entirely. I’ve tried restarting the phone several times and nothing has any impact and can’t find anything online except a lot of other people having the same issue without a fix.
Replies
1
Boosts
2
Views
1.2k
Activity
Jul ’24
Password prompt for CardDAV policy on re-installing the same profile
Enrol Supervised iOS device. Push an CardDAV policy for the above device, the contacts gets synced in the native Contacts app as expected. (https://developer.apple.com/documentation/devicemanagement/carddav) When the above same profile is re-installed in the above device, the synced contacts are lost and password prompt is shown to enter the password - even though the installed profile contains password for the CardDAV policy. Password prompt from the device Re-Installed configuration <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>PayloadVersion</key> <integer>1</integer> <key>PayloadUUID</key> <string>35ee541b-fec0-46b0-bd48-bcc0702ab60b</string> <key>PayloadType</key> <string>Configuration</string> <key>PayloadOrganization</key> <string>MDM</string> <key>PayloadIdentifier</key> <string>com.mdm.ec89620f-2905-4c14-b09d-7e9f17944468.CardDAV</string> <key>PayloadDisplayName</key> <string>CardDAV</string> <key>PayloadRemovalDisallowed</key> <true/> <key>PayloadContent</key> <array> <dict> <key>PayloadVersion</key> <integer>1</integer> <key>PayloadUUID</key> <string>07c423b5-8ae2-4e6e-9336-aa9ca850d6c9</string> <key>PayloadType</key> <string>com.apple.carddav.account</string> <key>PayloadOrganization</key> <string>MDM</string> <key>PayloadIdentifier</key> <string>07cV423b5-8ae2-4e6e-9336-aa9ca850d6c9</string> <key>PayloadDisplayName</key> <string>CardDAV Policy</string> <key>CardDAVAccountDescription</key> <string>****</string> <key>CardDAVHostName</key> <string>www.googleapis.com</string> <key>CardDAVPassword</key> <string>****</string> <key>CardDAVPort</key> <integer>443</integer> <key>CardDAVPrincipalURL</key> <string></string> <key>CardDAVUseSSL</key> <true/> <key>CardDAVUsername</key> <string>****</string> </dict> </array> </dict> </plist> Feedback ID : FB14250521
Replies
0
Boosts
1
Views
1.1k
Activity
Jul ’24
Screentime restriction interfering with MDM passcode policy
Enrol Supervised iOS device Turn ON screen time restriction by opening Settings app -> Content & Privacy restrictions -> Passcode & Face ID -> Don’t Allow. Now install a Passcode policy profile via MDM with the key “forcePIN” set to “true”, such that the device is needed to change the passcode in device. By following above steps, the profile fails. The failure response from the device states that passcode restriction is applied in the device, “The profile ‘Profilename’ may require a passcode change but the passcode cannot be modified.” This is an incorrect behaviour as MDM should have more control over the screen-time restriction as well. Error response from the device <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CommandUUID</key> <string>InstallProfile</string> <key>ErrorChain</key> <array> <dict> <key>ErrorCode</key> <integer>4001</integer> <key>ErrorDomain</key> <string>MCInstallationErrorDomain</string> <key>LocalizedDescription</key> <string>Profile Installation Failed</string> <key>USEnglishDescription</key> <string>Profile Installation Failed</string> </dict> <dict> <key>ErrorCode</key> <integer>4026</integer> <key>ErrorDomain</key> <string>MCInstallationErrorDomain</string> <key>LocalizedDescription</key> <string>The profile **** may require a passcode change but the passcode cannot be modified.</string> <key>USEnglishDescription</key> <string>The profile **** may require a passcode change but the passcode cannot be modified.</string> </dict> </array> <key>Status</key> <string>Error</string> <key>UDID</key> <string>****</string> </dict> </plist> Feedback ID : FB14249704
Replies
0
Boosts
0
Views
943
Activity
Jul ’24
Usage time tracking is being killed by jetsam
Brief & History Since iOS 17.4 and up we experience a lot of flakyness when it comes to DeviceActivity event thresholds. After a lot of testing and investigations inside system logs and filing countless bug reports we found a reproducible way why the event thresholds are not getting properly called. Findings Apparently when the device reaches near to max memory something called jetsamkills processes left and right. This means that the UsageTrackingAgent that (we think) is responsible for tracking the usage time of the device gets killed and doesn't recover until significant memory is freeing up on the device. How to test it yourself Use a slightly older device with ~ 3 or 4 GB of RAM Open a game or two that is meomry intensive (like Fishing Clash, yes..) and observe In the console logs you see something that only happens then: Process UsageTrackingAgent [39307] killed by jetsam reason highwater This happens often but recovers itself when the UsageTrackingAgent exceeds their 6MB memory limit. Yet the log looks like this: Process UsageTrackingAgent [39307] killed by jetsam reason per-process limit Once you kick the game, the memory is free and sometimes the event thresholds are calling in again. Defeating the purpose However this defeats the purpose of tracking usage time and shielding perhaps the playing app from being played after a certain amount of time! Feedback Assistant Ticket Here is the ticket with sysdiagnose, step by step and more information: FB13884981 Please fix this ASAP, this is such a pain for production users and their kids EVERY DAY.
Replies
1
Boosts
15
Views
2.3k
Activity
Jul ’24
[iOS 18 Beta 2] Already monitored device activities need to be manually stopped before being restarted
Since iOS 18 Seed 2, I've noticed an issue. When calling startMonitoring(_:during:events:) with an already monitored activity, intervalDidStart in the Device Activity Monitor extension isn't triggered as it should be. I have to manually call stopMonitoring(_:) BEFORE restarting the activity for intervalDidStart to be called. This is 100% reproducible. This is different from how it worked before iOS 18 Seed 2 and contradicts the official documentation, which says, “If the app already monitored the activity, this method overwrites the previous schedule and events.” IMO, this suggests we shouldn't have to stop the activity manually; the startMonitoring(_:during:events:) method should handle it automatically. Is this a mistake or intended behavior? If intended: Could you give us the reason? The documentation should be updated to reflect this change. I've already filed a feedback about this issue (FB14110789).
Replies
2
Boosts
4
Views
1.1k
Activity
Jul ’24
The DeviceActivityMonitor did not trigger a callback
The listening callbacks were not triggered for intervalDidStart and intervalDidEnd after successfully starting center.startMonitoring when I attempted to set a schedule with DeviceActivitySchedule at 20-minute intervals Is there anyone who can assist me? Thank you. Below you will find my code. let intervalLengthInSeconds = 20 * 60 let intervalEnd = Date(timeIntervalSinceNow: TimeInterval(intervalLengthInSeconds)) let intervalStart = Date() let schedule = DeviceActivitySchedule(intervalStart: Calendar.current.dateComponents([.hour, .minute], from: intervalStart), intervalEnd: Calendar.current.dateComponents([.hour, .minute], from: intervalEnd), repeats: false, warningTime: DateComponents(minute: 1)) let newActivity = DeviceActivityName(rawValue: "20minuteUse") Log("😯 \(String(describing: schedule.nextInterval))") do { try center.startMonitoring(newActivity, during: schedule) } catch { print("failed to start session: \(error.localizedDescription)") } class MyMonitorExtension: DeviceActivityMonitor { let store = ManagedSettingsStore() // You can use the `store` property to shield apps when an interval starts, ends, or meets a threshold. override func intervalDidStart(for activity: DeviceActivityName) { super.intervalDidStart(for: activity) // Shield selected applications. Log("😓 start-------") } override func intervalDidEnd(for activity: DeviceActivityName) { super.intervalDidEnd(for: activity) Log("😓 end-------") } override func intervalWillStartWarning(for activity: DeviceActivityName) { super.intervalWillStartWarning(for: activity) Log("😓 StartWarning-------") } override func intervalWillEndWarning(for activity: DeviceActivityName) { super.intervalWillEndWarning(for: activity) Log("😓 EndWarning-------") } } schedule.nextInterval ------ print: 😯 Optional(2024-06-21 08:34:00 +0000 to 2024-06-21 08:54:00 +0000)
Replies
2
Boosts
0
Views
873
Activity
Jul ’24
Canceling request to […].DeviceActivityMonitorExtension because it exceeded its allowed time.
Hello, I am working on an app that schedules a device activity monitor from the screen time API. I noticed that sometimes scheduling an activity monitor won’t work and instead I see this log: Canceling request to […].DeviceActivityMonitorExtension because it exceeded its allowed time. What does this mean? What exactly is exceeding its allowed time? Would love to get some feedback on this so I can prevent this from happening. Thanks a lot for any help and have a nice day!
Replies
0
Boosts
1
Views
796
Activity
Jun ’24