Within the DeviceActivity API, the documentation for DeviceActivityCenter.startMonitoring says: "Attempting to monitor too many activities or activities that are too tightly scheduled can cause this method to throw an error."
Is there a documented limit of the amount of activities that are able to be monitored simultaneously? I understand that monitoring "too many activities" will throw an excessiveActivities error, but I can not find documentation that specifically identifies the conditions that this error can be thrown.
Post
Replies
Boosts
Views
Activity
I am developing an app for iOS 16 using the Xcode 14.0 beta. I've created certificates and provisioning files both through Xcode and manually following instructions at https://developer.apple.com/documentation/xcode/running-your-app-in-the-simulator-or-on-a-device, but every time when trying to install the app on my iPhone 13 Pro Max running iOS 16.0 beta, I get the error The code signature version is no longer supported. Googling around, I haven't found anything funky about code signing with iOS 16 beta, but that might be because it is so new. Is there any reason that my code signature would be invalid given my developer setup? It's attached to my Apple ID and I am a member of the Apple Developer Program. Here's the details to my error if you want to dig in:
Details
Unable to install "Screentox"
Domain: com.apple.dt.MobileDeviceErrorDomain
Code: -402620375
User Info: {
DVTErrorCreationDateKey = "2022-08-02 13:43:50 +0000";
IDERunOperationFailingWorker = IDEInstalliPhoneLauncher;
}
--
The code signature version is no longer supported.
Domain: com.apple.dt.MobileDeviceErrorDomain
Code: -402620375
User Info: {
DVTRadarComponentKey = 487925;
MobileDeviceErrorCode = "(0xE8008029)";
"com.apple.dtdevicekit.stacktrace" = (
0 DTDeviceKitBase 0x0000000122538c30 DTDKCreateNSErrorFromAMDErrorCode + 235
1 DTDeviceKitBase 0x00000001225752ff __90-[DTDKMobileDeviceToken installApplicationBundleAtPath:withOptions:andError:withCallback:]_block_invoke + 155
2 DVTFoundation 0x000000010b7453b5 DVTInvokeWithStrongOwnership + 71
3 DTDeviceKitBase 0x0000000122575027 -[DTDKMobileDeviceToken installApplicationBundleAtPath:withOptions:andError:withCallback:] + 1409
4 IDEiOSSupportCore 0x0000000121f6c66c __118-[DVTiOSDevice(DVTiPhoneApplicationInstallation) processAppInstallSet:appUninstallSet:installOptions:completionBlock:]_block_invoke.301 + 3520
5 DVTFoundation 0x000000010b87a629 __DVT_CALLING_CLIENT_BLOCK__ + 7
6 DVTFoundation 0x000000010b87b13d __DVTDispatchAsync_block_invoke + 196
7 libdispatch.dylib 0x00007ff81d8990cc _dispatch_call_block_and_release + 12
8 libdispatch.dylib 0x00007ff81d89a317 _dispatch_client_callout + 8
9 libdispatch.dylib 0x00007ff81d8a0317 _dispatch_lane_serial_drain + 672
10 libdispatch.dylib 0x00007ff81d8a0dfd _dispatch_lane_invoke + 366
11 libdispatch.dylib 0x00007ff81d8aaeee _dispatch_workloop_worker_thread + 753
12 libsystem_pthread.dylib 0x00007ff81da4dfd0 _pthread_wqthread + 326
13 libsystem_pthread.dylib 0x00007ff81da4cf57 start_wqthread + 15
);
}
--
Analytics Event: com.apple.dt.IDERunOperationWorkerFinished : {
"device_model" = "iPhone14,3";
"device_osBuild" = "16.0 (20A5328h)";
"device_platform" = "com.apple.platform.iphoneos";
"launchSession_schemeCommand" = Run;
"launchSession_state" = 1;
"launchSession_targetArch" = arm64;
"operation_duration_ms" = 4934;
"operation_errorCode" = "-402620375";
"operation_errorDomain" = "com.apple.dt.MobileDeviceErrorDomain";
"operation_errorWorker" = IDEInstalliPhoneLauncher;
"operation_name" = IDEiPhoneRunOperationWorkerGroup;
"param_consoleMode" = 0;
"param_debugger_attachToExtensions" = 0;
"param_debugger_attachToXPC" = 1;
"param_debugger_type" = 5;
"param_destination_isProxy" = 0;
"param_destination_platform" = "com.apple.platform.iphoneos";
"param_diag_MainThreadChecker_stopOnIssue" = 0;
"param_diag_MallocStackLogging_enableDuringAttach" = 0;
"param_diag_MallocStackLogging_enableForXPC" = 1;
"param_diag_allowLocationSimulation" = 1;
"param_diag_gpu_frameCapture_enable" = 0;
"param_diag_gpu_shaderValidation_enable" = 0;
"param_diag_gpu_validation_enable" = 0;
"param_diag_memoryGraphOnResourceException" = 0;
"param_diag_queueDebugging_enable" = 1;
"param_diag_runtimeProfile_generate" = 0;
"param_diag_sanitizer_asan_enable" = 0;
"param_diag_sanitizer_tsan_enable" = 0;
"param_diag_sanitizer_tsan_stopOnIssue" = 0;
"param_diag_sanitizer_ubsan_stopOnIssue" = 0;
"param_diag_showNonLocalizedStrings" = 0;
"param_diag_viewDebugging_enabled" = 1;
"param_diag_viewDebugging_insertDylibOnLaunch" = 1;
"param_install_style" = 0;
"param_launcher_UID" = 2;
"param_launcher_allowDeviceSensorReplayData" = 0;
"param_launcher_kind" = 0;
"param_launcher_style" = 0;
"param_launcher_substyle" = 0;
"param_runnable_appExtensionHostRunMode" = 0;
"param_runnable_productType" = "com.apple.product-type.application";
"param_runnable_type" = 2;
"param_testing_launchedForTesting" = 0;
"param_testing_suppressSimulatorApp" = 0;
"param_testing_usingCLI" = 0;
"sdk_canonicalName" = "iphoneos16.0";
"sdk_osVersion" = "16.0";
"sdk_variant" = iphoneos;
}
--
System Information
macOS Version 12.4 (Build 21F79)
Xcode 14.0 (21304.3) (Build 14A5270f)
Timestamp: 2022-08-02T09:43:50-04:00
Is there a way to use DeviceActivityMonitor to monitor a user's Screen Time ONLY on the current device, even if they have "Share Across Devices" enabled in their Screen Time settings?
For DeviceActivityReport, you can provide a DeviceActivityFilter which can specify the devices you want to show. But I have not seen any way to filter devices with the DeviveActivityMonitor API. I would expect there to be a additional argument to DeviceActivityEvent's init method:
init(
applications: Set<ApplicationToken> = [],
categories: Set<ActivityCategoryToken> = [],
webDomains: Set<WebDomainToken> = [],
threshold: DateComponents
)
Where you can specify devices as well. Right now, it seems like the default behavior is to monitor across all shared devices, which is causing problems for my application.
For my app, I use the DeviceActivity API to define a daily, repeating DeviceActivitySchedule that begins at 12:00AM and ends at 11:59 PM every day. I notice that when the device is powered off before 11:59 PM and powered back on the next day, neither the intervalDidEnd nor intervalDidStart callback functions are called. It appears that the interval extends into the next day and only ends once 11:59 PM comes around again.
What is the expected behavior of the system to call the intervalDidStart and intervalDidEnd callback functions when the device is powered off during the scheduled start or end time?
My app monitors DeviceActivityEvents with no categories, apps, or websites selected because we want to monitor their time spent on all categories, apps, and websites. This is because my app gives users rewards for keeping their total Screen Time low.
Unfortunately, it has been seemingly impossible to align the Screen Time shown with DeviceActivityReport to the Screen Time monitored with DeviceActivityMonitor. By default, the DeviceActivityReport captures more Screen Time than the DeviceActivityMonitor by default. But if I try to filter the report by totalActivityDuration on each category, it misses some Screen Time captured by the monitor (like FaceTime, for instance).
I simply want to report to the user exactly the Screen Time I am monitoring by default with DeviceActivityMonitor. Is that possible without selecting any categories, apps, or websites in the monitor?
My app has been "waiting in review" for several days. Usually it at least gets into review within 24 hours, sometimes even approved within that time frame. Is there a slowdown during the holiday season? I read that Apple was supposedly keeping the review process working during the holidays
My app "Present: Screen Time Control" (bundle ID com.getpresentapp.Present) has been in review for a week. Usually the app review takes about a day. Is there a reason for the long review time?
I am having a lot of trouble reliably making network requests from the DeviceActivityMonitor extension.
In the app extension, when intervalDidEnd is called by the system, I add some data to the app's local CoreData store and sync that with the server. I use URLSession dataTask to make a POST request to my server, with URLSessionConfiguration.sharedContainerIdentifier set to my App Group's shared identifier. It is extremely rare that my server receives this request, although sometimes (rarely) it does.
I've tried things like wrapping the task in performExpiringActivity or using URLSessionConfiguration.background suspecting that this task needs to run in the background, but none of it seems to work.
What I suspect is happening is that the App Extension gets cancelled before the request is able to be invoked. Looking at the console logs, sometimes the work stops before the request is called, sometimes during the request task, and sometimes even before I am able to update my local data store.
It's been very difficult to find any information on the lifecycle of the DeviceActivityMonitor Extension. What I want to know is:
How can I reliably make network requests from the DeviceActivityMonitor Extension?
What is the lifecycle of this extension? (How long do I have to complete work inside callback functions invoked by the system? And can I extend this time if necessary?)
My app uses a repeating 24 hour DeviceActivitySchedule defined like this:
let intervalStart = DateComponents(hour: 0, minute: 0, second: 0)
let intervalEnd = DateComponents(hour: 23, minute: 59, second: 59)
let schedule = DeviceActivitySchedule(
intervalStart: intervalStart,
intervalEnd: intervalEnd,
repeats: true)
try center.startMonitoring(
ACTIVITY_NAME,
during: schedule,
events: [...])
Both intervalDidStart and intervalDidEnd callback functions update CoreData and UserDefaults, and sometimes make network requests, and I'm worried that their close invocations may cause unexpected behavior.
Since intervalDidStart should be invoked only one second after intervalDidEnd, but intervalDidEnd may take longer than one second to run, due to updating local data and waiting for network requests to complete, how should this effect the invocation time of intervalDidStart? Is there a rule about the ordering of these functions, for instance if the interval is repeating and essentially overlaps like mine, is it guaranteed that intervalDidStart will always be called after intervalDidEnd returns, or is the behavior more undefined?
I've downloaded another screen time app that uses DeviceActivityMonitor, and once that app starts monitoring during an active monitoring schedule on my app - my app's monitoring schedule immediately ends. Is this expected behavior? Can't find this in any of the docs, but are two separate apps allowed to monitor activities during an overlapping schedule?
It seems like private browsing is undetectable with DeviceActivityMonitor for two reasons:
Specific web domains do not cause the monitoring threshold callback functions to fire, due to the privacy setting
Safari is not able to be monitored as an app or a category. It doesn't appear in the FamilyActivityPicker, and it doesn't appear to belong to any Screen Time category when viewing Safari's information in Screen Time Settings
Is there any way to monitor device activity during private browsing? If not, that seems like a big problem for apps that allow parents to set device activity limits for their kids.
Since Monday March 13 2023, DeviceActivityReport with a daily segment filter shows 0 screen time, for all users of my app (there are thousands). When changing the segment to hourly, it works but performance suffers.
I've defined the filter like this:
@State private var filter =
DeviceActivityFilter(segment: .daily(during: DateInterval(
start: Calendar.current.startOfDay(for: .now),
end: .now)))
Is anybody else experiencing this? This happened on its own after no change in the code or update to the app, and seems to be correlated with the first full day of Daylight Savings.
I will file a bug in Feedback Assistant, but is there any other guidance you can give on what might be the root cause, and if there's a fix? Seems like a large issue. Thanks in advance!
I've been experiencing some serious performance issues with DeviceActivityReport. Their severity tends to vary across devices - for some of my users it's really bad and for some it's mostly fine - but every device seems to experience these issues at some point.
1. DeviceActivityReport is completely blank. Often on launch, the DeviceActivityReport is completely blank and the only way to make it show up is to click back and forth between tabs, or quit the app and re-open it. Sometimes, it will show up after one or two seconds, but that is still a bad user experience. When looking at logs during this issue, I can see that makeConfiguration still runs successfully and returns a value, so I suspect the issue is with the rendering of the View in the App Extension.
2. Gestures are slow to register, or can't register at all. For example, if I place my DeviceActivityReport inside a ScrollView, I cannot scroll if I perform the gesture on the report view. If I try to scroll on the part of the screen that's not inside the report view, the screen scrolls but it will lag. This makes me think that if I perform a gesture on the report view, only the view inside the App Extension will register the gesture, but not the parent view in my host app. Is that the expected behavior?
My primary concern is number (1), it's by far the biggest pain point for my users and makes my app almost useless to them if they can't view their screen time :(. These issue have been reported before by other developers on the forum (https://developer.apple.com/forums/thread/723444, https://developer.apple.com/forums/thread/723491, https://developer.apple.com/forums/thread/720549).
Instead of recommending that I submit a bug to Feedback Assistant (which I will do), I am kindly asking for some recommendations to work around the known performance issues of DeviceActivityReport. Several apps out there that use the DeviceActivity API that do not appear to have these performance issues, like Opal and Jomo, so they must be doing something right!
One thing I've noticed is that the further up in the View hierarchy the DeviceActivityReport is, the better its performance, but I'm not sure why - maybe it is because the earlier the extension is connected to, the better. My app also has several tabs, makes network requests with asynchronous tasks on launch, uses the DeviceActivityMonitorExtension, and uses CoreData as a local data store. Maybe these things affect performance?
Thank you in advance for any performance recommendations that you could provide!
I've asked several questions about DeviceActivity performance issues where the answers have cited limitations to the lifecycle of the DeviceActivity App Extensions. For example:
Question about DeviceActivityReport lag and performance issues responded letting me know that my extension may be exceeding its memory limit of 100MB and subsequently getting terminated by the system.
Question about async tasks in DeviceActivityMonitor responded letting me know that the monitor extensions lifecycle ends and is terminated by the system once all synchronous functions return, so it has no async support.
I couldn't find either of these facts documented anywhere, and the DeviceActivity docs mention very little about how the extensions actually work. In general, it seems like these app extensions are basically a black box.
Is there any additional comprehensive documentation about the true lifecycle of the app extensions, their limitations, and how apps should handle error cases (like the system terminating the app extension process)? If not, I would be very grateful if you could provide any information you have in the response to this question. Thanks in advance!
I understand that the DeviceActivityMonitor extension is designed to be very lightweight, and the system terminates the extension as soon as its callback functions return.
However, I want to save values to UserDefaults inside the extension's callback functions. This creates concurrency issues for my app because the documentation for UserDefaults states that "When you set a default value, it’s changed synchronously within your process, and asynchronously to persistent storage and other processes."
In order to guarantee that these values are persisted before the extension terminates my app, I want to call UserDefaults.synchronize(), but its documentations states that it's "unnecessary and shouldn't be used." Furthermore, it's listed under "Legacy" but not marked deprecated.
Is synchronize() the recommended way to solve my concurrency problem? Or could there be a better way to wait for storage synchronization before returning from a synchronous function?