You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+147-9Lines changed: 147 additions & 9 deletions
Original file line number
Diff line number
Diff line change
@@ -11,10 +11,35 @@ Provides direct access to Apples Screen Time, Device Activity and Shielding APIs
11
11
12
12
Please note that it only supports iOS (and requires iOS 15 or higher) and requires a Custom Dev Client to work with Expo. For Android I'd probably look into [UsageStats](https://developer.android.com/reference/android/app/usage/UsageStats), which seems provide more granularity.
13
13
14
-
# Examples
14
+
# Examples & Use Cases
15
+
16
+
## Handle permissions
17
+
18
+
To block apps, you need to request Screen Time permissions. Note that some features (for example, events) may still trigger without permissions; however, this behavior is not guaranteed.
import * as ReactNativeDeviceActivity from "react-native-device-activity";
33
+
34
+
ReactNativeDeviceActivity.revokeAuthorization();
35
+
36
+
## Select Apps to track
37
+
38
+
For most use cases you need to get an activitySelection from the user, which is a token representing the apps the user wants to track, block or whitelist. This can be done by presenting the native view:
- This is a SwiftUI view, which is prone to crashing, especially when browsing larger categories of apps or searching for apps. It's recommended to provide a fallback view (positioned behind the SwiftUI view) that allows the user to know what's happening and reload the view and tailor that to your app's design and UX.
69
+
The activitySelection tokens can be particularly large (especially if you use includeEntireCategory flag), so you probably want to reference them through a familyActivitySelectionId instead of always passing the string token around. Most functions in this library accept a familyActivitySelectionId as well as the familyActivitySelection token directly.
70
+
71
+
## Time tracking
72
+
73
+
It's worth noting that the Screen Time API is not designed for time tracking out-of-the-box. So you have to set up events with names you can parse as time after they've triggered.
eventName: 'minutes_reached_10', // remember to give event names that make it possible for you to extract time at a later stage, if you want to access this information
53
91
familyActivitySelection: activitySelection,
54
92
threshold: { minute: 10 },
55
93
}
56
94
]
57
95
);
58
96
}
59
97
60
-
// you can listen to events (which I guess only works when the app is alive):
98
+
// you can listen to events (which only works when the app is alive):
Depending on your use case (if you need different schedules for different days, for example) you might need multiple monitors. There's a hard limit on 20 monitors at the same time. Study the [DateComponents](https://developer.apple.com/documentation/foundation/datecomponents) object to model this to your use case.
120
+
121
+
## Block the shield
122
+
123
+
To block apps, you can do it directly from your code.
eventName: 'minutes_reached_10', // remember to give event names that make it possible for you to extract time at a later stage, if you want to access this information
149
+
familyActivitySelection: activitySelection,
150
+
threshold: { minute: 10 },
151
+
actions: [
152
+
{
153
+
type: "blockSelection",
154
+
familyActivitySelectionId,
155
+
}
156
+
]
157
+
}
158
+
]
159
+
);
160
+
}
161
+
```
162
+
163
+
There are many other actions you can perform, like sending web requests or notifications. The easiest way to explore this is by using TypeScript, which is easier to keep up-to-date than this documentation.
164
+
165
+
You can also configure the shield UI and actions of the shield (this can also be done in the Swift process with actions):
For [managed](https://docs.expo.dev/archive/managed-vs-bare/) Expo projects, please follow the installation instructions in the [API documentation for the latest stable release](#api-documentation). If you follow the link and there is no documentation available then this library is not yet usable within managed projects — it is likely to be included in an upcoming Expo SDK release.
@@ -111,15 +245,17 @@ For Expo to be able to automatically handle provisioning you need to specify ext
111
245
You can potentially modify the targets manually, although you risk the library and your app code diverging. If you want to disable the automatic copying of the targets, you can set `copyToTargetFolder` to `false` in the plugin configuration [as seen here](https://github.com/Intentional-Digital/react-native-device-activity/blob/main/example/app.json#L53).
112
246
113
247
## Some notes
114
-
- It's not possible to 100% know which familyActivitySelection an event being handled is triggered for in the context of the Shield UI/actions. We try to make a best guess here - prioritizing apps/websites in an activitySelection over categories, and smaller activitySelections over larger ones (i.e. "Instagram" over "Instagram + Facebook" over "Social Media Apps"). This means that if you display a shield specific for the Instagram selection that will take precedence over the less specific shields.
248
+
249
+
- It's not possible to 100% know which familyActivitySelection an event being handled is triggered for in the context of the Shield UI/actions. We try to make the best guess here, prioritizing apps/websites in an activitySelection over categories, and smaller activitySelections over larger ones (i.e. "Instagram" over "Instagram + Facebook" over "Social Media Apps"). This means that if you display a shield specific for the Instagram selection that will take precedence over the less specific shields.
115
250
- When determining which familyActivitySelectionId that should be used it will only look for familyActivitySelectionIds that are contained in any of the currently monitored activity names (i.e. if familyActivitySelectionId is "social-media-apps" it will only trigger if there is an activity name that contains "social-media-apps"). This might be a limitation for some implementations, it would probably be nice to make this configurable.
116
251
117
252
## Data model
253
+
118
254
Almost all the functionality is built around persisting configuration as well as event history to UserDefaults.
119
255
120
256
- familyActivitySelectionId mapping. This makes it possible for us to tie a familyActivitySelection token to an id that we can reuse and refer to at a later stage.
121
-
- Triggers. This includes configuring shield UI/actions as well as sending web requests or notifications from the Swift background side, in the context of the device activity monitor process. Prefixed like actions_for_${goalId} in userDefaults. This is how we do blocking of apps, updates to shield UI/actions etc.
122
-
- Event history. Contains information of which events have been triggered and when. Prefixed like events_${goalId} in userDefaults. This can be useful for tracking time spent.
257
+
- Triggers. This includes configuring shield UI/actions as well as sending web requests or notifications from the Swift background side, in the context of the device activity monitor process. Prefixed like actions*for*${goalId} in userDefaults. This is how we do blocking of apps, updates to shield UI/actions etc.
258
+
- Event history. Contains information of which events have been triggered and when. Prefixed like events\_${goalId} in userDefaults. This can be useful for tracking time spent.
123
259
- ShieldIds. To reduce the storage strain on userDefaults shields are referenced with shieldIds.
124
260
125
261
# Installation in bare React Native projects
@@ -160,7 +296,8 @@ Contributions are very welcome! Please refer to guidelines described in the [con
160
296
# Weird behaviors ⚠️
161
297
162
298
- Authorization changes outside app not captured
163
-
When we've asked whether the user has authorized us to use screen time, and the state is changed outside the app, the native API doesn't update until the app restarts, i.e. this flow:
299
+
When we've asked whether the user has authorized us to use screen time, and the state is changed outside the app, the native API doesn't update until the app restarts, i.e. this flow:
300
+
164
301
1. Ask for current permission
165
302
2. Change permission outside the app
166
303
3. Ask for current permission again will return same as (1)
@@ -173,6 +310,7 @@ When we've asked whether the user has authorized us to use screen time, and the
173
310
- The DeviceActivitySelectionView is prone to crashes, which is outside of our control. The best we can do is provide fallback views that allows the user to know what's happening and reload the view.
174
311
175
312
# Troubleshooting 📱
313
+
176
314
The Screen Time APIs are known to be very finnicky. Here are some things you can try to troubleshoot events not being reported:
177
315
178
316
- Disable Low Power Mode (mentioned by Apple Community Specialist [here](https://discussions.apple.com/thread/254808070)) 🪫
@@ -182,4 +320,4 @@ The Screen Time APIs are known to be very finnicky. Here are some things you can
182
320
- Make sure device is not low on storage (mentioned by Apple Community Specialist [here](https://discussions.apple.com/thread/254808070)) 💾
183
321
- Upgrade iOS version
184
322
- Content & Privacy Restrictions: If any restrictions are enabled under Screen Time’s Content & Privacy Restrictions, ensure none are blocking your app.
0 commit comments